From 4c60a2f50b163cb52495c3815a41ade7e536de39 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Tue, 23 May 2023 14:00:52 -0600 Subject: [PATCH 01/25] Reorganize NRL ozone physics scheme into CCPP phases. Make scheme (memory) stateless. --- physics/GFS_phys_time_vary.fv3.F90 | 80 ++----- physics/GFS_phys_time_vary.fv3.meta | 76 +----- physics/GFS_phys_time_vary.scm.F90 | 68 ++---- physics/GFS_phys_time_vary.scm.meta | 76 +----- physics/GFS_rrtmg_pre.F90 | 11 +- physics/GFS_rrtmg_pre.meta | 30 +++ physics/GFS_rrtmg_setup.F90 | 7 +- physics/GFS_rrtmg_setup.meta | 21 ++ physics/ozinterp.f90 | 212 ----------------- physics/ozne_def.f | 24 -- physics/ozne_def.meta | 29 --- physics/ozphys_2015.F90 | 343 ++++++++++++++++++++++++++++ physics/ozphys_2015.f | 190 --------------- physics/ozphys_2015.meta | 203 ++++++++++++++-- physics/radiation_gases.f | 13 +- 15 files changed, 635 insertions(+), 748 deletions(-) delete mode 100644 physics/ozinterp.f90 delete mode 100644 physics/ozne_def.f delete mode 100644 physics/ozne_def.meta create mode 100644 physics/ozphys_2015.F90 delete mode 100644 physics/ozphys_2015.f diff --git a/physics/GFS_phys_time_vary.fv3.F90 b/physics/GFS_phys_time_vary.fv3.F90 index 42f2bbc15..334228afe 100644 --- a/physics/GFS_phys_time_vary.fv3.F90 +++ b/physics/GFS_phys_time_vary.fv3.F90 @@ -2,7 +2,7 @@ !! Contains code related to GFS physics suite setup (physics part of time_vary_step) !>\defgroup mod_GFS_phys_time_vary GFS Physics Time Update -!! This module contains GFS physics time vary subroutines including ozone, stratospheric water vapor, +!! This module contains GFS physics time vary subroutines including stratospheric water vapor, !! aerosol, IN&CCN and surface properties updates. module GFS_phys_time_vary @@ -14,9 +14,6 @@ module GFS_phys_time_vary use mersenne_twister, only: random_setseed, random_number - use ozne_def, only : levozp, oz_coeff, oz_lat, oz_pres, oz_time, ozplin - use ozinterp, only : read_o3data, setindxoz, ozinterpol - use h2o_def, only : levh2o, h2o_coeff, h2o_lat, h2o_pres, h2o_time, h2oplin use h2ointerp, only : read_h2odata, setindxh2o, h2ointerpol @@ -66,9 +63,9 @@ module GFS_phys_time_vary !>\section gen_GFS_phys_time_vary_init GFS_phys_time_vary_init General Algorithm !> @{ subroutine GFS_phys_time_vary_init ( & - me, master, ntoz, h2o_phys, iaerclm, iccn, iaermdl, iflip, im, levs, & + me, master, h2o_phys, iaerclm, iccn, iaermdl, iflip, im, levs, & nx, ny, idate, xlat_d, xlon_d, & - jindx1_o3, jindx2_o3, ddy_o3, ozpl, jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & + jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & jindx1_aer, jindx2_aer, ddy_aer, iindx1_aer, iindx2_aer, ddx_aer, aer_nm, & jindx1_ci, jindx2_ci, ddy_ci, iindx1_ci, iindx2_ci, ddx_ci, imap, jmap, & do_ugwp_v1, jindx1_tau, jindx2_tau, ddy_j1tau, ddy_j2tau, & @@ -85,15 +82,15 @@ subroutine GFS_phys_time_vary_init ( implicit none ! Interface variables - integer, intent(in) :: me, master, ntoz, iccn, iflip, im, nx, ny, levs, iaermdl + integer, intent(in) :: me, master, iccn, iflip, im, nx, ny, levs, iaermdl logical, intent(in) :: h2o_phys, iaerclm, lsm_cold_start integer, intent(in) :: idate(:) real(kind_phys), intent(in) :: fhour real(kind_phys), intent(in) :: xlat_d(:), xlon_d(:) - integer, intent(inout) :: jindx1_o3(:), jindx2_o3(:), jindx1_h(:), jindx2_h(:) - real(kind_phys), intent(inout) :: ddy_o3(:), ddy_h(:) - real(kind_phys), intent(in) :: ozpl(:,:,:), h2opl(:,:,:) + integer, intent(inout) :: jindx1_h(:), jindx2_h(:) + real(kind_phys), intent(inout) :: ddy_h(:) + real(kind_phys), intent(in) :: h2opl(:,:,:) integer, intent(inout) :: jindx1_aer(:), jindx2_aer(:), iindx1_aer(:), iindx2_aer(:) real(kind_phys), intent(inout) :: ddy_aer(:), ddx_aer(:) real(kind_phys), intent(out) :: aer_nm(:,:,:) @@ -196,13 +193,12 @@ subroutine GFS_phys_time_vary_init ( jamax=-999 !$OMP parallel num_threads(nthrds) default(none) & -!$OMP shared (me,master,ntoz,h2o_phys,im,nx,ny,levs,idate) & +!$OMP shared (me,master,h2o_phys,im,nx,ny,levs,idate) & !$OMP shared (xlat_d,xlon_d,imap,jmap,errmsg,errflg) & -!$OMP shared (levozp,oz_coeff,oz_pres,ozpl) & !$OMP shared (levh2o,h2o_coeff,h2o_pres,h2opl) & !$OMP shared (iamin, iamax, jamin, jamax) & !$OMP shared (iaerclm,iaermdl,ntrcaer,aer_nm,iflip,iccn) & -!$OMP shared (jindx1_o3,jindx2_o3,ddy_o3,jindx1_h,jindx2_h,ddy_h) & +!$OMP shared (jindx1_h,jindx2_h,ddy_h) & !$OMP shared (jindx1_aer,jindx2_aer,ddy_aer,iindx1_aer,iindx2_aer,ddx_aer) & !$OMP shared (jindx1_ci,jindx2_ci,ddy_ci,iindx1_ci,iindx2_ci,ddx_ci) & !$OMP shared (do_ugwp_v1,jindx1_tau,jindx2_tau,ddy_j1tau,ddy_j2tau) & @@ -212,32 +208,12 @@ subroutine GFS_phys_time_vary_init ( !$OMP sections -!$OMP section -!> - Call read_o3data() to read ozone data - call read_o3data (ntoz, me, master) - - ! Consistency check that the hardcoded values for levozp and - ! oz_coeff in GFS_typedefs.F90 match what is set by read_o3data - ! in GFS_typedefs.F90: allocate (Tbd%ozpl (IM,levozp,oz_coeff)) - if (size(ozpl, dim=2).ne.levozp) then - write(errmsg,'(2a,i0,a,i0)') "Value error in GFS_phys_time_vary_init: ", & - "levozp from read_o3data does not match value in GFS_typedefs.F90: ", & - levozp, " /= ", size(ozpl, dim=2) - errflg = 1 - end if - if (size(ozpl, dim=3).ne.oz_coeff) then - write(errmsg,'(2a,i0,a,i0)') "Value error in GFS_phys_time_vary_init: ", & - "oz_coeff from read_o3data does not match value in GFS_typedefs.F90: ", & - oz_coeff, " /= ", size(ozpl, dim=3) - errflg = 1 - end if - !$OMP section !> - Call read_h2odata() to read stratospheric water vapor data call read_h2odata (h2o_phys, me, master) ! Consistency check that the hardcoded values for levh2o and - ! h2o_coeff in GFS_typedefs.F90 match what is set by read_o3data + ! h2o_coeff in GFS_typedefs.F90 match what is set by read_h2odata ! in GFS_typedefs.F90: allocate (Tbd%h2opl (IM,levh2o,h2o_coeff)) if (size(h2opl, dim=2).ne.levh2o) then write(errmsg,'(2a,i0,a,i0)') "Value error in GFS_phys_time_vary_init: ", & @@ -295,12 +271,6 @@ subroutine GFS_phys_time_vary_init ( !$OMP sections -!$OMP section -!> - Call setindxoz() to initialize ozone data - if (ntoz > 0) then - call setindxoz (im, xlat_d, jindx1_o3, jindx2_o3, ddy_o3) - endif - !$OMP section !> - Call setindxh2o() to initialize stratospheric water vapor data if (h2o_phys) then @@ -708,8 +678,8 @@ end subroutine GFS_phys_time_vary_init !> @{ subroutine GFS_phys_time_vary_timestep_init ( & me, master, cnx, cny, isc, jsc, nrcm, im, levs, kdt, idate, nsswr, fhswr, lsswr, fhour, & - imfdeepcnv, cal_pre, random_clds, nscyc, ntoz, h2o_phys, iaerclm, iccn, clstp, & - jindx1_o3, jindx2_o3, ddy_o3, ozpl, jindx1_h, jindx2_h, ddy_h, h2opl, iflip, & + imfdeepcnv, cal_pre, random_clds, nscyc, h2o_phys, iaerclm, iccn, clstp, & + jindx1_h, jindx2_h, ddy_h, h2opl, iflip, & jindx1_aer, jindx2_aer, ddy_aer, iindx1_aer, iindx2_aer, ddx_aer, aer_nm, & jindx1_ci, jindx2_ci, ddy_ci, iindx1_ci, iindx2_ci, ddx_ci, in_nm, ccn_nm, fn_nml, & imap, jmap, prsl, seed0, rann, nthrds, nx, ny, nsst, tile_num, nlunit, lsoil, lsoil_lsm,& @@ -724,14 +694,14 @@ subroutine GFS_phys_time_vary_timestep_init ( ! Interface variables integer, intent(in) :: me, master, cnx, cny, isc, jsc, nrcm, im, levs, kdt, & - nsswr, imfdeepcnv, iccn, nscyc, ntoz, iflip + nsswr, imfdeepcnv, iccn, nscyc, iflip integer, intent(in) :: idate(:) real(kind_phys), intent(in) :: fhswr, fhour logical, intent(in) :: lsswr, cal_pre, random_clds, h2o_phys, iaerclm real(kind_phys), intent(out) :: clstp - integer, intent(in) :: jindx1_o3(:), jindx2_o3(:), jindx1_h(:), jindx2_h(:) - real(kind_phys), intent(in) :: ddy_o3(:), ddy_h(:) - real(kind_phys), intent(inout) :: ozpl(:,:,:), h2opl(:,:,:) + integer, intent(in) :: jindx1_h(:), jindx2_h(:) + real(kind_phys), intent(in) :: ddy_h(:) + real(kind_phys), intent(inout) :: h2opl(:,:,:) integer, intent(in) :: jindx1_aer(:), jindx2_aer(:), iindx1_aer(:), iindx2_aer(:) real(kind_phys), intent(in) :: ddy_aer(:), ddx_aer(:) real(kind_phys), intent(inout) :: aer_nm(:,:,:) @@ -788,8 +758,8 @@ subroutine GFS_phys_time_vary_timestep_init ( !$OMP parallel num_threads(nthrds) default(none) & !$OMP shared(kdt,nsswr,lsswr,clstp,imfdeepcnv,cal_pre,random_clds) & !$OMP shared(fhswr,fhour,seed0,cnx,cny,nrcm,wrk,rannie,rndval) & -!$OMP shared(rann,im,isc,jsc,imap,jmap,ntoz,me,idate,jindx1_o3,jindx2_o3) & -!$OMP shared(ozpl,ddy_o3,h2o_phys,jindx1_h,jindx2_h,h2opl,ddy_h,iaerclm,master) & +!$OMP shared(rann,im,isc,jsc,imap,jmap,me,idate) & +!$OMP shared(h2o_phys,jindx1_h,jindx2_h,h2opl,ddy_h,iaerclm,master) & !$OMP shared(levs,prsl,iccn,jindx1_ci,jindx2_ci,ddy_ci,iindx1_ci,iindx2_ci) & !$OMP shared(ddx_ci,in_nm,ccn_nm,do_ugwp_v1,jindx1_tau,jindx2_tau,ddy_j1tau) & !$OMP shared(ddy_j2tau,tau_amf,iflip) & @@ -842,14 +812,6 @@ subroutine GFS_phys_time_vary_timestep_init ( endif ! imfdeepcnv, cal_re, random_clds -!$OMP section -!> - Call ozinterpol() to make ozone interpolation - if (ntoz > 0) then - call ozinterpol (me, im, idate, fhour, & - jindx1_o3, jindx2_o3, & - ozpl, ddy_o3) - endif - !$OMP section !> - Call h2ointerpol() to make stratospheric water vapor data interpolation if (h2o_phys) then @@ -944,12 +906,6 @@ subroutine GFS_phys_time_vary_finalize(errmsg, errflg) if (.not.is_initialized) return - ! Deallocate ozone arrays - if (allocated(oz_lat) ) deallocate(oz_lat) - if (allocated(oz_pres) ) deallocate(oz_pres) - if (allocated(oz_time) ) deallocate(oz_time) - if (allocated(ozplin) ) deallocate(ozplin) - ! Deallocate h2o arrays if (allocated(h2o_lat) ) deallocate(h2o_lat) if (allocated(h2o_pres)) deallocate(h2o_pres) diff --git a/physics/GFS_phys_time_vary.fv3.meta b/physics/GFS_phys_time_vary.fv3.meta index ce8c6c54b..654b5afd8 100644 --- a/physics/GFS_phys_time_vary.fv3.meta +++ b/physics/GFS_phys_time_vary.fv3.meta @@ -2,7 +2,7 @@ name = GFS_phys_time_vary type = scheme dependencies = aerclm_def.F,aerinterp.F90,gcycle.F90,h2o_def.f,h2ointerp.f90,iccn_def.F,iccninterp.F90,machine.F,mersenne_twister.f - dependencies = namelist_soilveg.f,set_soilveg.f,ozinterp.f90,ozne_def.f,sfcsub.F,cires_tauamf_data.F90,noahmp_tables.f90 + dependencies = namelist_soilveg.f,set_soilveg.f,sfcsub.F,cires_tauamf_data.F90,noahmp_tables.f90 ######################################################################## [ccpp-arg-table] @@ -23,13 +23,6 @@ dimensions = () type = integer intent = in -[ntoz] - standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array - long_name = tracer index for ozone mixing ratio - units = index - dimensions = () - type = integer - intent = in [h2o_phys] standard_name = flag_for_stratospheric_water_vapor_physics long_name = flag for stratospheric water vapor physics @@ -116,36 +109,6 @@ type = real kind = kind_phys intent = in -[jindx1_o3] - standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation low index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = inout -[jindx2_o3] - standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation high index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = inout -[ddy_o3] - standard_name = latitude_interpolation_weight_for_ozone_forcing - long_name = interpolation high index for ozone - units = none - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = inout -[ozpl] - standard_name = ozone_forcing - long_name = ozone forcing data - units = mixed - dimensions = (horizontal_dimension,vertical_dimension_of_ozone_forcing_data,number_of_coefficients_in_ozone_forcing_data) - type = real - kind = kind_phys - intent = in [jindx1_h] standard_name = lower_latitude_index_of_stratospheric_water_vapor_forcing_for_interpolation long_name = interpolation low index for stratospheric water vapor @@ -1077,13 +1040,6 @@ dimensions = () type = integer intent = in -[ntoz] - standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array - long_name = tracer index for ozone mixing ratio - units = index - dimensions = () - type = integer - intent = in [h2o_phys] standard_name = flag_for_stratospheric_water_vapor_physics long_name = flag for stratospheric water vapor physics @@ -1113,36 +1069,6 @@ type = real kind = kind_phys intent = out -[jindx1_o3] - standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation low index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[jindx2_o3] - standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation high index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[ddy_o3] - standard_name = latitude_interpolation_weight_for_ozone_forcing - long_name = interpolation high index for ozone - units = none - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = in -[ozpl] - standard_name = ozone_forcing - long_name = ozone forcing data - units = mixed - dimensions = (horizontal_dimension,vertical_dimension_of_ozone_forcing_data,number_of_coefficients_in_ozone_forcing_data) - type = real - kind = kind_phys - intent = inout [jindx1_h] standard_name = lower_latitude_index_of_stratospheric_water_vapor_forcing_for_interpolation long_name = interpolation low index for stratospheric water vapor diff --git a/physics/GFS_phys_time_vary.scm.F90 b/physics/GFS_phys_time_vary.scm.F90 index 74b34e974..97460ac98 100644 --- a/physics/GFS_phys_time_vary.scm.F90 +++ b/physics/GFS_phys_time_vary.scm.F90 @@ -2,7 +2,7 @@ !! Contains code related to GFS physics suite setup (physics part of time_vary_step) !>\defgroup mod_GFS_phys_time_vary GFS Physics Time Update -!! This module contains GFS physics time vary subroutines including ozone, stratospheric water vapor, +!! This module contains GFS physics time vary subroutines including, stratospheric water vapor, !! aerosol, IN&CCN and surface properties updates. !> @{ module GFS_phys_time_vary @@ -11,9 +11,6 @@ module GFS_phys_time_vary use mersenne_twister, only: random_setseed, random_number - use ozne_def, only : levozp, oz_coeff, oz_lat, oz_pres, oz_time, ozplin - use ozinterp, only : read_o3data, setindxoz, ozinterpol - use h2o_def, only : levh2o, h2o_coeff, h2o_lat, h2o_pres, h2o_time, h2oplin use h2ointerp, only : read_h2odata, setindxh2o, h2ointerpol @@ -61,8 +58,8 @@ module GFS_phys_time_vary !>\section gen_GFS_phys_time_vary_init GFS_phys_time_vary_init General Algorithm !! @{ subroutine GFS_phys_time_vary_init ( & - me, master, ntoz, h2o_phys, iaerclm, iccn, iflip, im, nx, ny, idate, xlat_d, xlon_d, & - jindx1_o3, jindx2_o3, ddy_o3, ozpl, jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & + me, master, h2o_phys, iaerclm, iccn, iflip, im, nx, ny, idate, xlat_d, xlon_d, & + jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & jindx1_aer, jindx2_aer, ddy_aer, iindx1_aer, iindx2_aer, ddx_aer, aer_nm, & jindx1_ci, jindx2_ci, ddy_ci, iindx1_ci, iindx2_ci, ddx_ci, imap, jmap, & do_ugwp_v1, jindx1_tau, jindx2_tau, ddy_j1tau, ddy_j2tau, & @@ -79,15 +76,15 @@ subroutine GFS_phys_time_vary_init ( implicit none ! Interface variables - integer, intent(in) :: me, master, ntoz, iccn, iflip, im, nx, ny + integer, intent(in) :: me, master, iccn, iflip, im, nx, ny logical, intent(in) :: h2o_phys, iaerclm, lsm_cold_start integer, intent(in) :: idate(:) real(kind_phys), intent(in) :: fhour real(kind_phys), intent(in) :: xlat_d(:), xlon_d(:) - integer, intent(inout) :: jindx1_o3(:), jindx2_o3(:), jindx1_h(:), jindx2_h(:) - real(kind_phys), intent(inout) :: ddy_o3(:), ddy_h(:) - real(kind_phys), intent(in) :: ozpl(:,:,:), h2opl(:,:,:) + integer, intent(inout) :: jindx1_h(:), jindx2_h(:) + real(kind_phys), intent(inout) :: ddy_h(:) + real(kind_phys), intent(in) :: h2opl(:,:,:) integer, intent(inout) :: jindx1_aer(:), jindx2_aer(:), iindx1_aer(:), iindx2_aer(:) real(kind_phys), intent(inout) :: ddy_aer(:), ddx_aer(:) real(kind_phys), intent(in) :: aer_nm(:,:,:) @@ -189,30 +186,11 @@ subroutine GFS_phys_time_vary_init ( jamin=999 jamax=-999 -!> - Call read_o3data() to read ozone data - call read_o3data (ntoz, me, master) - - ! Consistency check that the hardcoded values for levozp and - ! oz_coeff in GFS_typedefs.F90 match what is set by read_o3data - ! in GFS_typedefs.F90: allocate (Tbd%ozpl (IM,levozp,oz_coeff)) - if (size(ozpl, dim=2).ne.levozp) then - write(errmsg,'(2a,i0,a,i0)') "Value error in GFS_phys_time_vary_init: ", & - "levozp from read_o3data does not match value in GFS_typedefs.F90: ", & - levozp, " /= ", size(ozpl, dim=2) - errflg = 1 - end if - if (size(ozpl, dim=3).ne.oz_coeff) then - write(errmsg,'(2a,i0,a,i0)') "Value error in GFS_phys_time_vary_init: ", & - "oz_coeff from read_o3data does not match value in GFS_typedefs.F90: ", & - oz_coeff, " /= ", size(ozpl, dim=3) - errflg = 1 - end if - !> - Call read_h2odata() to read stratospheric water vapor data call read_h2odata (h2o_phys, me, master) ! Consistency check that the hardcoded values for levh2o and - ! h2o_coeff in GFS_typedefs.F90 match what is set by read_o3data + ! h2o_coeff in GFS_typedefs.F90 match what is set by read_h2odata ! in GFS_typedefs.F90: allocate (Tbd%h2opl (IM,levh2o,h2o_coeff)) if (size(h2opl, dim=2).ne.levh2o) then write(errmsg,'(2a,i0,a,i0)') "Value error in GFS_phys_time_vary_init: ", & @@ -266,11 +244,6 @@ subroutine GFS_phys_time_vary_init ( !> - Initialize soil vegetation (needed for sncovr calculation further down) call set_soilveg(me, isot, ivegsrc, nlunit, errmsg, errflg) -!> - Call setindxoz() to initialize ozone data - if (ntoz > 0) then - call setindxoz (im, xlat_d, jindx1_o3, jindx2_o3, ddy_o3) - endif - !> - Call setindxh2o() to initialize stratospheric water vapor data if (h2o_phys) then call setindxh2o (im, xlat_d, jindx1_h, jindx2_h, ddy_h) @@ -652,8 +625,8 @@ end subroutine GFS_phys_time_vary_init !! @{ subroutine GFS_phys_time_vary_timestep_init ( & me, master, cnx, cny, isc, jsc, nrcm, im, levs, kdt, idate, nsswr, fhswr, lsswr, fhour, & - imfdeepcnv, cal_pre, random_clds, ntoz, h2o_phys, iaerclm, iccn, clstp, & - jindx1_o3, jindx2_o3, ddy_o3, ozpl, jindx1_h, jindx2_h, ddy_h, h2opl, iflip, & + imfdeepcnv, cal_pre, random_clds, h2o_phys, iaerclm, iccn, clstp, & + jindx1_h, jindx2_h, ddy_h, h2opl, iflip, & jindx1_aer, jindx2_aer, ddy_aer, iindx1_aer, iindx2_aer, ddx_aer, aer_nm, & jindx1_ci, jindx2_ci, ddy_ci, iindx1_ci, iindx2_ci, ddx_ci, in_nm, ccn_nm, & imap, jmap, prsl, seed0, rann, do_ugwp_v1, jindx1_tau, jindx2_tau, ddy_j1tau, ddy_j2tau,& @@ -663,14 +636,14 @@ subroutine GFS_phys_time_vary_timestep_init ( ! Interface variables integer, intent(in) :: me, master, cnx, cny, isc, jsc, nrcm, im, levs, kdt, & - nsswr, imfdeepcnv, iccn, ntoz, iflip + nsswr, imfdeepcnv, iccn, iflip integer, intent(in) :: idate(:) real(kind_phys), intent(in) :: fhswr, fhour logical, intent(in) :: lsswr, cal_pre, random_clds, h2o_phys, iaerclm real(kind_phys), intent(out) :: clstp - integer, intent(in) :: jindx1_o3(:), jindx2_o3(:), jindx1_h(:), jindx2_h(:) - real(kind_phys), intent(in) :: ddy_o3(:), ddy_h(:) - real(kind_phys), intent(inout) :: ozpl(:,:,:), h2opl(:,:,:) + integer, intent(in) :: jindx1_h(:), jindx2_h(:) + real(kind_phys), intent(in) :: ddy_h(:) + real(kind_phys), intent(inout) :: h2opl(:,:,:) integer, intent(in) :: jindx1_aer(:), jindx2_aer(:), iindx1_aer(:), iindx2_aer(:) real(kind_phys), intent(in) :: ddy_aer(:), ddx_aer(:) real(kind_phys), intent(inout) :: aer_nm(:,:,:) @@ -748,13 +721,6 @@ subroutine GFS_phys_time_vary_timestep_init ( endif ! imfdeepcnv, cal_re, random_clds -!> - Call ozinterpol() to make ozone interpolation - if (ntoz > 0) then - call ozinterpol (me, im, idate, fhour, & - jindx1_o3, jindx2_o3, & - ozpl, ddy_o3) - endif - !> - Call h2ointerpol() to make stratospheric water vapor data interpolation if (h2o_phys) then call h2ointerpol (me, im, idate, fhour, & @@ -844,12 +810,6 @@ subroutine GFS_phys_time_vary_finalize(errmsg, errflg) if (.not.is_initialized) return - ! Deallocate ozone arrays - if (allocated(oz_lat) ) deallocate(oz_lat) - if (allocated(oz_pres) ) deallocate(oz_pres) - if (allocated(oz_time) ) deallocate(oz_time) - if (allocated(ozplin) ) deallocate(ozplin) - ! Deallocate h2o arrays if (allocated(h2o_lat) ) deallocate(h2o_lat) if (allocated(h2o_pres)) deallocate(h2o_pres) diff --git a/physics/GFS_phys_time_vary.scm.meta b/physics/GFS_phys_time_vary.scm.meta index 8b59e4bed..21d1f2736 100644 --- a/physics/GFS_phys_time_vary.scm.meta +++ b/physics/GFS_phys_time_vary.scm.meta @@ -2,7 +2,7 @@ name = GFS_phys_time_vary type = scheme dependencies = aerclm_def.F,aerinterp.F90,h2o_def.f,h2ointerp.f90,iccn_def.F,iccninterp.F90,machine.F,mersenne_twister.f - dependencies = namelist_soilveg.f,set_soilveg.f,ozinterp.f90,ozne_def.f,cires_tauamf_data.F90,noahmp_tables.f90 + dependencies = namelist_soilveg.f,set_soilveg.f,cires_tauamf_data.F90,noahmp_tables.f90 ######################################################################## [ccpp-arg-table] @@ -23,13 +23,6 @@ dimensions = () type = integer intent = in -[ntoz] - standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array - long_name = tracer index for ozone mixing ratio - units = index - dimensions = () - type = integer - intent = in [h2o_phys] standard_name = flag_for_stratospheric_water_vapor_physics long_name = flag for stratospheric water vapor physics @@ -102,36 +95,6 @@ type = real kind = kind_phys intent = in -[jindx1_o3] - standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation low index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = inout -[jindx2_o3] - standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation high index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = inout -[ddy_o3] - standard_name = latitude_interpolation_weight_for_ozone_forcing - long_name = interpolation high index for ozone - units = none - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = inout -[ozpl] - standard_name = ozone_forcing - long_name = ozone forcing data - units = mixed - dimensions = (horizontal_dimension,vertical_dimension_of_ozone_forcing_data,number_of_coefficients_in_ozone_forcing_data) - type = real - kind = kind_phys - intent = in [jindx1_h] standard_name = lower_latitude_index_of_stratospheric_water_vapor_forcing_for_interpolation long_name = interpolation low index for stratospheric water vapor @@ -1056,13 +1019,6 @@ dimensions = () type = logical intent = in -[ntoz] - standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array - long_name = tracer index for ozone mixing ratio - units = index - dimensions = () - type = integer - intent = in [h2o_phys] standard_name = flag_for_stratospheric_water_vapor_physics long_name = flag for stratospheric water vapor physics @@ -1092,36 +1048,6 @@ type = real kind = kind_phys intent = out -[jindx1_o3] - standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation low index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[jindx2_o3] - standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation high index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[ddy_o3] - standard_name = latitude_interpolation_weight_for_ozone_forcing - long_name = interpolation high index for ozone - units = none - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = in -[ozpl] - standard_name = ozone_forcing - long_name = ozone forcing data - units = mixed - dimensions = (horizontal_dimension,vertical_dimension_of_ozone_forcing_data,number_of_coefficients_in_ozone_forcing_data) - type = real - kind = kind_phys - intent = inout [jindx1_h] standard_name = lower_latitude_index_of_stratospheric_water_vapor_forcing_for_interpolation long_name = interpolation low index for stratospheric water vapor diff --git a/physics/GFS_rrtmg_pre.F90 b/physics/GFS_rrtmg_pre.F90 index c45bec3e3..ae88ca0fc 100644 --- a/physics/GFS_rrtmg_pre.F90 +++ b/physics/GFS_rrtmg_pre.F90 @@ -45,7 +45,8 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& gasvmr_ccl4, gasvmr_cfc113, aerodp,ext550, clouds6, clouds7, clouds8, & clouds9, cldsa, cldfra, cldfra2d, lwp_ex,iwp_ex, lwp_fc,iwp_fc, & faersw1, faersw2, faersw3, faerlw1, faerlw2, faerlw3, alpha, & - aero_dir_fdb, fdb_coef, spp_wts_rad, spp_rad, ico2, errmsg, errflg) + aero_dir_fdb, fdb_coef, spp_wts_rad, spp_rad, ico2, latsozp, levozp, & + blatc, dphiozc, errmsg, errflg) use machine, only: kind_phys @@ -101,7 +102,8 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& imp_physics_mg, imp_physics_wsm6, & imp_physics_nssl, & imp_physics_fer_hires, & - yearlen, icloud, iaermdl, iaerflg + yearlen, icloud, iaermdl, iaerflg, & + latsozp, levozp integer, intent(in) :: & iovr, & ! choice of cloud-overlap method @@ -132,7 +134,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& integer, intent(in) :: spp_rad real(kind_phys), intent(in) :: spp_wts_rad(:,:) - real(kind=kind_phys), intent(in) :: fhswr, fhlwr, solhr, sup, julian, sppt_amp, dcorr_con + real(kind=kind_phys), intent(in) :: fhswr, fhlwr, solhr, sup, julian, sppt_amp, dcorr_con, blatc, dphiozc real(kind=kind_phys), intent(in) :: con_eps, epsm1, fvirt, rog, rocp, con_rd, con_pi, con_g, con_ttp, con_thgni real(kind=kind_phys), dimension(:), intent(in) :: xlat_d, xlat, xlon, & @@ -429,8 +431,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& enddo enddo else ! climatological ozone - call getozn (prslk1, xlat, im, lmk, top_at_1, & ! --- inputs - olyr) ! --- outputs + call getozn (prslk1, xlat, im, lmk, top_at_1, latsozp, levozp, blatc, dphiozc, olyr) endif ! end_if_ntoz !> - Call coszmn(), to compute cosine of zenith angle (only when SW is called) diff --git a/physics/GFS_rrtmg_pre.meta b/physics/GFS_rrtmg_pre.meta index d7feaeb3f..88363ef18 100644 --- a/physics/GFS_rrtmg_pre.meta +++ b/physics/GFS_rrtmg_pre.meta @@ -1496,6 +1496,36 @@ dimensions = () type = integer intent = in +[latsozp] + standard_name = number_of_latitudes_in_ozone_data + long_name = number of latitude in ozone data + units = count + dimensions = () + type = integer + intent = in +[levozp] + standard_name = number_of_levels_in_ozone_data + long_name = number of levels in ozone data + units = count + dimensions = () + type = integer + intent = in +[dphiozc] + standard_name = ozone_data_parameter_1 + long_name = ozone data parameter 1 + units = none + dimensions = () + type = real + kind = kind_phys + intent = in +[blatc] + standard_name = ozone_data_parameter_2 + long_name = ozone data parameter 2 + units = none + dimensions = () + type = real + kind = kind_phys + intent = in [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP diff --git a/physics/GFS_rrtmg_setup.F90 b/physics/GFS_rrtmg_setup.F90 index 384d5252d..30917b961 100644 --- a/physics/GFS_rrtmg_setup.F90 +++ b/physics/GFS_rrtmg_setup.F90 @@ -44,7 +44,7 @@ subroutine GFS_rrtmg_setup_init ( si, levr, ictm, isol, solar_file, ico2, & iaermdl, iaerflg, aeros_file, con_pi, con_t0c, con_c, con_boltz, & con_plnk, con_solr_2008, con_solr_2002, con_g, con_rd, co2usr_file, & co2cyc_file, rad_hr_units, inc_minor_gas, icliq_lw, isubcsw, isubclw,& - iswmode, ipsd0, ltp, lextop, errmsg, errflg) + iswmode, latsozp, levozp, timeozp, ipsd0, ltp, lextop, errmsg, errflg) ! ================= subprogram documentation block ================ ! ! ! ! subprogram: GFS_rrtmg_setup_init - a subprogram to initialize radiation ! @@ -155,7 +155,8 @@ subroutine GFS_rrtmg_setup_init ( si, levr, ictm, isol, solar_file, ico2, & integer, intent(in) :: levr, ictm, isol, ico2, iaer, ntcw, num_p3d, & ltp, npdf3d, ntoz, iovr, iovr_rand, iovr_maxrand, iovr_max, & iovr_dcorr, iovr_exp, iovr_exprand, icliq_sw, imp_physics, & - iflip, me, rad_hr_units, icliq_lw, isubcsw, isubclw, iswmode + iflip, me, rad_hr_units, icliq_lw, isubcsw, isubclw, iswmode, & + latsozp, levozp, timeozp integer, intent(in) :: idate(:) logical, intent(in) :: lcrick, lcnorm, lnoprec, do_RRTMGP, lalw1bd, & inc_minor_gas, lextop @@ -219,7 +220,7 @@ subroutine GFS_rrtmg_setup_init ( si, levr, ictm, isol, solar_file, ico2, & call aer_init ( levr, me, iaermdl, iaerflg, lalw1bd, aeros_file, & con_pi, con_t0c, con_c, con_boltz, con_plnk, errflg, errmsg) call gas_init ( me, co2usr_file, co2cyc_file, ico2, ictm, ntoz, & - con_pi, errflg, errmsg) + con_pi, latsozp, levozp, timeozp, errflg, errmsg) call cld_init ( si, levr, imp_physics, me, con_g, con_rd, errflg, errmsg) call rlwinit ( me, rad_hr_units, inc_minor_gas, icliq_lw, isubcsw, & iovr, iovr_rand, iovr_maxrand, iovr_max, iovr_dcorr, & diff --git a/physics/GFS_rrtmg_setup.meta b/physics/GFS_rrtmg_setup.meta index adf6d8750..42b999c82 100644 --- a/physics/GFS_rrtmg_setup.meta +++ b/physics/GFS_rrtmg_setup.meta @@ -173,6 +173,27 @@ dimensions = () type = integer intent = in +[levozp] + standard_name = number_of_levels_in_ozone_data + long_name = number of levels in ozone data + units = count + dimensions = () + type = integer + intent = in +[timeozp] + standard_name = number_of_times_in_ozone_data + long_name = number of times in ozone data + units = count + dimensions = () + type = integer + intent = in +[latsozp] + standard_name = number_of_latitudes_in_ozone_data + long_name = number of latitude in ozone data + units = count + dimensions = () + type = integer + intent = in [icliq_sw] standard_name = control_for_shortwave_radiation_liquid_clouds long_name = sw optical property for liquid clouds diff --git a/physics/ozinterp.f90 b/physics/ozinterp.f90 deleted file mode 100644 index 5b3149d61..000000000 --- a/physics/ozinterp.f90 +++ /dev/null @@ -1,212 +0,0 @@ -!>\file ozinterp.f90 -!! This file contains ozone climatology interpolation subroutines. - -!>\ingroup mod_GFS_phys_time_vary -!! This module contains subroutines of reading and interpolating ozone coefficients. -module ozinterp - - implicit none - - private - - public :: read_o3data, setindxoz, ozinterpol - -contains - - SUBROUTINE read_o3data (ntoz, me, master) - use machine, only: kind_phys - use ozne_def -!--- in/out - integer, intent(in) :: ntoz - integer, intent(in) :: me - integer, intent(in) :: master -!--- locals - integer :: i, n, k - real(kind=4), allocatable, dimension(:) :: oz_lat4, oz_pres4 - real(kind=4), allocatable, dimension(:) :: oz_time4, tempin - real(kind=4) :: blatc4 - - if (ntoz <= 0) then ! Diagnostic ozone - rewind (kozc) - read (kozc,end=101) latsozc, levozc, timeozc, blatc4 - 101 if (levozc < 10 .or. levozc > 100) then - rewind (kozc) - levozc = 17 - latsozc = 18 - blatc = -85.0 - else - blatc = blatc4 - endif - latsozp = 2 - levozp = 1 - timeoz = 1 - oz_coeff = 0 - dphiozc = -(blatc+blatc)/(latsozc-1) - return - endif - - open(unit=kozpl,file='global_o3prdlos.f77', form='unformatted', convert='big_endian') - -!--- read in indices -!--- - read (kozpl) oz_coeff, latsozp, levozp, timeoz - if (me == master) then - write(*,*) 'Reading in o3data from global_o3prdlos.f77 ' - write(*,*) ' oz_coeff = ', oz_coeff - write(*,*) ' latsozp = ', latsozp - write(*,*) ' levozp = ', levozp - write(*,*) ' timeoz = ', timeoz - endif - -!--- read in data -!--- oz_lat - latitude of data (-90 to 90) -!--- oz_pres - vertical pressure level (mb) -!--- oz_time - time coordinate (days) -!--- - allocate (oz_lat(latsozp), oz_pres(levozp),oz_time(timeoz+1)) - allocate (oz_lat4(latsozp), oz_pres4(levozp),oz_time4(timeoz+1)) - rewind (kozpl) - read (kozpl) oz_coeff, latsozp, levozp, timeoz, oz_lat4, oz_pres4, oz_time4 - oz_pres(:) = oz_pres4(:) -!--- convert pressure levels from mb to ln(Pa) - oz_pres(:) = log(100.0*oz_pres(:)) - oz_lat(:) = oz_lat4(:) - oz_time(:) = oz_time4(:) - deallocate (oz_lat4, oz_pres4, oz_time4) - -!--- read in ozplin which is in order of (lattitudes, ozone levels, coeff number, time) -!--- assume latitudes is on a uniform gaussian grid -!--- - allocate (tempin(latsozp)) - allocate (ozplin(latsozp,levozp,oz_coeff,timeoz)) - DO i=1,timeoz - DO n=1,oz_coeff - DO k=1,levozp - READ(kozpl) tempin - ozplin(:,k,n,i) = tempin(:) - ENDDO - ENDDO - ENDDO - deallocate (tempin) - - close(kozpl) - - END SUBROUTINE read_o3data -! -!********************************************************************** -! - SUBROUTINE setindxoz(npts,dlat,jindx1,jindx2,ddy) -! - USE MACHINE, ONLY: kind_phys - USE OZNE_DEF, ONLY: jo3 => latsozp, oz_lat -! - implicit none -! - integer npts, JINDX1(npts),JINDX2(npts) - real(kind=kind_phys) dlat(npts),DDY(npts) -! - integer i,j,lat -! - DO J=1,npts - jindx2(j) = jo3 + 1 - do i=1,jo3 - if (dlat(j) < oz_lat(i)) then - jindx2(j) = i - exit - endif - enddo - jindx1(j) = max(jindx2(j)-1,1) - jindx2(j) = min(jindx2(j),jo3) - if (jindx2(j) .ne. jindx1(j)) then - DDY(j) = (dlat(j) - oz_lat(jindx1(j))) & - / (oz_lat(jindx2(j)) - oz_lat(jindx1(j))) - else - ddy(j) = 1.0 - endif -! print *,' j=',j,' dlat=',dlat(j),' jindx12=',jindx1(j), & -! jjindx2(j),' oz_lat=',oz_lat(jindx1(j)), & -! oz_lat(jindx2(j)),' ddy=',ddy(j) - ENDDO - - RETURN - END SUBROUTINE setindxoz -! -!********************************************************************** -! - SUBROUTINE ozinterpol(me,npts,IDATE,FHOUR,jindx1,jindx2,ozplout,ddy) -! - USE MACHINE, ONLY : kind_phys - USE OZNE_DEF - implicit none - integer iday,j,j1,j2,l,npts,nc,n1,n2 - real(kind=kind_phys) fhour,tem, tx1, tx2 -! - - integer JINDX1(npts), JINDX2(npts) - integer me, idate(4), IDAT(8),JDAT(8) -! - real(kind=kind_phys) DDY(npts) - real(kind=kind_phys) ozplout(npts,levozp,oz_coeff) - real(kind=kind_phys) rjday - integer jdow, jdoy, jday - real(8) rinc(5) - real(4) rinc4(5) - integer w3kindreal,w3kindint -! - IDAT=0 - IDAT(1)=IDATE(4) - IDAT(2)=IDATE(2) - IDAT(3)=IDATE(3) - IDAT(5)=IDATE(1) - RINC=0. - RINC(2)=FHOUR - call w3kind(w3kindreal,w3kindint) - if(w3kindreal==4) then - rinc4=rinc - CALL W3MOVDAT(RINC4,IDAT,JDAT) - else - CALL W3MOVDAT(RINC,IDAT,JDAT) - endif -! - jdow = 0 - jdoy = 0 - jday = 0 - call w3doxdat(jdat,jdow,jdoy,jday) - rjday = jdoy + jdat(5) / 24. - IF (RJDAY < oz_time(1)) RJDAY = RJDAY + 365. -! - n2 = timeoz + 1 - do j=2,timeoz - if (rjday < oz_time(j)) then - n2 = j - exit - endif - enddo - n1 = n2 - 1 -! -! if (me == 0) print *,' n1=',n1,' n2=',n2,' rjday=',rjday -! &,'oz_time=',oz_time(n1),oz_time(n2) -! - - tx1 = (oz_time(n2) - rjday) / (oz_time(n2) - oz_time(n1)) - tx2 = 1.0 - tx1 - - if (n2 > timeoz) n2 = n2 - timeoz -! - do nc=1,oz_coeff - DO L=1,levozp - DO J=1,npts - J1 = JINDX1(J) - J2 = JINDX2(J) - TEM = 1.0 - DDY(J) - ozplout(j,L,nc) = & - tx1*(TEM*ozplin(J1,L,nc,n1)+DDY(J)*ozplin(J2,L,nc,n1)) & - + tx2*(TEM*ozplin(J1,L,nc,n2)+DDY(J)*ozplin(J2,L,nc,n2)) - ENDDO - ENDDO - enddo -! - RETURN - END SUBROUTINE ozinterpol - -end module ozinterp diff --git a/physics/ozne_def.f b/physics/ozne_def.f deleted file mode 100644 index 8f3af6240..000000000 --- a/physics/ozne_def.f +++ /dev/null @@ -1,24 +0,0 @@ -!>\file ozne_def.f -!! This file contains the ozone array definition used in ozone physics. - -!>\ingroup mod_GFS_phys_time_vary -!! This module defines arrays in Ozone scheme. - module ozne_def - -!> \section arg_table_ozne_def -!! \htmlinclude ozne_def.html -!! - - use machine , only : kind_phys - implicit none - - integer, parameter :: kozpl=28, kozc=48 - - integer latsozp, levozp, timeoz, latsozc, levozc, timeozc - &, oz_coeff - real (kind=kind_phys) blatc, dphiozc - real (kind=kind_phys), allocatable :: oz_lat(:), oz_pres(:) - &, oz_time(:) - real (kind=kind_phys), allocatable :: ozplin(:,:,:,:) - - end module ozne_def diff --git a/physics/ozne_def.meta b/physics/ozne_def.meta deleted file mode 100644 index 3cad9c14d..000000000 --- a/physics/ozne_def.meta +++ /dev/null @@ -1,29 +0,0 @@ -[ccpp-table-properties] - name = ozne_def - type = module - dependencies = machine.F - -[ccpp-arg-table] - name = ozne_def - type = module - -[levozp] - standard_name = vertical_dimension_of_ozone_forcing_data - long_name = number of vertical layers in ozone forcing data - units = count - dimensions = () - type = integer -[oz_coeff] - standard_name = number_of_coefficients_in_ozone_forcing_data - long_name = number of coefficients in ozone forcing data - units = index - dimensions = () - type = integer -[oz_pres] - standard_name = natural_log_of_ozone_forcing_data_pressure_levels - long_name = natural log of ozone forcing data pressure levels in Pa - units = 1 - dimensions = (vertical_dimension_of_ozone_forcing_data) - type = real - kind = kind_phys - active = (index_of_ozone_mixing_ratio_in_tracer_concentration_array>0) diff --git a/physics/ozphys_2015.F90 b/physics/ozphys_2015.F90 new file mode 100644 index 000000000..17f2178a4 --- /dev/null +++ b/physics/ozphys_2015.F90 @@ -0,0 +1,343 @@ +! ########################################################################################### +!> \file ozphys_2015.F90 +!! +! ########################################################################################### +module ozphys_2015 + use machine , only : kind_phys + implicit none + public ozphys_2015_init, ozphys_2015_timestep_init, ozphys_2015_run +contains + +! ########################################################################################### +!>\defgroup GFS_ozphys_2015 GFS Ozone Photochemistry (2015) Module +!! This module contains the CCPP-compliant Ozone 2015 photochemistry scheme. +!> @{ +!> \section arg_table_ozphys_2015_init Argument Table +!! \htmlinclude ozphys_2015_init.html +!! +! ########################################################################################### + subroutine ozphys_2015_init(oz_phys_2015, nPts, latsozp, oz_lat, dlat, jindx1, jindx2, & + ddy, errmsg, errflg) + ! Inputs + logical, intent(in) :: & + oz_phys_2015 ! Control flag for NRL 2015 ozone physics scheme + integer, intent(in) :: & + nPts, & ! Horizontal dimension + latsozp ! Number of latitudes in ozone data + real(kind_phys), intent(in), dimension(:) :: & + oz_lat, & ! Latitudes of ozone data + dlat ! Latitudes of grid + ! Outputs + integer, intent(out), dimension(:) :: & + jindx1, & ! Interpolation index (low) for ozone data + jindx2 ! Interpolation index (high) for ozone data + real(kind_phys), intent(out), dimension(:) :: & + ddy ! Interpolation high index for ozone data + character(len=*), intent(out) :: & + errmsg ! CCPP error message + integer, intent(out) :: & + errflg ! CCPP error flag + + ! Local + integer i,j + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + ! Sanity check + if (.not.oz_phys_2015) then + write (errmsg,'(*(a))') 'Logic error: oz_phys_2015 == .false.' + errflg = 1 + return + endif + + ! Set indices + do j=1,nPts + jindx2(j) = latsozp + 1 + do i=1,latsozp + if (dlat(j) < oz_lat(i)) then + jindx2(j) = i + exit + endif + enddo + jindx1(j) = max(jindx2(j)-1,1) + jindx2(j) = min(jindx2(j),latsozp) + if (jindx2(j) .ne. jindx1(j)) then + ddy(j) = (dlat(j) - oz_lat(jindx1(j))) / (oz_lat(jindx2(j)) - oz_lat(jindx1(j))) + else + ddy(j) = 1.0 + endif + enddo + + end subroutine ozphys_2015_init + +! ########################################################################################### +!> \section arg_table_ozphys_2015_timestep_init Argument Table +!! \htmlinclude ozphys_2015_timestep_init.html +!! +! ########################################################################################### + subroutine ozphys_2015_timestep_init(nPts, idate, fhour, jindx1, jindx2, latsozp, levozp, & + oz_coeff, timeoz, ozplin, oz_time, oz_pres, oz_lat, ddy, ozplout, errmsg, errflg) + ! Inputs + integer, intent(in) :: & + nPts, & ! Horizontal dimension + latsozp, & ! Number of latitudes in ozone data + levozp, & ! Number of levels in ozone data + oz_coeff, & ! Number of coefficients in ozone data + timeoz ! Number of times in ozone data + integer, intent(in),dimension(:) :: & + idate, & ! Initial date with different size and ordering + jindx1, & ! Interpolation index (low) for ozone + jindx2 ! Interpolation index (high) for ozone + real(kind_phys), intent(in) :: & + fhour ! Forecast hour + real(kind_phys), intent(in), dimension(:) :: & + ddy, & ! Interpolation high index for ozone data + oz_lat, & ! Latitudes for ozone data + oz_pres, & ! Levels for ozone data + oz_time ! Time for ozone data + real(kind_phys), intent(in), dimension(:,:,:,:) :: & + ozplin ! Ozone data + + ! Outputs + real(kind_phys), intent(out), dimension(:,:,:) :: & + ozplout ! Ozone forcing data + character(len=*), intent(out) :: & + errmsg ! CCPP error message + integer, intent(out) :: & + errflg ! CCPP error flag + + ! Local + integer :: idat(8),jdat(8),iday,j,j1,j2,l,nc,n1,n2,jdow,jdoy,& + jday,w3kindreal,w3kindint + real(kind_phys) :: tem, tx1, tx2, rjday + real(8) :: rinc(5) + real(4) :: rinc4(5) + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + ! + idat=0 + idat(1)=idate(4) + idat(2)=idate(2) + idat(3)=idate(3) + idat(5)=idate(1) + rinc=0. + rinc(2)=fhour + call w3kind(w3kindreal,w3kindint) + if(w3kindreal==4) then + rinc4=rinc + CALL w3movdat(rinc4,idat,jdat) + else + CALL w3movdat(rinc,idat,jdat) + endif + ! + jdow = 0 + jdoy = 0 + jday = 0 + call w3doxdat(jdat,jdow,jdoy,jday) + rjday = jdoy + jdat(5) / 24. + IF (RJDAY < oz_time(1)) RJDAY = RJDAY + 365. + ! + n2 = timeoz + 1 + do j=2,timeoz + if (rjday < oz_time(j)) then + n2 = j + exit + endif + enddo + n1 = n2 - 1 + + tx1 = (oz_time(n2) - rjday) / (oz_time(n2) - oz_time(n1)) + tx2 = 1.0 - tx1 + + if (n2 > timeoz) n2 = n2 - timeoz + ! + do nc=1,oz_coeff + do L=1,levozp + do J=1,npts + J1 = jindx1(J) + J2 = jindx2(J) + TEM = 1.0 - ddy(J) + ozplout(j,L,nc) = tx1*(TEM*ozplin(J1,L,nc,n1)+ddy(J)*ozplin(J2,L,nc,n1)) & + + tx2*(TEM*ozplin(J1,L,nc,n2)+ddy(J)*ozplin(J2,L,nc,n2)) + enddo + enddo + enddo + + ! + return + + end subroutine ozphys_2015_timestep_init + +! ########################################################################################### +!> The operational GFS currently parameterizes ozone production and +!! destruction based on monthly mean coefficients ( +!! \c ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77) provided by Naval +!! Research Laboratory through CHEM2D chemistry model +!! (McCormack et al. (2006) \cite mccormack_et_al_2006). +!! \section arg_table_ozphys_2015_run Argument Table +!! \htmlinclude ozphys_2015_run.html +!! +!> \section genal_ozphys_2015 GFS ozphys_2015_run General Algorithm +!> - This code assumes that both prsl and po3 are from bottom to top +!! as are all other variables. +!> - This code is specifically for NRL parameterization and +!! climatological T and O3 are in location 5 and 6 of prdout array +!!\author June 2015 - Shrinivas Moorthi +! ########################################################################################### + subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, prdout, pl_coeff, & + delp, ldiag3d, dtend, dtidx, ntoz, index_of_process_prod_loss, & + index_of_process_ozmix, index_of_process_temp, index_of_process_overhead_ozone, & + con_g, errmsg, errflg) + + ! Inputs + logical, intent(in) :: & + ldiag3d + real(kind_phys),intent(in) :: & + con_g + integer, intent(in) :: & + im, & ! + levs, & ! + ko3, & ! + pl_coeff, & ! + ntoz, & ! + index_of_process_prod_loss, & ! + index_of_process_ozmix, & ! + index_of_process_temp, & + index_of_process_overhead_ozone + integer, intent(in), dimension(:,:) :: & + dtidx ! + real(kind_phys), intent(in) :: & + dt ! + real(kind_phys), intent(in), dimension(:) :: & + po3 ! + real(kind_phys), intent(in), dimension(:,:) :: & + prsl, & ! + tin, & ! + delp ! + real(kind_phys), intent(in), dimension(:,:,:) :: & + prdout ! + + ! In/Outs + real(kind=kind_phys), intent(inout), dimension(:,:,:) :: & + dtend ! + + ! Outputs + real(kind=kind_phys), intent(inout), dimension(:,:) :: & + oz ! + character(len=*), intent(out) :: & + errmsg ! CCPP error message + integer, intent(out) :: & + errflg ! CCPP error flag + + ! Locals + integer :: k, kmax, kmin, l, i, j + integer, dimension(4) :: idtend + logical, dimension(im) :: flg + real :: gravi + real(kind_phys) :: pmax, pmin, tem, temp + real(kind_phys), dimension(im) :: wk1, wk2, wk3, ozib + real(kind_phys), dimension(im,pl_coeff) :: prod + real(kind_phys), dimension(im,levs) :: ozi + real(kind_phys), dimension(im,levs+1) :: colo3, coloz + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + ! Are UFS diagnostic tendencies requested? If so, set up bookeeping indices... + if(ldiag3d) then + idtend(1) = dtidx(100+ntoz,index_of_process_prod_loss) ! was ozp1 + idtend(2) = dtidx(100+ntoz,index_of_process_ozmix) ! was ozp2 + idtend(3) = dtidx(100+ntoz,index_of_process_temp) ! was ozp3 + idtend(4) = dtidx(100+ntoz,index_of_process_overhead_ozone) ! was ozp4 + else + idtend=0 + endif + + ! Temporaries + ozi = oz + gravi=1.0/con_g + + colo3(:,levs+1) = 0.0 + coloz(:,levs+1) = 0.0 + + do l=levs,1,-1 + pmin = 1.0e10 + pmax = -1.0e10 + + do i=1,im + wk1(i) = log(prsl(i,l)) + pmin = min(wk1(i), pmin) + pmax = max(wk1(i), pmax) + prod(i,:) = 0.0 + enddo + kmax = 1 + kmin = 1 + do k=1,ko3-1 + if (pmin < po3(k)) kmax = k + if (pmax < po3(k)) kmin = k + enddo + ! + do k=kmin,kmax + temp = 1.0 / (po3(k) - po3(k+1)) + do i=1,im + flg(i) = .false. + if (wk1(i) < po3(k) .and. wk1(i) >= po3(k+1)) then + flg(i) = .true. + wk2(i) = (wk1(i) - po3(k+1)) * temp + wk3(i) = 1.0 - wk2(i) + endif + enddo + do j=1,pl_coeff + do i=1,im + if (flg(i)) then + prod(i,j) = wk2(i) * prdout(i,k,j) + wk3(i) * prdout(i,k+1,j) + endif + enddo + enddo + enddo + + do j=1,pl_coeff + do i=1,im + if (wk1(i) < po3(ko3)) then + prod(i,j) = prdout(i,ko3,j) + endif + if (wk1(i) >= po3(1)) then + prod(i,j) = prdout(i,1,j) + endif + enddo + enddo + do i=1,im + colo3(i,l) = colo3(i,l+1) + ozi(i,l) * delp(i,l)*gravi + coloz(i,l) = coloz(i,l+1) + prod(i,6) * delp(i,l)*gravi + prod(i,2) = min(prod(i,2), 0.0) + enddo + do i=1,im + ozib(i) = ozi(i,l) ! no filling + tem = prod(i,1) - prod(i,2) * prod(i,6) + prod(i,3) * (tin(i,l) - prod(i,5)) & + + prod(i,4) * (colo3(i,l)-coloz(i,l)) + oz(i,l) = (ozib(i) + tem*dt) / (1.0 - prod(i,2)*dt) + enddo + if(idtend(1)>=1) then + dtend(:,l,idtend(1)) = dtend(:,l,idtend(1)) + (prod(:,1)-prod(:,2)*prod(:,6))*dt + endif + if(idtend(2)>=1) then + dtend(:,l,idtend(2)) = dtend(:,l,idtend(2)) + (oz(:,l) - ozib(:)) + endif + if(idtend(3)>=1) then + dtend(:,l,idtend(3)) = dtend(:,l,idtend(3)) + prod(:,3)*(tin(:,l)-prod(:,5))*dt + endif + if(idtend(4)>=1) then + dtend(:,l,idtend(4)) = dtend(:,l,idtend(4)) + prod(:,4) * (colo3(:,l)-coloz(:,l))*dt + endif + enddo + + return + end subroutine ozphys_2015_run +!> @} +end module ozphys_2015 diff --git a/physics/ozphys_2015.f b/physics/ozphys_2015.f deleted file mode 100644 index 85c79f733..000000000 --- a/physics/ozphys_2015.f +++ /dev/null @@ -1,190 +0,0 @@ -!> \file ozphys_2015.f -!! This file is ozone sources and sinks. - - - module ozphys_2015 - - contains - -!>\defgroup GFS_ozphys_2015 GFS Ozone Photochemistry (2015) Module -!! This module contains the CCPP-compliant Ozone 2015 photochemistry scheme. -!> @{ -!> \section arg_table_ozphys_2015_init Argument Table -!! \htmlinclude ozphys_2015_init.html -!! - subroutine ozphys_2015_init(oz_phys_2015, errmsg, errflg) - - implicit none - logical, intent(in) :: oz_phys_2015 - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - if (.not.oz_phys_2015) then - write (errmsg,'(*(a))') 'Logic error: oz_phys_2015 == .false.' - errflg = 1 - return - endif - - end subroutine ozphys_2015_init - -!> The operational GFS currently parameterizes ozone production and -!! destruction based on monthly mean coefficients ( -!! \c ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77) provided by Naval -!! Research Laboratory through CHEM2D chemistry model -!! (McCormack et al. (2006) \cite mccormack_et_al_2006). -!! \section arg_table_ozphys_2015_run Argument Table -!! \htmlinclude ozphys_2015_run.html -!! -!> \section genal_ozphys_2015 GFS ozphys_2015_run General Algorithm -!> - This code assumes that both prsl and po3 are from bottom to top -!! as are all other variables. -!> - This code is specifically for NRL parameterization and -!! climatological T and O3 are in location 5 and 6 of prdout array -!!\author June 2015 - Shrinivas Moorthi - subroutine ozphys_2015_run ( & - & im, levs, ko3, dt, oz, tin, po3, prsl, prdout, pl_coeff, & - & delp, ldiag3d, dtend, dtidx, ntoz, index_of_process_prod_loss& - & , index_of_process_ozmix, index_of_process_temp, & - & index_of_process_overhead_ozone, con_g, me, errmsg, errflg) -! -! - use machine , only : kind_phys - implicit none -! - real(kind=kind_phys),intent(in) :: con_g - real :: gravi - integer, intent(in) :: im, levs, ko3, pl_coeff,me - real(kind=kind_phys), intent(in) :: po3(:), & - & prsl(:,:), tin(:,:), & - & delp(:,:), & - & prdout(:,:,:), dt - real(kind=kind_phys), intent(inout) :: dtend(:,:,:) - integer, intent(in) :: dtidx(:,:), ntoz, & - & index_of_process_prod_loss, index_of_process_ozmix, & - & index_of_process_temp, index_of_process_overhead_ozone - real(kind=kind_phys), intent(inout) :: oz(im,levs) - - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg - - integer k,kmax,kmin,l,i,j, idtend(4) - logical ldiag3d, flg(im), qdiag3d - real(kind=kind_phys) pmax, pmin, tem, temp - real(kind=kind_phys) wk1(im), wk2(im), wk3(im),prod(im,pl_coeff), & - & ozib(im), colo3(im,levs+1), coloz(im,levs+1),& - & ozi(im,levs) -! - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - if(ldiag3d) then - idtend(1) = dtidx(100+ntoz,index_of_process_prod_loss) ! was ozp1 - idtend(2) = dtidx(100+ntoz,index_of_process_ozmix) ! was ozp2 - idtend(3) = dtidx(100+ntoz,index_of_process_temp) ! was ozp3 - idtend(4) = dtidx(100+ntoz,index_of_process_overhead_ozone) ! was ozp4 - else - idtend=0 - endif - -!ccpp: save input oz in ozi - ozi = oz - gravi=1.0/con_g - - colo3(:,levs+1) = 0.0 - coloz(:,levs+1) = 0.0 -! - do l=levs,1,-1 - pmin = 1.0e10 - pmax = -1.0e10 -! - do i=1,im - wk1(i) = log(prsl(i,l)) - pmin = min(wk1(i), pmin) - pmax = max(wk1(i), pmax) - prod(i,:) = 0.0 - enddo - kmax = 1 - kmin = 1 - do k=1,ko3-1 - if (pmin < po3(k)) kmax = k - if (pmax < po3(k)) kmin = k - enddo -! - do k=kmin,kmax - temp = 1.0 / (po3(k) - po3(k+1)) - do i=1,im - flg(i) = .false. - if (wk1(i) < po3(k) .and. wk1(i) >= po3(k+1)) then - flg(i) = .true. - wk2(i) = (wk1(i) - po3(k+1)) * temp - wk3(i) = 1.0 - wk2(i) - endif - enddo - do j=1,pl_coeff - do i=1,im - if (flg(i)) then - prod(i,j) = wk2(i) * prdout(i,k,j) - & + wk3(i) * prdout(i,k+1,j) - endif - enddo - enddo - enddo -! - do j=1,pl_coeff - do i=1,im - if (wk1(i) < po3(ko3)) then - prod(i,j) = prdout(i,ko3,j) - endif - if (wk1(i) >= po3(1)) then - prod(i,j) = prdout(i,1,j) - endif - enddo - enddo - do i=1,im - colo3(i,l) = colo3(i,l+1) + ozi(i,l) * delp(i,l)*gravi - coloz(i,l) = coloz(i,l+1) + prod(i,6) * delp(i,l)*gravi - prod(i,2) = min(prod(i,2), 0.0) - enddo -! write(1000+me,*) ' colo3=',colo3(1,l),' coloz=',coloz(1,l) -! &,' l=',l - do i=1,im - ozib(i) = ozi(i,l) ! no filling - tem = prod(i,1) - prod(i,2) * prod(i,6) - & + prod(i,3) * (tin(i,l) - prod(i,5)) - & + prod(i,4) * (colo3(i,l)-coloz(i,l)) - -! if (me .eq. 0) print *,'ozphys_2015 tem=',tem,' prod=',prod(i,:) -! &,' ozib=',ozib(i),' l=',l,' tin=',tin(i,l),'colo3=',colo3(i,l+1) - -!ccpp ozo(i,l) = (ozib(i) + tem*dt) / (1.0 - prod(i,2)*dt) - oz(i,l) = (ozib(i) + tem*dt) / (1.0 - prod(i,2)*dt) - enddo - if(idtend(1)>=1) then - dtend(:,l,idtend(1)) = dtend(:,l,idtend(1)) + ! was ozp1 - & (prod(:,1)-prod(:,2)*prod(:,6))*dt - endif - if(idtend(2)>=1) then - dtend(:,l,idtend(2)) = dtend(:,l,idtend(2)) + ! was ozp2 - & (oz(:,l) - ozib(:)) - endif - if(idtend(3)>=1) then - dtend(:,l,idtend(3)) = dtend(:,l,idtend(3)) + ! was ozp3 - & prod(:,3)*(tin(:,l)-prod(:,5))*dt - endif - if(idtend(4)>=1) then - dtend(:,l,idtend(4)) = dtend(:,l,idtend(4)) + ! was ozp4 - & prod(:,4) * (colo3(:,l)-coloz(:,l))*dt - endif - enddo ! vertical loop -! - return - end subroutine ozphys_2015_run - -!> @} - - end module ozphys_2015 diff --git a/physics/ozphys_2015.meta b/physics/ozphys_2015.meta index 8bce7defe..59621b386 100644 --- a/physics/ozphys_2015.meta +++ b/physics/ozphys_2015.meta @@ -7,6 +7,20 @@ [ccpp-arg-table] name = ozphys_2015_init type = scheme +[nPts] + standard_name = horizontal_dimension + long_name = horizontal dimension + units = count + dimensions = () + type = integer + intent = in +[latsozp] + standard_name = number_of_latitudes_in_ozone_data + long_name = number of latitude in ozone data + units = count + dimensions = () + type = integer + intent = in [oz_phys_2015] standard_name = flag_for_nrl_2015_ozone_scheme long_name = flag for new (2015) ozone physics @@ -14,6 +28,176 @@ dimensions = () type = logical intent = in +[oz_lat] + standard_name = ozone_data_latitude + long_name = ozone data latitude + units = deg + dimensions = (number_of_latitudes_in_ozone_data) + type = real + kind = kind_phys + intent = in +[dlat] + standard_name = latitude_in_degree + long_name = latitude in degree north + units = degree_north + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = in +[jindx1] + standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation low index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = out +[jindx2] + standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation high index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = out +[ddy] + standard_name = latitude_interpolation_weight_for_ozone_forcing + long_name = interpolation high index for ozone + units = none + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = out +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = ozphys_2015_timestep_init + type = scheme +[nPts] + standard_name = horizontal_dimension + long_name = horizontal dimension + units = count + dimensions = () + type = integer + intent = in +[idate] + standard_name = date_and_time_at_model_initialization_in_united_states_order + long_name = initial date with different size and ordering + units = none + dimensions = (4) + type = integer + intent = in +[fhour] + standard_name = forecast_time + long_name = current forecast time + units = h + dimensions = () + type = real + kind = kind_phys + intent = in +[jindx1] + standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation low index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[jindx2] + standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation high index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[latsozp] + standard_name = number_of_latitudes_in_ozone_data + long_name = number of latitude in ozone data + units = count + dimensions = () + type = integer + intent = in +[levozp] + standard_name = number_of_levels_in_ozone_data + long_name = number of levels in ozone data + units = count + dimensions = () + type = integer + intent = in +[oz_coeff] + standard_name = number_of_coefficients_in_ozone_data + long_name = number of coefficients in ozone data + units = count + dimensions = () + type = integer + intent = in +[timeoz] + standard_name = number_of_times_in_ozone_data + long_name = number of times in ozone data + units = count + dimensions = () + type = integer + intent = in +[ozplin] + standard_name = ozone_data + long_name = ozone data + units = 1 + dimensions = (number_of_latitudes_in_ozone_data,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data,number_of_times_in_ozone_data) + type = real + kind = kind_phys + intent = in +[oz_time] + standard_name = ozone_data_time + long_name = ozone data time + units = none + dimensions = (13) + type = real + kind = kind_phys + intent = in +[oz_pres] + standard_name = ozone_data_level_pressure + long_name = ozone data level pressure + units = Pa + dimensions = (number_of_levels_in_ozone_data) + type = real + kind = kind_phys + intent = in +[oz_lat] + standard_name = ozone_data_latitude + long_name = ozone data latitude + units = deg + dimensions = (number_of_latitudes_in_ozone_data) + type = real + kind = kind_phys + intent = in +[ddy] + standard_name = latitude_interpolation_weight_for_ozone_forcing + long_name = interpolation high index for ozone + units = none + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = in +[ozplout] + standard_name = ozone_forcing + long_name = ozone forcing data + units = mixed + dimensions = (horizontal_dimension,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) + type = real + kind = kind_phys + intent = out [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP @@ -49,7 +233,7 @@ type = integer intent = in [ko3] - standard_name = vertical_dimension_of_ozone_forcing_data + standard_name = number_of_levels_in_ozone_data long_name = number of vertical layers in ozone forcing data units = count dimensions = () @@ -80,10 +264,10 @@ kind = kind_phys intent = in [po3] - standard_name = natural_log_of_ozone_forcing_data_pressure_levels + standard_name = natural_log_of_ozone_data_pressure_levels long_name = natural log of ozone forcing data pressure levels units = 1 - dimensions = (vertical_dimension_of_ozone_forcing_data) + dimensions = (number_of_levels_in_ozone_data) type = real kind = kind_phys intent = in @@ -99,14 +283,14 @@ standard_name = ozone_forcing long_name = ozone forcing data units = mixed - dimensions = (horizontal_loop_extent,vertical_dimension_of_ozone_forcing_data,number_of_coefficients_in_ozone_forcing_data) + dimensions = (horizontal_loop_extent,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) type = real kind = kind_phys intent = in [pl_coeff] - standard_name = number_of_coefficients_in_ozone_forcing_data + standard_name = number_of_coefficients_in_ozone_data long_name = number of coefficients in ozone forcing data - units = index + units = count dimensions = () type = integer intent = in @@ -183,13 +367,6 @@ type = real kind = kind_phys intent = in -[me] - standard_name = mpi_rank - long_name = rank of the current MPI task - units = index - dimensions = () - type = integer - intent = in [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP diff --git a/physics/radiation_gases.f b/physics/radiation_gases.f index ccc3b598a..5f017598f 100644 --- a/physics/radiation_gases.f +++ b/physics/radiation_gases.f @@ -142,9 +142,6 @@ module module_radiation_gases use machine, only : kind_phys, kind_io4 use funcphys, only : fpkapx - use ozne_def, only : JMR => latsozc, LOZ => levozc, & - & blte => blatc, dlte=> dphiozc, & - & timeozc => timeozc use module_iounitdef, only : NIO3CLM, NICO2CN ! implicit none @@ -233,7 +230,7 @@ module module_radiation_gases !>\section gas_init_gen gas_init General Algorithm !----------------------------------- subroutine gas_init( me, co2usr_file, co2cyc_file, ico2flg, & - & ictmflg, ioznflg, con_pi, errflg, errmsg) + & ictmflg, ioznflg, con_pi, JMR, LOZ, timeozc, errflg, errmsg) ! =================================================================== ! ! ! @@ -283,8 +280,10 @@ subroutine gas_init( me, co2usr_file, co2cyc_file, ico2flg, & ! --- inputs: integer, intent(in) :: me, ictmflg, ioznflg, ico2flg + integer, intent(in) :: JMR, LOZ, timeozc character(len=26),intent(in) :: co2usr_file,co2cyc_file real(kind=kind_phys), intent(in) :: con_pi + ! --- output: character(len=*), intent(out) :: errmsg integer, intent(out) :: errflg @@ -1115,7 +1114,8 @@ end subroutine getgases !! ratio (g/g) !>\section getozn_gen getozn General Algorithm !----------------------------------- - subroutine getozn( prslk,xlat, IMAX, LM, top_at_1, o3mmr) + subroutine getozn( prslk,xlat, IMAX, LM, top_at_1, JMR, LOZ, blte,& + & dlte, o3mmr) ! =================================================================== ! ! ! @@ -1144,7 +1144,8 @@ subroutine getozn( prslk,xlat, IMAX, LM, top_at_1, o3mmr) implicit none ! --- inputs: - integer, intent(in) :: IMAX, LM + integer, intent(in) :: IMAX, LM, JMR, LOZ + real(kind=kind_phys), intent(in) :: blte, dlte logical, intent(in) :: top_at_1 real (kind=kind_phys), intent(in) :: prslk(:,:), xlat(:) From 70b9d7e5ddaf8a4308415ea601a1f8366f62e9d1 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Thu, 25 May 2023 10:27:12 -0600 Subject: [PATCH 02/25] RRTMGP changes for refactored NRL ozone physics. --- physics/GFS_rrtmgp_pre.F90 | 13 +++++++--- physics/GFS_rrtmgp_pre.meta | 30 ++++++++++++++++++++++ physics/GFS_rrtmgp_setup.F90 | 13 +++++----- physics/GFS_rrtmgp_setup.meta | 21 ++++++++++++++++ physics/ozphys_2015.F90 | 47 ++++++++++++++++++----------------- 5 files changed, 91 insertions(+), 33 deletions(-) diff --git a/physics/GFS_rrtmgp_pre.F90 b/physics/GFS_rrtmgp_pre.F90 index 009eb8c38..e9cbc3d23 100644 --- a/physics/GFS_rrtmgp_pre.F90 +++ b/physics/GFS_rrtmgp_pre.F90 @@ -117,7 +117,7 @@ subroutine GFS_rrtmgp_pre_run(me, nCol, nLev, i_o3, doSWrad, doLWrad, fhswr, fhl vmr_n2o, vmr_co2, tsfg, tsfa, qs_lay, q_lay, tv_lay, & relhum, deltaZ, deltaZc, deltaP, active_gases_array, & tsfc_radtime, coszen, coszdg, top_at_1, iSFC, iTOA, nDay, idxday, semis, & - sfc_emiss_byband, ico2, con_pi, errmsg, errflg) + sfc_emiss_byband, ico2, latsozp, levozp, blatc, dphiozc, con_pi, errmsg, errflg) ! Inputs integer, intent(in) :: & @@ -125,13 +125,17 @@ subroutine GFS_rrtmgp_pre_run(me, nCol, nLev, i_o3, doSWrad, doLWrad, fhswr, fhl nCol, & ! Number of horizontal grid points nLev, & ! Number of vertical layers ico2, & ! Flag for co2 radiation scheme - i_o3 ! Index into tracer array for ozone + i_o3, & ! Index into tracer array for ozone + latsozp, & ! + levozp logical, intent(in) :: & doSWrad, & ! Call SW radiation? doLWrad ! Call LW radiation real(kind_phys), intent(in) :: & fhswr, & ! Frequency of SW radiation call. - fhlwr ! Frequency of LW radiation call. + fhlwr, & ! Frequency of LW radiation call. + blatc, & ! + dphiozc real(kind_phys), intent(in) :: & con_g, & ! Physical constant: gravitational constant con_rd, & ! Physical constant: gas-constant for dry air @@ -350,7 +354,8 @@ subroutine GFS_rrtmgp_pre_run(me, nCol, nLev, i_o3, doSWrad, doLWrad, fhswr, fhl enddo ! OR Use climatological ozone data else - call getozn (prslk(1:NCOL,:), xlat, nCol, nLev, top_at_1, o3_lay) + call getozn (prslk(1:NCOL,:), xlat, nCol, nLev, top_at_1, latsozp, levozp, blatc, & + dphiozc, o3_lay) endif ! ####################################################################################### diff --git a/physics/GFS_rrtmgp_pre.meta b/physics/GFS_rrtmgp_pre.meta index abb07b825..47980b513 100644 --- a/physics/GFS_rrtmgp_pre.meta +++ b/physics/GFS_rrtmgp_pre.meta @@ -503,6 +503,36 @@ dimensions = (horizontal_loop_extent) type = integer intent = inout +[latsozp] + standard_name = number_of_latitudes_in_ozone_data + long_name = number of latitude in ozone data + units = count + dimensions = () + type = integer + intent = in +[levozp] + standard_name = number_of_levels_in_ozone_data + long_name = number of levels in ozone data + units = count + dimensions = () + type = integer + intent = in +[dphiozc] + standard_name = ozone_data_parameter_1 + long_name = ozone data parameter 1 + units = none + dimensions = () + type = real + kind = kind_phys + intent = in +[blatc] + standard_name = ozone_data_parameter_2 + long_name = ozone data parameter 2 + units = none + dimensions = () + type = real + kind = kind_phys + intent = in [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP diff --git a/physics/GFS_rrtmgp_setup.F90 b/physics/GFS_rrtmgp_setup.F90 index 76db14279..7b5479e60 100644 --- a/physics/GFS_rrtmgp_setup.F90 +++ b/physics/GFS_rrtmgp_setup.F90 @@ -37,9 +37,10 @@ module GFS_rrtmgp_setup subroutine GFS_rrtmgp_setup_init(do_RRTMGP, imp_physics, imp_physics_fer_hires, & imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6, imp_physics_zhao_carr, & imp_physics_zhao_carr_pdf, imp_physics_mg, si, levr, ictm, isol, ico2, iaer, & - ntcw, ntoz, iovr, isubc_sw, isubc_lw, lalw1bd, idate, me, aeros_file, & - iaermdl, iaerflg, con_pi, con_t0c, con_c, con_boltz, con_plnk, solar_file, & - con_solr_2008, con_solr_2002, co2usr_file, co2cyc_file, ipsd0, errmsg, errflg) + ntcw, ntoz, iovr, latsozp, levozp, timeozp, isubc_sw, isubc_lw, lalw1bd, idate, & + me, aeros_file, iaermdl, iaerflg, con_pi, con_t0c, con_c, con_boltz, con_plnk, & + solar_file, con_solr_2008, con_solr_2002, co2usr_file, co2cyc_file, ipsd0, & + errmsg, errflg) ! Inputs logical, intent(in) :: do_RRTMGP @@ -57,8 +58,7 @@ subroutine GFS_rrtmgp_setup_init(do_RRTMGP, imp_physics, imp_physics_fer_hires, real(kind_phys), dimension(:), intent(in) :: & si integer, intent(in) :: levr, ictm, isol, ico2, iaer, & - ntcw, ntoz, iovr, isubc_sw, isubc_lw, & - me + ntcw, ntoz, iovr, isubc_sw, isubc_lw, latsozp, levozp, timeozp, me logical, intent(in) :: & lalw1bd integer, intent(in), dimension(:) :: & @@ -129,7 +129,8 @@ subroutine GFS_rrtmgp_setup_init(do_RRTMGP, imp_physics, imp_physics_fer_hires, call sol_init ( me, isol, solar_file, con_solr_2008, con_solr_2002, con_pi ) call aer_init ( levr, me, iaermdl, iaerflg, lalw1bd, aeros_file, con_pi, con_t0c, & con_c, con_boltz, con_plnk, errflg, errmsg) - call gas_init ( me, co2usr_file, co2cyc_file, ico2, ictm, ntoz, con_pi, errflg, errmsg ) + call gas_init ( me, co2usr_file, co2cyc_file, ico2, ictm, ntoz, con_pi, latsozp, & + levozp, timeozp, errflg, errmsg ) if ( me == 0 ) then print *,' return from rad_initialize (GFS_rrtmgp_setup_init) - after calling radinit' diff --git a/physics/GFS_rrtmgp_setup.meta b/physics/GFS_rrtmgp_setup.meta index c4f7cfaa5..567294d4a 100644 --- a/physics/GFS_rrtmgp_setup.meta +++ b/physics/GFS_rrtmgp_setup.meta @@ -266,6 +266,27 @@ dimensions = () type = integer intent = inout +[levozp] + standard_name = number_of_levels_in_ozone_data + long_name = number of levels in ozone data + units = count + dimensions = () + type = integer + intent = in +[timeozp] + standard_name = number_of_times_in_ozone_data + long_name = number of times in ozone data + units = count + dimensions = () + type = integer + intent = in +[latsozp] + standard_name = number_of_latitudes_in_ozone_data + long_name = number of latitude in ozone data + units = count + dimensions = () + type = integer + intent = in [iaermdl] standard_name = control_for_aerosol_radiation_scheme long_name = control of aerosol scheme in radiation diff --git a/physics/ozphys_2015.F90 b/physics/ozphys_2015.F90 index 17f2178a4..4e73a5262 100644 --- a/physics/ozphys_2015.F90 +++ b/physics/ozphys_2015.F90 @@ -83,7 +83,7 @@ subroutine ozphys_2015_timestep_init(nPts, idate, fhour, jindx1, jindx2, latsozp integer, intent(in) :: & nPts, & ! Horizontal dimension latsozp, & ! Number of latitudes in ozone data - levozp, & ! Number of levels in ozone data + levozp, & ! Number of vertical layers in ozone data oz_coeff, & ! Number of coefficients in ozone data timeoz ! Number of times in ozone data integer, intent(in),dimension(:) :: & @@ -188,6 +188,7 @@ end subroutine ozphys_2015_timestep_init !> - This code is specifically for NRL parameterization and !! climatological T and O3 are in location 5 and 6 of prdout array !!\author June 2015 - Shrinivas Moorthi +!!\author May 2023 - Dustin Swales ! ########################################################################################### subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, prdout, pl_coeff, & delp, ldiag3d, dtend, dtidx, ntoz, index_of_process_prod_loss, & @@ -196,43 +197,43 @@ subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, prdout, pl_c ! Inputs logical, intent(in) :: & - ldiag3d + ldiag3d ! Flag to output GFS diagnostic tendencies real(kind_phys),intent(in) :: & - con_g + con_g ! Physical constant: Gravitational acceleration (ms-2) integer, intent(in) :: & - im, & ! - levs, & ! - ko3, & ! - pl_coeff, & ! - ntoz, & ! - index_of_process_prod_loss, & ! - index_of_process_ozmix, & ! - index_of_process_temp, & - index_of_process_overhead_ozone + im, & ! Horizontal dimension + levs, & ! Number of vertical layers + ko3, & ! Number of vertical layers in ozone forcing data + pl_coeff, & ! Number of coefficients in ozone forcing data + ntoz, & ! Index for ozone mixing ratio + index_of_process_prod_loss, & ! Index for process in diagnostic tendency output + index_of_process_ozmix, & ! Index for process in diagnostic tendency output + index_of_process_temp, & ! Index for process in diagnostic tendency output + index_of_process_overhead_ozone ! Index for process in diagnostic tendency output integer, intent(in), dimension(:,:) :: & - dtidx ! + dtidx ! Bookkeeping indices for GFS diagnostic tendencies real(kind_phys), intent(in) :: & - dt ! + dt ! Physics timestep (seconds) real(kind_phys), intent(in), dimension(:) :: & - po3 ! + po3 ! Natural log of ozone forcing data pressure levels real(kind_phys), intent(in), dimension(:,:) :: & - prsl, & ! - tin, & ! - delp ! + prsl, & ! Air-pressure (Pa) + tin, & ! Temperature of new-state (K) + delp ! Difference between mid-layer pressures (Pa) real(kind_phys), intent(in), dimension(:,:,:) :: & - prdout ! + prdout ! Ozone forcing data ! In/Outs real(kind=kind_phys), intent(inout), dimension(:,:,:) :: & - dtend ! + dtend ! Diagnostic tendencies for state variables ! Outputs real(kind=kind_phys), intent(inout), dimension(:,:) :: & - oz ! + oz ! Ozone concentration updated by physics character(len=*), intent(out) :: & - errmsg ! CCPP error message + errmsg ! CCPP error message integer, intent(out) :: & - errflg ! CCPP error flag + errflg ! CCPP error flag ! Locals integer :: k, kmax, kmin, l, i, j From 6ff8689d3e1ed9ccaec7c09db6d8b12f633e59c1 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Thu, 25 May 2023 11:34:29 -0600 Subject: [PATCH 03/25] Revert change to CI test from NCAR->UWM merge --- .github/workflows/ci_fv3_ccpp_prebuild.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci_fv3_ccpp_prebuild.yml b/.github/workflows/ci_fv3_ccpp_prebuild.yml index b23c9977e..a5c2f8092 100644 --- a/.github/workflows/ci_fv3_ccpp_prebuild.yml +++ b/.github/workflows/ci_fv3_ccpp_prebuild.yml @@ -24,7 +24,7 @@ jobs: run: echo "GIT_REMOTE_HASH=`git rev-parse HEAD`" >> $GITHUB_ENV - name: Checkout latest fv3atm - run: git clone https://github.com/NCAR/fv3atm.git + run: git clone https://github.com/NOAA-EMC/fv3atm.git - name: Initialize submodules run: | From 9859339985948e4d1fe2c721f7fab7830101dd72 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Thu, 15 Jun 2023 11:17:35 -0600 Subject: [PATCH 04/25] Some changes --- physics/GFS_rrtmg_pre.F90 | 6 +++--- physics/GFS_rrtmg_pre.meta | 12 ++++++------ physics/GFS_rrtmgp_pre.F90 | 8 ++++---- physics/GFS_rrtmgp_pre.meta | 12 ++++++------ physics/ozphys_2015.F90 | 7 ++++--- physics/ozphys_2015.meta | 8 -------- 6 files changed, 23 insertions(+), 30 deletions(-) diff --git a/physics/GFS_rrtmg_pre.F90 b/physics/GFS_rrtmg_pre.F90 index ae88ca0fc..cf9bbb6aa 100644 --- a/physics/GFS_rrtmg_pre.F90 +++ b/physics/GFS_rrtmg_pre.F90 @@ -45,7 +45,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& gasvmr_ccl4, gasvmr_cfc113, aerodp,ext550, clouds6, clouds7, clouds8, & clouds9, cldsa, cldfra, cldfra2d, lwp_ex,iwp_ex, lwp_fc,iwp_fc, & faersw1, faersw2, faersw3, faerlw1, faerlw2, faerlw3, alpha, & - aero_dir_fdb, fdb_coef, spp_wts_rad, spp_rad, ico2, latsozp, levozp, & + aero_dir_fdb, fdb_coef, spp_wts_rad, spp_rad, ico2, latsozc, levozc, & blatc, dphiozc, errmsg, errflg) use machine, only: kind_phys @@ -103,7 +103,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& imp_physics_nssl, & imp_physics_fer_hires, & yearlen, icloud, iaermdl, iaerflg, & - latsozp, levozp + latsozc, levozc integer, intent(in) :: & iovr, & ! choice of cloud-overlap method @@ -431,7 +431,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& enddo enddo else ! climatological ozone - call getozn (prslk1, xlat, im, lmk, top_at_1, latsozp, levozp, blatc, dphiozc, olyr) + call getozn (prslk1, xlat, im, lmk, top_at_1, latsozc, levozc, blatc, dphiozc, olyr) endif ! end_if_ntoz !> - Call coszmn(), to compute cosine of zenith angle (only when SW is called) diff --git a/physics/GFS_rrtmg_pre.meta b/physics/GFS_rrtmg_pre.meta index 88363ef18..3b4d35c6d 100644 --- a/physics/GFS_rrtmg_pre.meta +++ b/physics/GFS_rrtmg_pre.meta @@ -1496,16 +1496,16 @@ dimensions = () type = integer intent = in -[latsozp] - standard_name = number_of_latitudes_in_ozone_data - long_name = number of latitude in ozone data +[latsozc] + standard_name = number_of_latitudes_in_ozone_climotology_data + long_name = number of latitude in ozone climotology data units = count dimensions = () type = integer intent = in -[levozp] - standard_name = number_of_levels_in_ozone_data - long_name = number of levels in ozone data +[levozc] + standard_name = number_of_levels_in_ozone_climotology_data + long_name = number of levels in ozone climotology data units = count dimensions = () type = integer diff --git a/physics/GFS_rrtmgp_pre.F90 b/physics/GFS_rrtmgp_pre.F90 index e9cbc3d23..dd72a6a1c 100644 --- a/physics/GFS_rrtmgp_pre.F90 +++ b/physics/GFS_rrtmgp_pre.F90 @@ -117,7 +117,7 @@ subroutine GFS_rrtmgp_pre_run(me, nCol, nLev, i_o3, doSWrad, doLWrad, fhswr, fhl vmr_n2o, vmr_co2, tsfg, tsfa, qs_lay, q_lay, tv_lay, & relhum, deltaZ, deltaZc, deltaP, active_gases_array, & tsfc_radtime, coszen, coszdg, top_at_1, iSFC, iTOA, nDay, idxday, semis, & - sfc_emiss_byband, ico2, latsozp, levozp, blatc, dphiozc, con_pi, errmsg, errflg) + sfc_emiss_byband, ico2, latsozc, levozc, blatc, dphiozc, con_pi, errmsg, errflg) ! Inputs integer, intent(in) :: & @@ -126,8 +126,8 @@ subroutine GFS_rrtmgp_pre_run(me, nCol, nLev, i_o3, doSWrad, doLWrad, fhswr, fhl nLev, & ! Number of vertical layers ico2, & ! Flag for co2 radiation scheme i_o3, & ! Index into tracer array for ozone - latsozp, & ! - levozp + latsozc, & ! + levozc logical, intent(in) :: & doSWrad, & ! Call SW radiation? doLWrad ! Call LW radiation @@ -354,7 +354,7 @@ subroutine GFS_rrtmgp_pre_run(me, nCol, nLev, i_o3, doSWrad, doLWrad, fhswr, fhl enddo ! OR Use climatological ozone data else - call getozn (prslk(1:NCOL,:), xlat, nCol, nLev, top_at_1, latsozp, levozp, blatc, & + call getozn (prslk(1:NCOL,:), xlat, nCol, nLev, top_at_1, latsozc, levozc, blatc, & dphiozc, o3_lay) endif diff --git a/physics/GFS_rrtmgp_pre.meta b/physics/GFS_rrtmgp_pre.meta index 47980b513..1a96eee1b 100644 --- a/physics/GFS_rrtmgp_pre.meta +++ b/physics/GFS_rrtmgp_pre.meta @@ -503,16 +503,16 @@ dimensions = (horizontal_loop_extent) type = integer intent = inout -[latsozp] - standard_name = number_of_latitudes_in_ozone_data - long_name = number of latitude in ozone data +[latsozc] + standard_name = number_of_latitudes_in_ozone_climotology_data + long_name = number of latitude in ozone climotology data units = count dimensions = () type = integer intent = in -[levozp] - standard_name = number_of_levels_in_ozone_data - long_name = number of levels in ozone data +[levozc] + standard_name = number_of_levels_in_ozone_climotology_data + long_name = number of levels in ozone climotology data units = count dimensions = () type = integer diff --git a/physics/ozphys_2015.F90 b/physics/ozphys_2015.F90 index 4e73a5262..fda87611c 100644 --- a/physics/ozphys_2015.F90 +++ b/physics/ozphys_2015.F90 @@ -3,7 +3,7 @@ !! ! ########################################################################################### module ozphys_2015 - use machine , only : kind_phys + use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec implicit none public ozphys_2015_init, ozphys_2015_timestep_init, ozphys_2015_run contains @@ -78,7 +78,7 @@ end subroutine ozphys_2015_init !! ! ########################################################################################### subroutine ozphys_2015_timestep_init(nPts, idate, fhour, jindx1, jindx2, latsozp, levozp, & - oz_coeff, timeoz, ozplin, oz_time, oz_pres, oz_lat, ddy, ozplout, errmsg, errflg) + oz_coeff, timeoz, ozplin, oz_time, oz_lat, ddy, ozplout, errmsg, errflg) ! Inputs integer, intent(in) :: & nPts, & ! Horizontal dimension @@ -95,7 +95,6 @@ subroutine ozphys_2015_timestep_init(nPts, idate, fhour, jindx1, jindx2, latsozp real(kind_phys), intent(in), dimension(:) :: & ddy, & ! Interpolation high index for ozone data oz_lat, & ! Latitudes for ozone data - oz_pres, & ! Levels for ozone data oz_time ! Time for ozone data real(kind_phys), intent(in), dimension(:,:,:,:) :: & ozplin ! Ozone data @@ -114,6 +113,8 @@ subroutine ozphys_2015_timestep_init(nPts, idate, fhour, jindx1, jindx2, latsozp real(kind_phys) :: tem, tx1, tx2, rjday real(8) :: rinc(5) real(4) :: rinc4(5) + !real(kind_dbl_prec) :: rinc(5) + !real(kind_sngl_prec) :: rinc4(5) ! Initialize CCPP error handling variables errmsg = '' diff --git a/physics/ozphys_2015.meta b/physics/ozphys_2015.meta index 59621b386..eab24baf1 100644 --- a/physics/ozphys_2015.meta +++ b/physics/ozphys_2015.meta @@ -166,14 +166,6 @@ type = real kind = kind_phys intent = in -[oz_pres] - standard_name = ozone_data_level_pressure - long_name = ozone data level pressure - units = Pa - dimensions = (number_of_levels_in_ozone_data) - type = real - kind = kind_phys - intent = in [oz_lat] standard_name = ozone_data_latitude long_name = ozone data latitude From 8188e26897b91083b315a0c8f83e32f54209c96d Mon Sep 17 00:00:00 2001 From: dustinswales Date: Tue, 1 Aug 2023 16:01:38 -0600 Subject: [PATCH 05/25] Split ozone physics into time_vary and run components --- physics/GFS_rrtmg_setup.meta | 12 +- physics/GFS_rrtmgp_setup.meta | 12 +- physics/ozphys_2015.F90 | 181 ++--------------------------- physics/ozphys_2015.meta | 205 +-------------------------------- physics/ozphys_time_vary.F90 | 177 +++++++++++++++++++++++++++++ physics/ozphys_time_vary.meta | 207 ++++++++++++++++++++++++++++++++++ 6 files changed, 406 insertions(+), 388 deletions(-) create mode 100644 physics/ozphys_time_vary.F90 create mode 100644 physics/ozphys_time_vary.meta diff --git a/physics/GFS_rrtmg_setup.meta b/physics/GFS_rrtmg_setup.meta index 42b999c82..f92d6f8db 100644 --- a/physics/GFS_rrtmg_setup.meta +++ b/physics/GFS_rrtmg_setup.meta @@ -174,22 +174,22 @@ type = integer intent = in [levozp] - standard_name = number_of_levels_in_ozone_data - long_name = number of levels in ozone data + standard_name = number_of_levels_in_ozone_climotology_data + long_name = number of levels in ozone climotology data units = count dimensions = () type = integer intent = in [timeozp] - standard_name = number_of_times_in_ozone_data - long_name = number of times in ozone data + standard_name = number_of_times_in_ozone_climotology_data + long_name = number of times in ozone climotology data units = count dimensions = () type = integer intent = in [latsozp] - standard_name = number_of_latitudes_in_ozone_data - long_name = number of latitude in ozone data + standard_name = number_of_latitudes_in_ozone_climotology_data + long_name = number of latitude in ozone climotology data units = count dimensions = () type = integer diff --git a/physics/GFS_rrtmgp_setup.meta b/physics/GFS_rrtmgp_setup.meta index 567294d4a..c8ed60650 100644 --- a/physics/GFS_rrtmgp_setup.meta +++ b/physics/GFS_rrtmgp_setup.meta @@ -267,22 +267,22 @@ type = integer intent = inout [levozp] - standard_name = number_of_levels_in_ozone_data - long_name = number of levels in ozone data + standard_name = number_of_levels_in_ozone_climotology_data + long_name = number of levels in ozone climotology data units = count dimensions = () type = integer intent = in [timeozp] - standard_name = number_of_times_in_ozone_data - long_name = number of times in ozone data + standard_name = number_of_times_in_ozone_climotology_data + long_name = number of times in ozone climotology data units = count dimensions = () type = integer intent = in [latsozp] - standard_name = number_of_latitudes_in_ozone_data - long_name = number of latitude in ozone data + standard_name = number_of_latitudes_in_ozone_climotology_data + long_name = number of latitude in ozone climotology data units = count dimensions = () type = integer diff --git a/physics/ozphys_2015.F90 b/physics/ozphys_2015.F90 index fda87611c..82ade0cbd 100644 --- a/physics/ozphys_2015.F90 +++ b/physics/ozphys_2015.F90 @@ -5,176 +5,13 @@ module ozphys_2015 use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec implicit none - public ozphys_2015_init, ozphys_2015_timestep_init, ozphys_2015_run + public ozphys_2015_run contains ! ########################################################################################### !>\defgroup GFS_ozphys_2015 GFS Ozone Photochemistry (2015) Module !! This module contains the CCPP-compliant Ozone 2015 photochemistry scheme. !> @{ -!> \section arg_table_ozphys_2015_init Argument Table -!! \htmlinclude ozphys_2015_init.html -!! -! ########################################################################################### - subroutine ozphys_2015_init(oz_phys_2015, nPts, latsozp, oz_lat, dlat, jindx1, jindx2, & - ddy, errmsg, errflg) - ! Inputs - logical, intent(in) :: & - oz_phys_2015 ! Control flag for NRL 2015 ozone physics scheme - integer, intent(in) :: & - nPts, & ! Horizontal dimension - latsozp ! Number of latitudes in ozone data - real(kind_phys), intent(in), dimension(:) :: & - oz_lat, & ! Latitudes of ozone data - dlat ! Latitudes of grid - ! Outputs - integer, intent(out), dimension(:) :: & - jindx1, & ! Interpolation index (low) for ozone data - jindx2 ! Interpolation index (high) for ozone data - real(kind_phys), intent(out), dimension(:) :: & - ddy ! Interpolation high index for ozone data - character(len=*), intent(out) :: & - errmsg ! CCPP error message - integer, intent(out) :: & - errflg ! CCPP error flag - - ! Local - integer i,j - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - ! Sanity check - if (.not.oz_phys_2015) then - write (errmsg,'(*(a))') 'Logic error: oz_phys_2015 == .false.' - errflg = 1 - return - endif - - ! Set indices - do j=1,nPts - jindx2(j) = latsozp + 1 - do i=1,latsozp - if (dlat(j) < oz_lat(i)) then - jindx2(j) = i - exit - endif - enddo - jindx1(j) = max(jindx2(j)-1,1) - jindx2(j) = min(jindx2(j),latsozp) - if (jindx2(j) .ne. jindx1(j)) then - ddy(j) = (dlat(j) - oz_lat(jindx1(j))) / (oz_lat(jindx2(j)) - oz_lat(jindx1(j))) - else - ddy(j) = 1.0 - endif - enddo - - end subroutine ozphys_2015_init - -! ########################################################################################### -!> \section arg_table_ozphys_2015_timestep_init Argument Table -!! \htmlinclude ozphys_2015_timestep_init.html -!! -! ########################################################################################### - subroutine ozphys_2015_timestep_init(nPts, idate, fhour, jindx1, jindx2, latsozp, levozp, & - oz_coeff, timeoz, ozplin, oz_time, oz_lat, ddy, ozplout, errmsg, errflg) - ! Inputs - integer, intent(in) :: & - nPts, & ! Horizontal dimension - latsozp, & ! Number of latitudes in ozone data - levozp, & ! Number of vertical layers in ozone data - oz_coeff, & ! Number of coefficients in ozone data - timeoz ! Number of times in ozone data - integer, intent(in),dimension(:) :: & - idate, & ! Initial date with different size and ordering - jindx1, & ! Interpolation index (low) for ozone - jindx2 ! Interpolation index (high) for ozone - real(kind_phys), intent(in) :: & - fhour ! Forecast hour - real(kind_phys), intent(in), dimension(:) :: & - ddy, & ! Interpolation high index for ozone data - oz_lat, & ! Latitudes for ozone data - oz_time ! Time for ozone data - real(kind_phys), intent(in), dimension(:,:,:,:) :: & - ozplin ! Ozone data - - ! Outputs - real(kind_phys), intent(out), dimension(:,:,:) :: & - ozplout ! Ozone forcing data - character(len=*), intent(out) :: & - errmsg ! CCPP error message - integer, intent(out) :: & - errflg ! CCPP error flag - - ! Local - integer :: idat(8),jdat(8),iday,j,j1,j2,l,nc,n1,n2,jdow,jdoy,& - jday,w3kindreal,w3kindint - real(kind_phys) :: tem, tx1, tx2, rjday - real(8) :: rinc(5) - real(4) :: rinc4(5) - !real(kind_dbl_prec) :: rinc(5) - !real(kind_sngl_prec) :: rinc4(5) - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - ! - idat=0 - idat(1)=idate(4) - idat(2)=idate(2) - idat(3)=idate(3) - idat(5)=idate(1) - rinc=0. - rinc(2)=fhour - call w3kind(w3kindreal,w3kindint) - if(w3kindreal==4) then - rinc4=rinc - CALL w3movdat(rinc4,idat,jdat) - else - CALL w3movdat(rinc,idat,jdat) - endif - ! - jdow = 0 - jdoy = 0 - jday = 0 - call w3doxdat(jdat,jdow,jdoy,jday) - rjday = jdoy + jdat(5) / 24. - IF (RJDAY < oz_time(1)) RJDAY = RJDAY + 365. - ! - n2 = timeoz + 1 - do j=2,timeoz - if (rjday < oz_time(j)) then - n2 = j - exit - endif - enddo - n1 = n2 - 1 - - tx1 = (oz_time(n2) - rjday) / (oz_time(n2) - oz_time(n1)) - tx2 = 1.0 - tx1 - - if (n2 > timeoz) n2 = n2 - timeoz - ! - do nc=1,oz_coeff - do L=1,levozp - do J=1,npts - J1 = jindx1(J) - J2 = jindx2(J) - TEM = 1.0 - ddy(J) - ozplout(j,L,nc) = tx1*(TEM*ozplin(J1,L,nc,n1)+ddy(J)*ozplin(J2,L,nc,n1)) & - + tx2*(TEM*ozplin(J1,L,nc,n2)+ddy(J)*ozplin(J2,L,nc,n2)) - enddo - enddo - enddo - - ! - return - - end subroutine ozphys_2015_timestep_init - -! ########################################################################################### !> The operational GFS currently parameterizes ozone production and !! destruction based on monthly mean coefficients ( !! \c ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77) provided by Naval @@ -187,11 +24,11 @@ end subroutine ozphys_2015_timestep_init !> - This code assumes that both prsl and po3 are from bottom to top !! as are all other variables. !> - This code is specifically for NRL parameterization and -!! climatological T and O3 are in location 5 and 6 of prdout array -!!\author June 2015 - Shrinivas Moorthi -!!\author May 2023 - Dustin Swales +!! climatological T and O3 are in location 5 and 6 of oz_data array +!!\author June 2015 - Shrinivas Moorthi +!!\modified May 2023 - Dustin Swales ! ########################################################################################### - subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, prdout, pl_coeff, & + subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, oz_data, pl_coeff, & delp, ldiag3d, dtend, dtidx, ntoz, index_of_process_prod_loss, & index_of_process_ozmix, index_of_process_temp, index_of_process_overhead_ozone, & con_g, errmsg, errflg) @@ -222,7 +59,7 @@ subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, prdout, pl_c tin, & ! Temperature of new-state (K) delp ! Difference between mid-layer pressures (Pa) real(kind_phys), intent(in), dimension(:,:,:) :: & - prdout ! Ozone forcing data + oz_data ! Ozone forcing data ! In/Outs real(kind=kind_phys), intent(inout), dimension(:,:,:) :: & @@ -298,7 +135,7 @@ subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, prdout, pl_c do j=1,pl_coeff do i=1,im if (flg(i)) then - prod(i,j) = wk2(i) * prdout(i,k,j) + wk3(i) * prdout(i,k+1,j) + prod(i,j) = wk2(i) * oz_data(i,k,j) + wk3(i) * oz_data(i,k+1,j) endif enddo enddo @@ -307,10 +144,10 @@ subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, prdout, pl_c do j=1,pl_coeff do i=1,im if (wk1(i) < po3(ko3)) then - prod(i,j) = prdout(i,ko3,j) + prod(i,j) = oz_data(i,ko3,j) endif if (wk1(i) >= po3(1)) then - prod(i,j) = prdout(i,1,j) + prod(i,j) = oz_data(i,1,j) endif enddo enddo diff --git a/physics/ozphys_2015.meta b/physics/ozphys_2015.meta index eab24baf1..ea82defaa 100644 --- a/physics/ozphys_2015.meta +++ b/physics/ozphys_2015.meta @@ -3,209 +3,6 @@ type = scheme dependencies = machine.F -######################################################################## -[ccpp-arg-table] - name = ozphys_2015_init - type = scheme -[nPts] - standard_name = horizontal_dimension - long_name = horizontal dimension - units = count - dimensions = () - type = integer - intent = in -[latsozp] - standard_name = number_of_latitudes_in_ozone_data - long_name = number of latitude in ozone data - units = count - dimensions = () - type = integer - intent = in -[oz_phys_2015] - standard_name = flag_for_nrl_2015_ozone_scheme - long_name = flag for new (2015) ozone physics - units = flag - dimensions = () - type = logical - intent = in -[oz_lat] - standard_name = ozone_data_latitude - long_name = ozone data latitude - units = deg - dimensions = (number_of_latitudes_in_ozone_data) - type = real - kind = kind_phys - intent = in -[dlat] - standard_name = latitude_in_degree - long_name = latitude in degree north - units = degree_north - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = in -[jindx1] - standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation low index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = out -[jindx2] - standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation high index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = out -[ddy] - standard_name = latitude_interpolation_weight_for_ozone_forcing - long_name = interpolation high index for ozone - units = none - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = out -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - -######################################################################## -[ccpp-arg-table] - name = ozphys_2015_timestep_init - type = scheme -[nPts] - standard_name = horizontal_dimension - long_name = horizontal dimension - units = count - dimensions = () - type = integer - intent = in -[idate] - standard_name = date_and_time_at_model_initialization_in_united_states_order - long_name = initial date with different size and ordering - units = none - dimensions = (4) - type = integer - intent = in -[fhour] - standard_name = forecast_time - long_name = current forecast time - units = h - dimensions = () - type = real - kind = kind_phys - intent = in -[jindx1] - standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation low index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[jindx2] - standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation high index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[latsozp] - standard_name = number_of_latitudes_in_ozone_data - long_name = number of latitude in ozone data - units = count - dimensions = () - type = integer - intent = in -[levozp] - standard_name = number_of_levels_in_ozone_data - long_name = number of levels in ozone data - units = count - dimensions = () - type = integer - intent = in -[oz_coeff] - standard_name = number_of_coefficients_in_ozone_data - long_name = number of coefficients in ozone data - units = count - dimensions = () - type = integer - intent = in -[timeoz] - standard_name = number_of_times_in_ozone_data - long_name = number of times in ozone data - units = count - dimensions = () - type = integer - intent = in -[ozplin] - standard_name = ozone_data - long_name = ozone data - units = 1 - dimensions = (number_of_latitudes_in_ozone_data,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data,number_of_times_in_ozone_data) - type = real - kind = kind_phys - intent = in -[oz_time] - standard_name = ozone_data_time - long_name = ozone data time - units = none - dimensions = (13) - type = real - kind = kind_phys - intent = in -[oz_lat] - standard_name = ozone_data_latitude - long_name = ozone data latitude - units = deg - dimensions = (number_of_latitudes_in_ozone_data) - type = real - kind = kind_phys - intent = in -[ddy] - standard_name = latitude_interpolation_weight_for_ozone_forcing - long_name = interpolation high index for ozone - units = none - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = in -[ozplout] - standard_name = ozone_forcing - long_name = ozone forcing data - units = mixed - dimensions = (horizontal_dimension,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) - type = real - kind = kind_phys - intent = out -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - ######################################################################## [ccpp-arg-table] name = ozphys_2015_run @@ -271,7 +68,7 @@ type = real kind = kind_phys intent = in -[prdout] +[oz_data] standard_name = ozone_forcing long_name = ozone forcing data units = mixed diff --git a/physics/ozphys_time_vary.F90 b/physics/ozphys_time_vary.F90 new file mode 100644 index 000000000..5b36f88b9 --- /dev/null +++ b/physics/ozphys_time_vary.F90 @@ -0,0 +1,177 @@ +! ########################################################################################### +!> \file ozphys_time_vary.F90 +!! +! ########################################################################################### +module ozphys_time_vary + use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec + implicit none + public ozphys_time_vary_init, ozphys_time_vary_timestep_init +contains + +! ########################################################################################### +!>\defgroup GFS Ozone Photochemistry (2015) Module +!! This module contains the CCPP-compliant Ozone 2015 photochemistry scheme. +!> @{ +!> \section arg_table_ozphys_time_vary_init Argument Table +!! \htmlinclude ozphys_time_vary_init.html +!! +! ########################################################################################### + subroutine ozphys_time_vary_init(oz_phys, nPts, latsozp, oz_lat, dlat, jindx1, jindx2, & + ddy, errmsg, errflg) + ! Inputs + logical, intent(in) :: & + oz_phys ! Control flag for NRL ozone scheme + integer, intent(in) :: & + nPts, & ! Horizontal dimension + latsozp ! Number of latitudes in ozone data + real(kind_phys), intent(in), dimension(:) :: & + oz_lat, & ! Latitudes of ozone data + dlat ! Latitudes of grid + ! Outputs + integer, intent(inout), dimension(:) :: & + jindx1, & ! Interpolation index (low) for ozone data + jindx2 ! Interpolation index (high) for ozone data + real(kind_phys), intent(inout), dimension(:) :: & + ddy ! Interpolation high index for ozone data + character(len=*), intent(out) :: & + errmsg ! CCPP error message + integer, intent(out) :: & + errflg ! CCPP error flag + + ! Local + integer i,j + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + ! Sanity check + if (.not.oz_phys) then + write (errmsg,'(*(a))') 'Logic error: oz_phys == .false.' + errflg = 1 + return + endif + + ! Set indices + do j=1,nPts + jindx2(j) = latsozp + 1 + do i=1,latsozp + if (dlat(j) < oz_lat(i)) then + jindx2(j) = i + exit + endif + enddo + jindx1(j) = max(jindx2(j)-1,1) + jindx2(j) = min(jindx2(j),latsozp) + if (jindx2(j) .ne. jindx1(j)) then + ddy(j) = (dlat(j) - oz_lat(jindx1(j))) / (oz_lat(jindx2(j)) - oz_lat(jindx1(j))) + else + ddy(j) = 1.0 + endif + enddo + + end subroutine ozphys_time_vary_init + +! ########################################################################################### +!> \section arg_table_ozphys_time_vary_timestep_init Argument Table +!! \htmlinclude ozphys_time_vary_timestep_init.html +!! +! ########################################################################################### + subroutine ozphys_time_vary_timestep_init(nPts, idate, fhour, jindx1, jindx2, latsozp, & + levozp, oz_coeff, timeoz, ozplin, oz_time, oz_lat, ddy, oz_data, errmsg, errflg) + ! Inputs + integer, intent(in) :: & + nPts, & ! Horizontal dimension + latsozp, & ! Number of latitudes in ozone data + levozp, & ! Number of vertical layers in ozone data + oz_coeff, & ! Number of coefficients in ozone data + timeoz ! Number of times in ozone data + integer, intent(in),dimension(:) :: & + idate, & ! Initial date with different size and ordering + jindx1, & ! Interpolation index (low) for ozone + jindx2 ! Interpolation index (high) for ozone + real(kind_phys), intent(in) :: & + fhour ! Forecast hour + real(kind_phys), intent(in), dimension(:) :: & + ddy, & ! Interpolation high index for ozone data + oz_lat, & ! Latitudes for ozone data + oz_time ! Time for ozone data + real(kind_phys), intent(in), dimension(:,:,:,:) :: & + ozplin ! Ozone data + + ! Outputs + real(kind_phys), intent(inout), dimension(:,:,:) :: & + oz_data ! Ozone forcing data + character(len=*), intent(out) :: & + errmsg ! CCPP error message + integer, intent(out) :: & + errflg ! CCPP error flag + + ! Local + integer :: idat(8),jdat(8),iday,j,j1,j2,l,nc,n1,n2,jdow,jdoy,& + jday,w3kindreal,w3kindint + real(kind_phys) :: tem, tx1, tx2, rjday + real(8) :: rinc(5) + real(4) :: rinc4(5) + !real(kind_dbl_prec) :: rinc(5) + !real(kind_sngl_prec) :: rinc4(5) + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + ! + idat=0 + idat(1)=idate(4) + idat(2)=idate(2) + idat(3)=idate(3) + idat(5)=idate(1) + rinc=0. + rinc(2)=fhour + call w3kind(w3kindreal,w3kindint) + if(w3kindreal==4) then + rinc4=rinc + CALL w3movdat(rinc4,idat,jdat) + else + CALL w3movdat(rinc,idat,jdat) + endif + ! + jdow = 0 + jdoy = 0 + jday = 0 + call w3doxdat(jdat,jdow,jdoy,jday) + rjday = jdoy + jdat(5) / 24. + IF (RJDAY < oz_time(1)) RJDAY = RJDAY + 365. + ! + n2 = timeoz + 1 + do j=2,timeoz + if (rjday < oz_time(j)) then + n2 = j + exit + endif + enddo + n1 = n2 - 1 + + tx1 = (oz_time(n2) - rjday) / (oz_time(n2) - oz_time(n1)) + tx2 = 1.0 - tx1 + + if (n2 > timeoz) n2 = n2 - timeoz + ! + do nc=1,oz_coeff + do L=1,levozp + do J=1,npts + J1 = jindx1(J) + J2 = jindx2(J) + TEM = 1.0 - ddy(J) + oz_data(j,L,nc) = tx1*(TEM*ozplin(J1,L,nc,n1)+ddy(J)*ozplin(J2,L,nc,n1)) & + + tx2*(TEM*ozplin(J1,L,nc,n2)+ddy(J)*ozplin(J2,L,nc,n2)) + enddo + enddo + enddo + + ! + return + + end subroutine ozphys_time_vary_timestep_init +!> @} +end module ozphys_time_vary diff --git a/physics/ozphys_time_vary.meta b/physics/ozphys_time_vary.meta new file mode 100644 index 000000000..93aa4a3b0 --- /dev/null +++ b/physics/ozphys_time_vary.meta @@ -0,0 +1,207 @@ +[ccpp-table-properties] + name = ozphys_time_vary + type = scheme + dependencies = machine.F + +######################################################################## +[ccpp-arg-table] + name = ozphys_time_vary_init + type = scheme +[nPts] + standard_name = horizontal_dimension + long_name = horizontal dimension + units = count + dimensions = () + type = integer + intent = in +[latsozp] + standard_name = number_of_latitudes_in_ozone_data + long_name = number of latitude in ozone data + units = count + dimensions = () + type = integer + intent = in +[oz_phys] + standard_name = flag_for_nrl_2015_ozone_scheme + long_name = flag for new (2015) ozone physics + units = flag + dimensions = () + type = logical + intent = in +[oz_lat] + standard_name = ozone_data_latitude + long_name = ozone data latitude + units = deg + dimensions = (number_of_latitudes_in_ozone_data) + type = real + kind = kind_phys + intent = in +[dlat] + standard_name = latitude_in_degree + long_name = latitude in degree north + units = degree_north + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = in +[jindx1] + standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation low index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = inout +[jindx2] + standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation high index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = inout +[ddy] + standard_name = latitude_interpolation_weight_for_ozone_forcing + long_name = interpolation high index for ozone + units = none + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = inout +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = ozphys_time_vary_timestep_init + type = scheme +[nPts] + standard_name = horizontal_dimension + long_name = horizontal dimension + units = count + dimensions = () + type = integer + intent = in +[idate] + standard_name = date_and_time_at_model_initialization_in_united_states_order + long_name = initial date with different size and ordering + units = none + dimensions = (4) + type = integer + intent = in +[fhour] + standard_name = forecast_time + long_name = current forecast time + units = h + dimensions = () + type = real + kind = kind_phys + intent = in +[jindx1] + standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation low index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[jindx2] + standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation high index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[latsozp] + standard_name = number_of_latitudes_in_ozone_data + long_name = number of latitude in ozone data + units = count + dimensions = () + type = integer + intent = in +[levozp] + standard_name = number_of_levels_in_ozone_data + long_name = number of levels in ozone data + units = count + dimensions = () + type = integer + intent = in +[oz_coeff] + standard_name = number_of_coefficients_in_ozone_data + long_name = number of coefficients in ozone data + units = count + dimensions = () + type = integer + intent = in +[timeoz] + standard_name = number_of_times_in_ozone_data + long_name = number of times in ozone data + units = count + dimensions = () + type = integer + intent = in +[ozplin] + standard_name = ozone_data + long_name = ozone data + units = 1 + dimensions = (number_of_latitudes_in_ozone_data,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data,number_of_times_in_ozone_data) + type = real + kind = kind_phys + intent = in +[oz_time] + standard_name = ozone_data_time + long_name = ozone data time + units = none + dimensions = (13) + type = real + kind = kind_phys + intent = in +[oz_lat] + standard_name = ozone_data_latitude + long_name = ozone data latitude + units = deg + dimensions = (number_of_latitudes_in_ozone_data) + type = real + kind = kind_phys + intent = in +[ddy] + standard_name = latitude_interpolation_weight_for_ozone_forcing + long_name = interpolation high index for ozone + units = none + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = in +[oz_data] + standard_name = ozone_forcing + long_name = ozone forcing data + units = mixed + dimensions = (horizontal_dimension,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) + type = real + kind = kind_phys + intent = inout +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out From 0bfac2ac51d8c460b84cc49fd5240407bcaea6ba Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Wed, 2 Aug 2023 17:03:36 +0000 Subject: [PATCH 06/25] Some cleanup. Now working --- physics/GFS_rrtmg_pre.F90 | 2 +- physics/ozphys_2015.F90 | 52 +++++++++++++++++++++++++++++++---- physics/ozphys_2015.meta | 34 +++++++++++++++++++++++ physics/ozphys_time_vary.F90 | 22 ++++----------- physics/ozphys_time_vary.meta | 7 ----- 5 files changed, 87 insertions(+), 30 deletions(-) diff --git a/physics/GFS_rrtmg_pre.F90 b/physics/GFS_rrtmg_pre.F90 index 4a2c3b290..f2183919f 100644 --- a/physics/GFS_rrtmg_pre.F90 +++ b/physics/GFS_rrtmg_pre.F90 @@ -44,7 +44,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& gasvmr_o2, gasvmr_co, gasvmr_cfc11, gasvmr_cfc12, gasvmr_cfc22, & gasvmr_ccl4, gasvmr_cfc113, aerodp,ext550, clouds6, clouds7, clouds8, & clouds9, cldsa, cldfra, cldfra2d, lwp_ex,iwp_ex, lwp_fc,iwp_fc, & - faersw1, faersw2, faersw3, faerlw1, faerlw2, faerlw3, alpha, rrfs_sd & + faersw1, faersw2, faersw3, faerlw1, faerlw2, faerlw3, alpha, rrfs_sd, & aero_dir_fdb, fdb_coef, spp_wts_rad, spp_rad, ico2, latsozc, levozc, & blatc, dphiozc, errmsg, errflg) diff --git a/physics/ozphys_2015.F90 b/physics/ozphys_2015.F90 index 82ade0cbd..110ba02e2 100644 --- a/physics/ozphys_2015.F90 +++ b/physics/ozphys_2015.F90 @@ -5,7 +5,7 @@ module ozphys_2015 use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec implicit none - public ozphys_2015_run + public ozphys_2015_init, ozphys_2015_run contains ! ########################################################################################### @@ -17,8 +17,6 @@ module ozphys_2015 !! \c ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77) provided by Naval !! Research Laboratory through CHEM2D chemistry model !! (McCormack et al. (2006) \cite mccormack_et_al_2006). -!! \section arg_table_ozphys_2015_run Argument Table -!! \htmlinclude ozphys_2015_run.html !! !> \section genal_ozphys_2015 GFS ozphys_2015_run General Algorithm !> - This code assumes that both prsl and po3 are from bottom to top @@ -28,13 +26,50 @@ module ozphys_2015 !!\author June 2015 - Shrinivas Moorthi !!\modified May 2023 - Dustin Swales ! ########################################################################################### - subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, oz_data, pl_coeff, & - delp, ldiag3d, dtend, dtidx, ntoz, index_of_process_prod_loss, & + +! ########################################################################################### +! SUBROUTINE ozphys_2015_init +! ########################################################################################### +!! \section arg_table_ozphys_2015_init Argument Table +!! \htmlinclude ozphys_2015_init.html +!! + subroutine ozphys_2015_init(oz_phys, errmsg, errflg) + ! Inputs + logical, intent(in) :: & + oz_phys + ! Outputs + character(len=*), intent(out) :: & + errmsg + integer, intent(out) :: & + errflg + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + ! Sanity check + if (.not.oz_phys) then + write (errmsg,'(*(a))') 'Logic error: oz_phys_2015 == .false.' + errflg = 1 + return + endif + + end subroutine ozphys_2015_init + +! ########################################################################################### +! SUBROUTINE ozphys_2015_run +! ########################################################################################### +!! \section arg_table_ozphys_2015_run Argument Table +!! \htmlinclude ozphys_2015_run.html +!! + subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_data, & + pl_coeff, delp, ldiag3d, dtend, dtidx, ntoz, index_of_process_prod_loss, & index_of_process_ozmix, index_of_process_temp, index_of_process_overhead_ozone, & con_g, errmsg, errflg) ! Inputs logical, intent(in) :: & + oz_phys, & ! ldiag3d ! Flag to output GFS diagnostic tendencies real(kind_phys),intent(in) :: & con_g ! Physical constant: Gravitational acceleration (ms-2) @@ -88,6 +123,13 @@ subroutine ozphys_2015_run ( im, levs, ko3, dt, oz, tin, po3, prsl, oz_data, pl_ errmsg = '' errflg = 0 + ! Sanity checkt + if (.not.oz_phys) then + write (errmsg,'(*(a))') 'Logic error: oz_phys_2015 == .false.' + errflg = 1 + return + endif + ! Are UFS diagnostic tendencies requested? If so, set up bookeeping indices... if(ldiag3d) then idtend(1) = dtidx(100+ntoz,index_of_process_prod_loss) ! was ozp1 diff --git a/physics/ozphys_2015.meta b/physics/ozphys_2015.meta index ea82defaa..4b19f2c04 100644 --- a/physics/ozphys_2015.meta +++ b/physics/ozphys_2015.meta @@ -3,10 +3,44 @@ type = scheme dependencies = machine.F +######################################################################## +[ccpp-arg-table] + name = ozphys_2015_init + type = scheme +[oz_phys] + standard_name = flag_for_nrl_2015_ozone_scheme + long_name = flag for new (2015) ozone physics + units = flag + dimensions = () + type = logical + intent = in +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + ######################################################################## [ccpp-arg-table] name = ozphys_2015_run type = scheme +[oz_phys] + standard_name = flag_for_nrl_2015_ozone_scheme + long_name = flag for new (2015) ozone physics + units = flag + dimensions = () + type = logical + intent = in [im] standard_name = horizontal_loop_extent long_name = horizontal loop extent diff --git a/physics/ozphys_time_vary.F90 b/physics/ozphys_time_vary.F90 index 5b36f88b9..a0a778c36 100644 --- a/physics/ozphys_time_vary.F90 +++ b/physics/ozphys_time_vary.F90 @@ -9,18 +9,16 @@ module ozphys_time_vary contains ! ########################################################################################### -!>\defgroup GFS Ozone Photochemistry (2015) Module -!! This module contains the CCPP-compliant Ozone 2015 photochemistry scheme. +!>\defgroup GFS Ozone Data Module +!! This module updates the ozone data used by physics. !> @{ !> \section arg_table_ozphys_time_vary_init Argument Table !! \htmlinclude ozphys_time_vary_init.html !! ! ########################################################################################### - subroutine ozphys_time_vary_init(oz_phys, nPts, latsozp, oz_lat, dlat, jindx1, jindx2, & + subroutine ozphys_time_vary_init(nPts, latsozp, oz_lat, dlat, jindx1, jindx2, & ddy, errmsg, errflg) ! Inputs - logical, intent(in) :: & - oz_phys ! Control flag for NRL ozone scheme integer, intent(in) :: & nPts, & ! Horizontal dimension latsozp ! Number of latitudes in ozone data @@ -44,13 +42,6 @@ subroutine ozphys_time_vary_init(oz_phys, nPts, latsozp, oz_lat, dlat, jindx1, j ! Initialize CCPP error handling variables errmsg = '' errflg = 0 - - ! Sanity check - if (.not.oz_phys) then - write (errmsg,'(*(a))') 'Logic error: oz_phys == .false.' - errflg = 1 - return - endif ! Set indices do j=1,nPts @@ -111,10 +102,8 @@ subroutine ozphys_time_vary_timestep_init(nPts, idate, fhour, jindx1, jindx2, la integer :: idat(8),jdat(8),iday,j,j1,j2,l,nc,n1,n2,jdow,jdoy,& jday,w3kindreal,w3kindint real(kind_phys) :: tem, tx1, tx2, rjday - real(8) :: rinc(5) - real(4) :: rinc4(5) - !real(kind_dbl_prec) :: rinc(5) - !real(kind_sngl_prec) :: rinc4(5) + real(kind_dbl_prec) :: rinc(5) + real(kind_sngl_prec) :: rinc4(5) ! Initialize CCPP error handling variables errmsg = '' @@ -169,7 +158,6 @@ subroutine ozphys_time_vary_timestep_init(nPts, idate, fhour, jindx1, jindx2, la enddo enddo - ! return end subroutine ozphys_time_vary_timestep_init diff --git a/physics/ozphys_time_vary.meta b/physics/ozphys_time_vary.meta index 93aa4a3b0..75b8b8e4f 100644 --- a/physics/ozphys_time_vary.meta +++ b/physics/ozphys_time_vary.meta @@ -21,13 +21,6 @@ dimensions = () type = integer intent = in -[oz_phys] - standard_name = flag_for_nrl_2015_ozone_scheme - long_name = flag for new (2015) ozone physics - units = flag - dimensions = () - type = logical - intent = in [oz_lat] standard_name = ozone_data_latitude long_name = ozone data latitude From bea77c8dd21b60b8af7603e494aed45abcccec40 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Thu, 10 Aug 2023 17:32:59 +0000 Subject: [PATCH 07/25] More reorganization. --- physics/GFS_physics_diagnostics.F90 | 97 +++++++++++++++++++ physics/GFS_physics_diagnostics.meta | 140 +++++++++++++++++++++++++++ physics/ozphys_2015.F90 | 80 ++++++--------- physics/ozphys_2015.meta | 91 +++++++---------- physics/ozphys_time_vary.F90 | 4 +- physics/physcons.F90 | 1 + 6 files changed, 300 insertions(+), 113 deletions(-) create mode 100644 physics/GFS_physics_diagnostics.F90 create mode 100644 physics/GFS_physics_diagnostics.meta diff --git a/physics/GFS_physics_diagnostics.F90 b/physics/GFS_physics_diagnostics.F90 new file mode 100644 index 000000000..0c6197bc2 --- /dev/null +++ b/physics/GFS_physics_diagnostics.F90 @@ -0,0 +1,97 @@ +! ########################################################################################### +!> \file GFS_physics_diagnostics.F90 +!! +! ########################################################################################### +module GFS_physics_diagnostics + use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec + implicit none + public GFS_physics_diagnostics_init, GFS_physics_diagnostics_run +contains + +! ########################################################################################### +! SUBROUTINE GFS_physics_diagnostics_init +! ########################################################################################### +!! \section arg_table_GFS_physics_diagnostics_init Argument Table +!! \htmlinclude GFS_physics_diagnostics_init.html +!! + subroutine GFS_physics_diagnostics_init(errmsg, errflg) + + ! Outputs + character(len=*), intent(out) :: & + errmsg ! CCPP error message + integer, intent(out) :: & + errflg ! CCPP error flag + + end subroutine GFS_physics_diagnostics_init + +! ########################################################################################### +! SUBROUTINE GFS_physics_diagnostics_run +! ########################################################################################### +!! \section arg_table_GFS_physics_diagnostics_run Argument Table +!! \htmlinclude GFS_physics_diagnostics_run.html +!! + subroutine GFS_physics_diagnostics_run(nCol, nLev, ntoz, dtidx, ip_prod_loss, ip_ozmix, & + ip_temp, ip_overhead_ozone, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, dtend,& + errmsg, errflg) + ! Inputs + integer, intent(in) :: & + nCol, & ! Horizontal dimension + nLev, & ! Number of vertical layers + ntoz, & ! Index for ozone mixing ratio + ip_prod_loss, & ! Index for process in diagnostic tendency output + ip_ozmix, & ! Index for process in diagnostic tendency output + ip_temp, & ! Index for process in diagnostic tendency output + ip_overhead_ozone ! Index for process in diagnostic tendency output + integer, intent(in), dimension(:,:) :: & + dtidx ! Bookkeeping indices for GFS diagnostic tendencies + + ! Inputs (optional) + real(kind=kind_phys), intent(in), dimension(:,:), pointer, optional :: & + do3_dt_prd, & ! Physics tendency: production and loss effect + do3_dt_ozmx, & ! Physics tendency: ozone mixing ratio effect + do3_dt_temp, & ! Physics tendency: temperature effect + do3_dt_ohoz ! Physics tendency: overhead ozone effect + + ! Outputs + real(kind=kind_phys), intent(inout), dimension(:,:,:) :: & + dtend ! Diagnostic tendencies for state variables + character(len=*), intent(out) :: & + errmsg ! CCPP error message + integer, intent(out) :: & + errflg ! CCPP error flag + + ! Locals + integer :: idtend + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + ! ####################################################################################### + ! + ! Ozone physics diagnostics + ! + ! ####################################################################################### + idtend = dtidx(100+ntoz,ip_prod_loss) + if (idtend >= 1 .and. associated(do3_dt_prd)) then + dtend(:,:,idtend) = dtend(:,:,idtend) + do3_dt_prd + endif + ! + idtend = dtidx(100+ntoz,ip_ozmix) + if (idtend >= 1 .and. associated(do3_dt_ozmx)) then + dtend(:,:,idtend) = dtend(:,:,idtend) + do3_dt_ozmx + endif + ! + idtend = dtidx(100+ntoz,ip_temp) + if (idtend >= 1 .and. associated(do3_dt_temp)) then + dtend(:,:,idtend) = dtend(:,:,idtend) + do3_dt_temp + endif + ! + idtend = dtidx(100+ntoz,ip_overhead_ozone) + if (idtend >= 1 .and. associated(do3_dt_ohoz)) then + dtend(:,:,idtend) = dtend(:,:,idtend) + do3_dt_ohoz + endif + + end subroutine GFS_physics_diagnostics_run + +end module GFS_physics_diagnostics diff --git a/physics/GFS_physics_diagnostics.meta b/physics/GFS_physics_diagnostics.meta new file mode 100644 index 000000000..b6036b0c9 --- /dev/null +++ b/physics/GFS_physics_diagnostics.meta @@ -0,0 +1,140 @@ +[ccpp-table-properties] + name = GFS_physics_diagnostics + type = scheme + dependencies = machine.F + +######################################################################## +[ccpp-arg-table] + name = GFS_physics_diagnostics_init + type = scheme +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out + +######################################################################## +[ccpp-arg-table] + name = GFS_physics_diagnostics_run + type = scheme +[nCol] + standard_name = horizontal_loop_extent + long_name = horizontal loop extent + units = count + dimensions = () + type = integer + intent = in +[nLev] + standard_name = vertical_layer_dimension + long_name = number of vertical layers + units = count + dimensions = () + type = integer + intent = in +[dtend] + standard_name = cumulative_change_of_state_variables + long_name = diagnostic tendencies for state variables + units = mixed + dimensions = (horizontal_loop_extent,vertical_layer_dimension,cumulative_change_of_state_variables_outer_index_max) + type = real + kind = kind_phys + intent = inout +[dtidx] + standard_name = cumulative_change_of_state_variables_outer_index + long_name = index of state-variable and process in last dimension of diagnostic tendencies array AKA cumulative_change_index + units = index + dimensions = (number_of_tracers_plus_one_hundred,number_of_cumulative_change_processes) + type = integer + intent = in +[ntoz] + standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array + long_name = tracer index for ozone mixing ratio + units = index + dimensions = () + type = integer + intent = in +[ip_prod_loss] + standard_name = index_of_production_and_loss_process_in_cumulative_change_index + long_name = index of production and loss effect in photochemistry process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer + intent = in +[ip_ozmix] + standard_name = index_of_ozone_mixing_ratio_process_in_cumulative_change_index + long_name = index of ozone mixing ratio effect in photochemistry process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer + intent = in +[ip_temp] + standard_name = index_of_temperature_process_in_cumulative_change_index + long_name = index of temperature effect in photochemistry process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer + intent = in +[ip_overhead_ozone] + standard_name = index_of_overhead_process_in_cumulative_change_index + long_name = index of overhead ozone effect in photochemistry process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer + intent = in +[do3_dt_prd] + standard_name = ozone_tendency_due_to_production_and_loss_rate + long_name = ozone tendency due to production and loss rate + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[do3_dt_ozmx] + standard_name = ozone_tendency_due_to_ozone_mixing_ratio + long_name = ozone tendency due to ozone mixing ratio + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[do3_dt_temp] + standard_name = ozone_tendency_due_to_temperature + long_name = ozone tendency due to temperature + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[do3_dt_ohoz] + standard_name = ozone_tendency_due_to_overhead_ozone_column + long_name = ozone tendency due to overhead ozone column + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[errmsg] + standard_name = ccpp_error_message + long_name = error message for error handling in CCPP + units = none + dimensions = () + type = character + kind = len=* + intent = out +[errflg] + standard_name = ccpp_error_code + long_name = error code for error handling in CCPP + units = 1 + dimensions = () + type = integer + intent = out \ No newline at end of file diff --git a/physics/ozphys_2015.F90 b/physics/ozphys_2015.F90 index 110ba02e2..9898c71e4 100644 --- a/physics/ozphys_2015.F90 +++ b/physics/ozphys_2015.F90 @@ -63,42 +63,35 @@ end subroutine ozphys_2015_init !! \htmlinclude ozphys_2015_run.html !! subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_data, & - pl_coeff, delp, ldiag3d, dtend, dtidx, ntoz, index_of_process_prod_loss, & - index_of_process_ozmix, index_of_process_temp, index_of_process_overhead_ozone, & - con_g, errmsg, errflg) + pl_coeff, delp, con_1ovg, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, errmsg, errflg) ! Inputs logical, intent(in) :: & - oz_phys, & ! - ldiag3d ! Flag to output GFS diagnostic tendencies + oz_phys ! Flag for ozone_physics_2015 scheme. real(kind_phys),intent(in) :: & - con_g ! Physical constant: Gravitational acceleration (ms-2) + con_1ovg ! Physical constant: One divided by gravitational acceleration (m-1 s2) integer, intent(in) :: & - im, & ! Horizontal dimension - levs, & ! Number of vertical layers - ko3, & ! Number of vertical layers in ozone forcing data - pl_coeff, & ! Number of coefficients in ozone forcing data - ntoz, & ! Index for ozone mixing ratio - index_of_process_prod_loss, & ! Index for process in diagnostic tendency output - index_of_process_ozmix, & ! Index for process in diagnostic tendency output - index_of_process_temp, & ! Index for process in diagnostic tendency output - index_of_process_overhead_ozone ! Index for process in diagnostic tendency output - integer, intent(in), dimension(:,:) :: & - dtidx ! Bookkeeping indices for GFS diagnostic tendencies + im, & ! Horizontal dimension + levs, & ! Number of vertical layers + ko3, & ! Number of vertical layers in ozone forcing data + pl_coeff ! Number of coefficients in ozone forcing data real(kind_phys), intent(in) :: & - dt ! Physics timestep (seconds) + dt ! Physics timestep (seconds) real(kind_phys), intent(in), dimension(:) :: & - po3 ! Natural log of ozone forcing data pressure levels + po3 ! Natural log of ozone forcing data pressure levels real(kind_phys), intent(in), dimension(:,:) :: & - prsl, & ! Air-pressure (Pa) - tin, & ! Temperature of new-state (K) - delp ! Difference between mid-layer pressures (Pa) + prsl, & ! Air-pressure (Pa) + tin, & ! Temperature of new-state (K) + delp ! Difference between mid-layer pressures (Pa) real(kind_phys), intent(in), dimension(:,:,:) :: & - oz_data ! Ozone forcing data + oz_data ! Ozone forcing data - ! In/Outs - real(kind=kind_phys), intent(inout), dimension(:,:,:) :: & - dtend ! Diagnostic tendencies for state variables + ! Outputs (optional) + real(kind=kind_phys), intent(inout), dimension(:,:), pointer, optional :: & + do3_dt_prd, & ! Physics tendency: production and loss effect + do3_dt_ozmx, & ! Physics tendency: ozone mixing ratio effect + do3_dt_temp, & ! Physics tendency: temperature effect + do3_dt_ohoz ! Physics tendency: overhead ozone effect ! Outputs real(kind=kind_phys), intent(inout), dimension(:,:) :: & @@ -110,9 +103,7 @@ subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_d ! Locals integer :: k, kmax, kmin, l, i, j - integer, dimension(4) :: idtend logical, dimension(im) :: flg - real :: gravi real(kind_phys) :: pmax, pmin, tem, temp real(kind_phys), dimension(im) :: wk1, wk2, wk3, ozib real(kind_phys), dimension(im,pl_coeff) :: prod @@ -130,19 +121,8 @@ subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_d return endif - ! Are UFS diagnostic tendencies requested? If so, set up bookeeping indices... - if(ldiag3d) then - idtend(1) = dtidx(100+ntoz,index_of_process_prod_loss) ! was ozp1 - idtend(2) = dtidx(100+ntoz,index_of_process_ozmix) ! was ozp2 - idtend(3) = dtidx(100+ntoz,index_of_process_temp) ! was ozp3 - idtend(4) = dtidx(100+ntoz,index_of_process_overhead_ozone) ! was ozp4 - else - idtend=0 - endif - ! Temporaries ozi = oz - gravi=1.0/con_g colo3(:,levs+1) = 0.0 coloz(:,levs+1) = 0.0 @@ -194,8 +174,8 @@ subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_d enddo enddo do i=1,im - colo3(i,l) = colo3(i,l+1) + ozi(i,l) * delp(i,l)*gravi - coloz(i,l) = coloz(i,l+1) + prod(i,6) * delp(i,l)*gravi + colo3(i,l) = colo3(i,l+1) + ozi(i,l) * delp(i,l)*con_1ovg + coloz(i,l) = coloz(i,l+1) + prod(i,6) * delp(i,l)*con_1ovg prod(i,2) = min(prod(i,2), 0.0) enddo do i=1,im @@ -204,18 +184,12 @@ subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_d + prod(i,4) * (colo3(i,l)-coloz(i,l)) oz(i,l) = (ozib(i) + tem*dt) / (1.0 - prod(i,2)*dt) enddo - if(idtend(1)>=1) then - dtend(:,l,idtend(1)) = dtend(:,l,idtend(1)) + (prod(:,1)-prod(:,2)*prod(:,6))*dt - endif - if(idtend(2)>=1) then - dtend(:,l,idtend(2)) = dtend(:,l,idtend(2)) + (oz(:,l) - ozib(:)) - endif - if(idtend(3)>=1) then - dtend(:,l,idtend(3)) = dtend(:,l,idtend(3)) + prod(:,3)*(tin(:,l)-prod(:,5))*dt - endif - if(idtend(4)>=1) then - dtend(:,l,idtend(4)) = dtend(:,l,idtend(4)) + prod(:,4) * (colo3(:,l)-coloz(:,l))*dt - endif + + ! Diagnostics (optional) + if (associated(do3_dt_prd)) do3_dt_prd(:,l) = (prod(:,1)-prod(:,2)*prod(:,6))*dt + if (associated(do3_dt_ozmx)) do3_dt_ozmx(:,l) = (oz(:,l) - ozib(:)) + if (associated(do3_dt_temp)) do3_dt_temp(:,l) = prod(:,3)*(tin(:,l)-prod(:,5))*dt + if (associated(do3_dt_ohoz)) do3_dt_ohoz(:,l) = prod(:,4) * (colo3(:,l)-coloz(:,l))*dt enddo return diff --git a/physics/ozphys_2015.meta b/physics/ozphys_2015.meta index 4b19f2c04..1d8fba74e 100644 --- a/physics/ozphys_2015.meta +++ b/physics/ozphys_2015.meta @@ -125,71 +125,46 @@ type = real kind = kind_phys intent = in -[ldiag3d] - standard_name = flag_for_diagnostics_3D - long_name = flag for calculating 3-D diagnostic fields - units = flag +[con_1ovg] + standard_name = one_divided_by_the_gravitational_acceleration + long_name = inverse of gravitational acceleration + units = s2 m-1 dimensions = () - type = logical + type = real + kind = kind_phys intent = in -[dtend] - standard_name = cumulative_change_of_state_variables - long_name = diagnostic tendencies for state variables - units = mixed - dimensions = (horizontal_loop_extent,vertical_layer_dimension,cumulative_change_of_state_variables_outer_index_max) +[do3_dt_prd] + standard_name = ozone_tendency_due_to_production_and_loss_rate + long_name = ozone tendency due to production and loss rate + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) type = real kind = kind_phys intent = inout -[dtidx] - standard_name = cumulative_change_of_state_variables_outer_index - long_name = index of state-variable and process in last dimension of diagnostic tendencies array AKA cumulative_change_index - units = index - dimensions = (number_of_tracers_plus_one_hundred,number_of_cumulative_change_processes) - type = integer - intent = in -[ntoz] - standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array - long_name = tracer index for ozone mixing ratio - units = index - dimensions = () - type = integer - intent = in -[index_of_process_prod_loss] - standard_name = index_of_production_and_loss_process_in_cumulative_change_index - long_name = index of production and loss effect in photochemistry process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[index_of_process_ozmix] - standard_name = index_of_ozone_mixing_ratio_process_in_cumulative_change_index - long_name = index of ozone mixing ratio effect in photochemistry process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[index_of_process_temp] - standard_name = index_of_temperature_process_in_cumulative_change_index - long_name = index of temperature effect in photochemistry process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[index_of_process_overhead_ozone] - standard_name = index_of_overhead_process_in_cumulative_change_index - long_name = index of overhead ozone effect in photochemistry process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[con_g] - standard_name = gravitational_acceleration - long_name = gravitational acceleration - units = m s-2 - dimensions = () +[do3_dt_ozmx] + standard_name = ozone_tendency_due_to_ozone_mixing_ratio + long_name = ozone tendency due to ozone mixing ratio + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) type = real kind = kind_phys - intent = in + intent = inout +[do3_dt_temp] + standard_name = ozone_tendency_due_to_temperature + long_name = ozone tendency due to temperature + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[do3_dt_ohoz] + standard_name = ozone_tendency_due_to_overhead_ozone_column + long_name = ozone tendency due to overhead ozone column + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP diff --git a/physics/ozphys_time_vary.F90 b/physics/ozphys_time_vary.F90 index a0a778c36..ddac1dcd4 100644 --- a/physics/ozphys_time_vary.F90 +++ b/physics/ozphys_time_vary.F90 @@ -16,8 +16,8 @@ module ozphys_time_vary !! \htmlinclude ozphys_time_vary_init.html !! ! ########################################################################################### - subroutine ozphys_time_vary_init(nPts, latsozp, oz_lat, dlat, jindx1, jindx2, & - ddy, errmsg, errflg) + subroutine ozphys_time_vary_init(nPts, latsozp, oz_lat, dlat, jindx1, jindx2, ddy, & + errmsg, errflg) ! Inputs integer, intent(in) :: & nPts, & ! Horizontal dimension diff --git a/physics/physcons.F90 b/physics/physcons.F90 index e7ec8fb77..19a03ef20 100644 --- a/physics/physcons.F90 +++ b/physics/physcons.F90 @@ -97,6 +97,7 @@ module physcons real(kind=kind_phys),parameter:: con_dldt =con_cvap-con_cliq real(kind=kind_phys),parameter:: con_xpona =-con_dldt/con_rv real(kind=kind_phys),parameter:: con_xponb =-con_dldt/con_rv+con_hvap/(con_rv*con_ttp) + real(kind=kind_phys),parameter:: con_1ovg = 1._kind_phys/con_g !> \name Other Physics/Chemistry constants (source: 2002 CODATA) real(kind=kind_phys),parameter:: con_c =2.99792458e+8_kind_phys !< speed of light (\f$m/s\f$) From 26ca9f9c3d08aa5ddc5cb414c1a0377d1fb5fae2 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Wed, 6 Sep 2023 10:57:28 -0600 Subject: [PATCH 08/25] Renamed file --- ...s_diagnostics.F90 => GFS_physics_post.F90} | 30 +++++++++---------- ...diagnostics.meta => GFS_physics_post.meta} | 6 ++-- physics/ozphys_2015.F90 | 1 + 3 files changed, 19 insertions(+), 18 deletions(-) rename physics/{GFS_physics_diagnostics.F90 => GFS_physics_post.F90} (81%) rename physics/{GFS_physics_diagnostics.meta => GFS_physics_post.meta} (97%) diff --git a/physics/GFS_physics_diagnostics.F90 b/physics/GFS_physics_post.F90 similarity index 81% rename from physics/GFS_physics_diagnostics.F90 rename to physics/GFS_physics_post.F90 index 0c6197bc2..d034c1999 100644 --- a/physics/GFS_physics_diagnostics.F90 +++ b/physics/GFS_physics_post.F90 @@ -1,20 +1,20 @@ ! ########################################################################################### -!> \file GFS_physics_diagnostics.F90 +!> \file GFS_physics_post.F90 !! ! ########################################################################################### -module GFS_physics_diagnostics +module GFS_physics_post use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec implicit none - public GFS_physics_diagnostics_init, GFS_physics_diagnostics_run + public GFS_physics_post_init, GFS_physics_post_run contains ! ########################################################################################### -! SUBROUTINE GFS_physics_diagnostics_init +! SUBROUTINE GFS_physics_post_init ! ########################################################################################### -!! \section arg_table_GFS_physics_diagnostics_init Argument Table -!! \htmlinclude GFS_physics_diagnostics_init.html +!! \section arg_table_GFS_physics_post_init Argument Table +!! \htmlinclude GFS_physics_post_init.html !! - subroutine GFS_physics_diagnostics_init(errmsg, errflg) + subroutine GFS_physics_post_init(errmsg, errflg) ! Outputs character(len=*), intent(out) :: & @@ -22,15 +22,15 @@ subroutine GFS_physics_diagnostics_init(errmsg, errflg) integer, intent(out) :: & errflg ! CCPP error flag - end subroutine GFS_physics_diagnostics_init + end subroutine GFS_physics_post_init ! ########################################################################################### -! SUBROUTINE GFS_physics_diagnostics_run +! SUBROUTINE GFS_physics_post_run ! ########################################################################################### -!! \section arg_table_GFS_physics_diagnostics_run Argument Table -!! \htmlinclude GFS_physics_diagnostics_run.html +!! \section arg_table_GFS_physics_post_run Argument Table +!! \htmlinclude GFS_physics_post_run.html !! - subroutine GFS_physics_diagnostics_run(nCol, nLev, ntoz, dtidx, ip_prod_loss, ip_ozmix, & + subroutine GFS_physics_post_run(nCol, nLev, ntoz, dtidx, ip_prod_loss, ip_ozmix, & ip_temp, ip_overhead_ozone, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, dtend,& errmsg, errflg) ! Inputs @@ -69,7 +69,7 @@ subroutine GFS_physics_diagnostics_run(nCol, nLev, ntoz, dtidx, ip_prod_loss, ip ! ####################################################################################### ! - ! Ozone physics diagnostics + ! Ozone physics diagnostic ! ! ####################################################################################### idtend = dtidx(100+ntoz,ip_prod_loss) @@ -92,6 +92,6 @@ subroutine GFS_physics_diagnostics_run(nCol, nLev, ntoz, dtidx, ip_prod_loss, ip dtend(:,:,idtend) = dtend(:,:,idtend) + do3_dt_ohoz endif - end subroutine GFS_physics_diagnostics_run + end subroutine GFS_physics_post_run -end module GFS_physics_diagnostics +end module GFS_physics_post diff --git a/physics/GFS_physics_diagnostics.meta b/physics/GFS_physics_post.meta similarity index 97% rename from physics/GFS_physics_diagnostics.meta rename to physics/GFS_physics_post.meta index b6036b0c9..8b5120b9e 100644 --- a/physics/GFS_physics_diagnostics.meta +++ b/physics/GFS_physics_post.meta @@ -1,11 +1,11 @@ [ccpp-table-properties] - name = GFS_physics_diagnostics + name = GFS_physics_post type = scheme dependencies = machine.F ######################################################################## [ccpp-arg-table] - name = GFS_physics_diagnostics_init + name = GFS_physics_post_init type = scheme [errmsg] standard_name = ccpp_error_message @@ -25,7 +25,7 @@ ######################################################################## [ccpp-arg-table] - name = GFS_physics_diagnostics_run + name = GFS_physics_post_run type = scheme [nCol] standard_name = horizontal_loop_extent diff --git a/physics/ozphys_2015.F90 b/physics/ozphys_2015.F90 index 9898c71e4..47386bd6e 100644 --- a/physics/ozphys_2015.F90 +++ b/physics/ozphys_2015.F90 @@ -17,6 +17,7 @@ module ozphys_2015 !! \c ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77) provided by Naval !! Research Laboratory through CHEM2D chemistry model !! (McCormack et al. (2006) \cite mccormack_et_al_2006). +!! (https://doi.org/10.5194/acp-6-4943-2006) !! !> \section genal_ozphys_2015 GFS ozphys_2015_run General Algorithm !> - This code assumes that both prsl and po3 are from bottom to top From c0ec619536bd29740627cb2dc1da106b61dd435c Mon Sep 17 00:00:00 2001 From: Michael Toy Date: Tue, 19 Sep 2023 02:36:14 +0000 Subject: [PATCH 09/25] Added tendency limiter for mesosphere and horizontal wave number filter for orographic gravity wave drag in UGWP -- Issue #95 --- physics/drag_suite.F90 | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/physics/drag_suite.F90 b/physics/drag_suite.F90 index 22f122e71..ff68f4216 100644 --- a/physics/drag_suite.F90 +++ b/physics/drag_suite.F90 @@ -460,6 +460,8 @@ subroutine drag_suite_run( & real(kind=kind_phys), parameter :: ce = 0.8 real(kind=kind_phys), parameter :: cg = 0.5 real(kind=kind_phys), parameter :: sgmalolev = 0.5 ! max sigma lvl for dtfac + real(kind=kind_phys), parameter :: plolevmeso = 70.0 ! pres lvl for mesosphere OGWD reduction (Pa) + real(kind=kind_phys), parameter :: facmeso = 0.5 ! fractional velocity reduction for OGWD integer,parameter :: kpblmin = 2 ! @@ -472,7 +474,7 @@ subroutine drag_suite_run( & rcsks,wdir,ti,rdz,tem2,dw2,shr2, & bvf2,rdelks,wtkbj,tem,gfobnv,hd,fro, & rim,temc,tem1,efact,temv,dtaux,dtauy, & - dtauxb,dtauyb,eng0,eng1 + dtauxb,dtauyb,eng0,eng1,ksmax,dtfac_meso ! logical :: ldrag(im),icrilv(im), & flag(im),kloop1(im) @@ -887,6 +889,14 @@ subroutine drag_suite_run( & ldrag(i) = ldrag(i) .or. bnv2(i,1).le.0.0 ldrag(i) = ldrag(i) .or. ulow(i).eq.1.0 ldrag(i) = ldrag(i) .or. var_stoch(i) .le. 0.0 +! Check if mesoscale gravity waves will propagate vertically or be evanescent +! and not impart a drag force -- consider the maximum sub-grid horizontal +! topographic wavelength to be one-half the horizontal grid spacing -- calculate +! ksmax accordingly + ksmax = 4.0*pi/dx(i) ! based on wavelength = 0.5*dx(i) + if ( bnv2(i,1).gt.0.0 ) then + ldrag(i) = ldrag(i) .or. sqrt(bnv2(i,1))*rulow(i).lt.ksmax + endif ! ! set all ri low level values to the low level value ! @@ -1106,7 +1116,19 @@ subroutine drag_suite_run( & enddo ! do k = kts,km - taud_ms(i,k) = taud_ms(i,k)*dtfac(i)* ls_taper(i) *(1.-rstoch(i)) + + ! Check if well into mesosphere -- if so, perform similar reduction of + ! velocity tendency due to mesoscale GWD to prevent sudden reversal of + ! wind direction (similar to above) + dtfac_meso = 1.0 + if (prsl(i,k).le.plolevmeso) then + if (taud_ms(i,k).ne.0.) & + dtfac_meso = min(dtfac_meso,facmeso*abs(velco(i,k) & + /(deltim*rcs*taud_ms(i,k)))) + end if + + taud_ms(i,k) = taud_ms(i,k)*dtfac(i)*dtfac_meso* & + ls_taper(i) *(1.-rstoch(i)) taud_bl(i,k) = taud_bl(i,k)*dtfac(i)* ls_taper(i) *(1.-rstoch(i)) dtaux = taud_ms(i,k) * xn(i) From a110a5b93bce92bab083fdaa07bd21ba5cae8720 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Wed, 27 Sep 2023 14:04:50 -0600 Subject: [PATCH 10/25] Getting real close... --- physics/GFS_phys_time_vary.fv3.F90 | 105 ++++-- physics/GFS_phys_time_vary.fv3.meta | 83 ++++- physics/GFS_rrtmg_pre.F90 | 19 +- physics/GFS_rrtmg_pre.meta | 39 +-- physics/GFS_rrtmg_setup.F90 | 26 +- physics/GFS_rrtmg_setup.meta | 30 +- physics/GFS_rrtmgp_pre.F90 | 22 +- physics/GFS_rrtmgp_pre.meta | 35 +- physics/GFS_rrtmgp_setup.F90 | 20 +- physics/GFS_rrtmgp_setup.meta | 30 +- physics/module_ozphys.F90 | 476 ++++++++++++++++++++++++++++ physics/module_ozphys.meta | 24 ++ physics/ozphys_2015.F90 | 126 +++----- physics/ozphys_2015.meta | 62 +--- physics/ozphys_time_vary.F90 | 165 ---------- physics/ozphys_time_vary.meta | 200 ------------ physics/radiation_gases.f | 313 ++---------------- physics/rrtmgp_lw_main.F90 | 1 - 18 files changed, 815 insertions(+), 961 deletions(-) create mode 100644 physics/module_ozphys.F90 create mode 100644 physics/module_ozphys.meta delete mode 100644 physics/ozphys_time_vary.F90 delete mode 100644 physics/ozphys_time_vary.meta diff --git a/physics/GFS_phys_time_vary.fv3.F90 b/physics/GFS_phys_time_vary.fv3.F90 index d82f22399..af2dd9b00 100644 --- a/physics/GFS_phys_time_vary.fv3.F90 +++ b/physics/GFS_phys_time_vary.fv3.F90 @@ -10,10 +10,12 @@ module GFS_phys_time_vary use omp_lib #endif - use machine, only : kind_phys + use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec use mersenne_twister, only: random_setseed, random_number + use module_ozphys, only: ty_ozphys + use h2o_def, only : levh2o, h2o_coeff, h2o_lat, h2o_pres, h2o_time, h2oplin use h2ointerp, only : read_h2odata, setindxh2o, h2ointerpol @@ -64,9 +66,9 @@ module GFS_phys_time_vary !>\section gen_GFS_phys_time_vary_init GFS_phys_time_vary_init General Algorithm !> @{ subroutine GFS_phys_time_vary_init ( & - me, master, h2o_phys, iaerclm, iccn, iaermdl, iflip, im, levs, & + me, master, ntoz, h2o_phys, iaerclm, iccn, iaermdl, iflip, im, levs, & nx, ny, idate, xlat_d, xlon_d, & - jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & + jindx1_o3, jindx2_o3, ddy_o3, jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & jindx1_aer, jindx2_aer, ddy_aer, iindx1_aer, iindx2_aer, ddx_aer, aer_nm, & jindx1_ci, jindx2_ci, ddy_ci, iindx1_ci, iindx2_ci, ddx_ci, imap, jmap, & do_ugwp_v1, jindx1_tau, jindx2_tau, ddy_j1tau, ddy_j2tau, & @@ -79,12 +81,12 @@ subroutine GFS_phys_time_vary_init ( smcwtdxy, deeprechxy, rechxy, snowxy, snicexy, snliqxy, tsnoxy , smoiseq, zsnsoxy, & slc, smc, stc, tsfcl, snowd, canopy, tg3, stype, con_t0c, lsm_cold_start, nthrds, & lkm, use_lake_model, lakefrac, lakedepth, iopt_lake, iopt_lake_clm, iopt_lake_flake, & - lakefrac_threshold, lakedepth_threshold, errmsg, errflg) + lakefrac_threshold, lakedepth_threshold, ozphys, errmsg, errflg) implicit none ! Interface variables - integer, intent(in) :: me, master, iccn, iflip, im, nx, ny, levs, iaermdl + integer, intent(in) :: me, master, ntoz, iccn, iflip, im, nx, ny, levs, iaermdl logical, intent(in) :: h2o_phys, iaerclm, lsm_cold_start integer, intent(in) :: idate(:), iopt_lake, iopt_lake_clm, iopt_lake_flake real(kind_phys), intent(in) :: fhour, lakefrac_threshold, lakedepth_threshold @@ -93,8 +95,8 @@ subroutine GFS_phys_time_vary_init ( integer, intent(in) :: lkm integer, intent(inout) :: use_lake_model(:) real(kind=kind_phys), intent(in ) :: lakefrac(:), lakedepth(:) - integer, intent(inout) :: jindx1_h(:), jindx2_h(:) - real(kind_phys), intent(inout) :: ddy_h(:) + integer, intent(inout) :: jindx1_o3(:), jindx2_o3(:), jindx1_h(:), jindx2_h(:) + real(kind_phys), intent(inout) :: ddy_o3(:), ddy_h(:) real(kind_phys), intent(in) :: h2opl(:,:,:) integer, intent(inout) :: jindx1_aer(:), jindx2_aer(:), iindx1_aer(:), iindx2_aer(:) @@ -113,6 +115,7 @@ subroutine GFS_phys_time_vary_init ( real(kind_phys), intent(in) :: min_seaice, fice(:) real(kind_phys), intent(in) :: landfrac(:) real(kind_phys), intent(inout) :: weasd(:) + type(ty_ozphys), intent(in) :: ozphys ! NoahMP - only allocated when NoahMP is used integer, intent(in) :: lsoil, lsnow_lsm_lbound, lsnow_lsm_ubound @@ -200,21 +203,30 @@ subroutine GFS_phys_time_vary_init ( jamax=-999 !$OMP parallel num_threads(nthrds) default(none) & -!$OMP shared (me,master,h2o_phys,im,nx,ny,levs,idate) & +!$OMP shared (me,master,ntoz,h2o_phys,im,nx,ny,levs,idate) & !$OMP shared (xlat_d,xlon_d,imap,jmap,errmsg,errflg) & !$OMP shared (levh2o,h2o_coeff,h2o_pres,h2opl) & !$OMP shared (iamin, iamax, jamin, jamax) & !$OMP shared (iaerclm,iaermdl,ntrcaer,aer_nm,iflip,iccn) & -!$OMP shared (jindx1_h,jindx2_h,ddy_h) & +!$OMP shared (jindx1_o3,jindx2_o3,ddy_o3,jindx1_h,jindx2_h,ddy_h) & !$OMP shared (jindx1_aer,jindx2_aer,ddy_aer,iindx1_aer,iindx2_aer,ddx_aer) & !$OMP shared (jindx1_ci,jindx2_ci,ddy_ci,iindx1_ci,iindx2_ci,ddx_ci) & !$OMP shared (do_ugwp_v1,jindx1_tau,jindx2_tau,ddy_j1tau,ddy_j2tau) & !$OMP shared (isot,ivegsrc,nlunit,sncovr,sncovr_ice,lsm,lsm_ruc) & !$OMP shared (min_seaice,fice,landfrac,vtype,weasd,snupx,salp_data) & +!$OMP shared (ozphys) & !$OMP private (ix,i,j,rsnow,vegtyp) !$OMP sections +!$OMP section +!> - Setup spatial interpolation indices for ozone physics. + if (ntoz > 0) then + !$OMP CRITICAL + call ozphys%setup_forcing(xlat_d, jindx1_o3, jindx2_o3, ddy_o3) + !$OMP END CRITICAL + endif + !$OMP section !> - Call read_h2odata() to read stratospheric water vapor data call read_h2odata (h2o_phys, me, master) @@ -710,8 +722,8 @@ end subroutine GFS_phys_time_vary_init !> @{ subroutine GFS_phys_time_vary_timestep_init ( & me, master, cnx, cny, isc, jsc, nrcm, im, levs, kdt, idate, nsswr, fhswr, lsswr, fhour, & - imfdeepcnv, cal_pre, random_clds, nscyc, h2o_phys, iaerclm, iccn, clstp, & - jindx1_h, jindx2_h, ddy_h, h2opl, iflip, & + imfdeepcnv, cal_pre, random_clds, nscyc, ntoz, h2o_phys, iaerclm, iccn, clstp, & + jindx1_o3, jindx2_o3, ddy_o3, ozpl, jindx1_h, jindx2_h, ddy_h, h2opl, iflip, & jindx1_aer, jindx2_aer, ddy_aer, iindx1_aer, iindx2_aer, ddx_aer, aer_nm, & jindx1_ci, jindx2_ci, ddy_ci, iindx1_ci, iindx2_ci, ddx_ci, in_nm, ccn_nm, fn_nml, & imap, jmap, prsl, seed0, rann, nthrds, nx, ny, nsst, tile_num, nlunit, lsoil, lsoil_lsm,& @@ -719,21 +731,21 @@ subroutine GFS_phys_time_vary_timestep_init ( lakefrac, min_seaice, min_lakeice, smc, slc, stc, smois, sh2o, tslb, tiice, tg3, tref, & tsfc, tsfco, tisfc, hice, fice, facsf, facwf, alvsf, alvwf, alnsf, alnwf, zorli, zorll, & zorlo, weasd, slope, snoalb, canopy, vfrac, vtype, stype,scolor, shdmin, shdmax, snowd, & - cv, cvb, cvt, oro, oro_uf, xlat_d, xlon_d, slmsk, landfrac, & + cv, cvb, cvt, oro, oro_uf, xlat_d, xlon_d, slmsk, landfrac, ozphys, & do_ugwp_v1, jindx1_tau, jindx2_tau, ddy_j1tau, ddy_j2tau, tau_amf, errmsg, errflg) implicit none ! Interface variables integer, intent(in) :: me, master, cnx, cny, isc, jsc, nrcm, im, levs, kdt, & - nsswr, imfdeepcnv, iccn, nscyc, iflip + nsswr, imfdeepcnv, iccn, nscyc, ntoz, iflip integer, intent(in) :: idate(:) real(kind_phys), intent(in) :: fhswr, fhour logical, intent(in) :: lsswr, cal_pre, random_clds, h2o_phys, iaerclm real(kind_phys), intent(out) :: clstp - integer, intent(in) :: jindx1_h(:), jindx2_h(:) - real(kind_phys), intent(in) :: ddy_h(:) - real(kind_phys), intent(inout) :: h2opl(:,:,:) + integer, intent(in) :: jindx1_o3(:), jindx2_o3(:), jindx1_h(:), jindx2_h(:) + real(kind_phys), intent(in) :: ddy_o3(:), ddy_h(:) + real(kind_phys), intent(inout) :: ozpl(:,:,:), h2opl(:,:,:) integer, intent(in) :: jindx1_aer(:), jindx2_aer(:), iindx1_aer(:), iindx2_aer(:) real(kind_phys), intent(in) :: ddy_aer(:), ddx_aer(:) real(kind_phys), intent(inout) :: aer_nm(:,:,:) @@ -749,6 +761,7 @@ subroutine GFS_phys_time_vary_timestep_init ( integer, intent(in) :: jindx1_tau(:), jindx2_tau(:) real(kind_phys), intent(in) :: ddy_j1tau(:), ddy_j2tau(:) real(kind_phys), intent(inout) :: tau_amf(:) + type(ty_ozphys), intent(in) :: ozphys ! For gcycle only integer, intent(in) :: nthrds, nx, ny, nsst, tile_num, nlunit, lsoil @@ -771,10 +784,13 @@ subroutine GFS_phys_time_vary_timestep_init ( integer, intent(out) :: errflg ! Local variables - integer :: i, j, k, iseed, iskip, ix - real(kind=kind_phys) :: wrk(1) - real(kind=kind_phys) :: rannie(cny) - real(kind=kind_phys) :: rndval(cnx*cny*nrcm) + integer :: i, j, k, iseed, iskip, ix, idat(8), jdat(8), iday, j1, j2, nc, n1, n2, jdow, & + jdoy, jday, w3kindreal, w3kindint + real(kind_phys) :: wrk(1), tem, tx1, tx2, rjday + real(kind_phys) :: rannie(cny) + real(kind_phys) :: rndval(cnx*cny*nrcm) + real(kind_dbl_prec) :: rinc(5) + real(kind_sngl_prec) :: rinc4(5) ! Initialize CCPP error handling variables errmsg = '' @@ -790,15 +806,56 @@ subroutine GFS_phys_time_vary_timestep_init ( !$OMP parallel num_threads(nthrds) default(none) & !$OMP shared(kdt,nsswr,lsswr,clstp,imfdeepcnv,cal_pre,random_clds) & !$OMP shared(fhswr,fhour,seed0,cnx,cny,nrcm,wrk,rannie,rndval) & -!$OMP shared(rann,im,isc,jsc,imap,jmap,me,idate) & -!$OMP shared(h2o_phys,jindx1_h,jindx2_h,h2opl,ddy_h,iaerclm,master) & +!$OMP shared(rann,im,isc,jsc,imap,jmap,ntoz,me,idate,jindx1_o3,jindx2_o3) & +!$OMP shared(ozpl,ddy_o3,h2o_phys,jindx1_h,jindx2_h,h2opl,ddy_h,iaerclm,master) & !$OMP shared(levs,prsl,iccn,jindx1_ci,jindx2_ci,ddy_ci,iindx1_ci,iindx2_ci) & !$OMP shared(ddx_ci,in_nm,ccn_nm,do_ugwp_v1,jindx1_tau,jindx2_tau,ddy_j1tau) & -!$OMP shared(ddy_j2tau,tau_amf,iflip) & -!$OMP private(iseed,iskip,i,j,k) +!$OMP shared(ddy_j2tau,tau_amf,iflip,ozphys) & +!$OMP private(iseed,iskip,i,j,rjday,idat,rinc,w3kindreal,w3kindint,jdat)& +!$OMP private(jdow,jdoy,jday,rinc4,n1,n2) !$OMP sections +!$OMP section +!> - Compute temporal interpolation indices for updating gas concentrations. + idat=0 + idat(1)=idate(4) + idat(2)=idate(2) + idat(3)=idate(3) + idat(5)=idate(1) + rinc=0. + rinc(2)=fhour + call w3kind(w3kindreal,w3kindint) + if(w3kindreal==4) then + rinc4=rinc + CALL w3movdat(rinc4,idat,jdat) + else + CALL w3movdat(rinc,idat,jdat) + endif + jdow = 0 + jdoy = 0 + jday = 0 + call w3doxdat(jdat,jdow,jdoy,jday) + rjday = jdoy + jdat(5) / 24. + if (rjday < ozphys%time(1)) rjday = rjday + 365. + + n2 = ozphys%ntime + 1 + do j=2,ozphys%ntime + if (rjday < ozphys%time(j)) then + n2 = j + exit + endif + enddo + n1 = n2 - 1 + if (n2 > ozphys%ntime) n2 = n2 - ozphys%ntime + + !> - Update ozone concentration. + if (ntoz > 0) then + !$OMP CRITICAL + call ozphys%update_forcing(jindx1_o3, jindx2_o3, ddy_o3, rjday, n1, n2, ozpl) + !$OMP END CRITICAL + endif + !$OMP section !--- switch for saving convective clouds - cnvc90.f diff --git a/physics/GFS_phys_time_vary.fv3.meta b/physics/GFS_phys_time_vary.fv3.meta index 6ef6e226c..bf5a3fa04 100644 --- a/physics/GFS_phys_time_vary.fv3.meta +++ b/physics/GFS_phys_time_vary.fv3.meta @@ -2,7 +2,7 @@ name = GFS_phys_time_vary type = scheme dependencies = aerclm_def.F,aerinterp.F90,gcycle.F90,h2o_def.f,h2ointerp.f90,iccn_def.F,iccninterp.F90,machine.F,mersenne_twister.f - dependencies = namelist_soilveg.f,set_soilveg.f,sfcsub.F,cires_tauamf_data.F90,noahmp_tables.f90 + dependencies = namelist_soilveg.f,set_soilveg.f,sfcsub.F,cires_tauamf_data.F90,noahmp_tables.f90,module_ozphys.F90 ######################################################################## [ccpp-arg-table] @@ -72,6 +72,36 @@ dimensions = () type = integer intent = in + intent = in +[ntoz] + standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array + long_name = tracer index for ozone mixing ratio + units = index + dimensions = () + type = integer + intent = in +[jindx1_o3] + standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation low index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[jindx2_o3] + standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation high index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[ddy_o3] + standard_name = latitude_interpolation_weight_for_ozone_forcing + long_name = interpolation high index for ozone + units = none + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = in [nx] standard_name = number_of_points_in_x_direction_for_this_MPI_rank long_name = number of points in x direction for this MPI rank @@ -932,6 +962,13 @@ type = real kind = kind_phys intent = in +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed + dimensions = () + type = ty_ozphys + intent = in [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP @@ -1107,6 +1144,13 @@ dimensions = () type = integer intent = in +[ntoz] + standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array + long_name = tracer index for ozone mixing ratio + units = index + dimensions = () + type = integer + intent = in [h2o_phys] standard_name = flag_for_stratospheric_water_vapor_physics long_name = flag for stratospheric water vapor physics @@ -1136,6 +1180,36 @@ type = real kind = kind_phys intent = out +[jindx1_o3] + standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation low index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[jindx2_o3] + standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation high index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[ddy_o3] + standard_name = latitude_interpolation_weight_for_ozone_forcing + long_name = interpolation high index for ozone + units = none + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = in +[ozpl] + standard_name = ozone_forcing + long_name = ozone forcing data + units = mixed + dimensions = (horizontal_dimension,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) + type = real + kind = kind_phys + intent = inout [jindx1_h] standard_name = lower_latitude_index_of_stratospheric_water_vapor_forcing_for_interpolation long_name = interpolation low index for stratospheric water vapor @@ -1868,6 +1942,13 @@ type = real kind = kind_phys intent = inout +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed + dimensions = () + type = ty_ozphys + intent = in [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP diff --git a/physics/GFS_rrtmg_pre.F90 b/physics/GFS_rrtmg_pre.F90 index f2183919f..69be4f8d0 100644 --- a/physics/GFS_rrtmg_pre.F90 +++ b/physics/GFS_rrtmg_pre.F90 @@ -45,8 +45,8 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& gasvmr_ccl4, gasvmr_cfc113, aerodp,ext550, clouds6, clouds7, clouds8, & clouds9, cldsa, cldfra, cldfra2d, lwp_ex,iwp_ex, lwp_fc,iwp_fc, & faersw1, faersw2, faersw3, faerlw1, faerlw2, faerlw3, alpha, rrfs_sd, & - aero_dir_fdb, fdb_coef, spp_wts_rad, spp_rad, ico2, latsozc, levozc, & - blatc, dphiozc, errmsg, errflg) + aero_dir_fdb, fdb_coef, spp_wts_rad, spp_rad, ico2, ozphys, & + errmsg, errflg) use machine, only: kind_phys @@ -54,7 +54,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& use funcphys, only: fpvs use module_radiation_astronomy,only: coszmn ! sol_init, sol_update - use module_radiation_gases, only: NF_VGAS, getgases, getozn ! gas_init, gas_update, + use module_radiation_gases, only: NF_VGAS, getgases ! gas_init, gas_update, use module_radiation_aerosols, only: NF_AESW, NF_AELW, setaer, & ! aer_init, aer_update, & NSPC1 use module_radiation_clouds, only: NF_CLDS, & ! cld_init @@ -81,6 +81,8 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& make_IceNumber, & make_DropletNumber, & make_RainNumber + ! For NRL Ozone + use module_ozphys, only: ty_ozphys implicit none integer, intent(in) :: im, levs, lm, lmk, lmp, ltp, & @@ -102,8 +104,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& imp_physics_mg, imp_physics_wsm6, & imp_physics_nssl, & imp_physics_fer_hires, & - yearlen, icloud, iaermdl, iaerflg, & - latsozc, levozc + yearlen, icloud, iaermdl, iaerflg integer, intent(in) :: & iovr, & ! choice of cloud-overlap method @@ -134,7 +135,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& integer, intent(in) :: spp_rad real(kind_phys), intent(in) :: spp_wts_rad(:,:) - real(kind=kind_phys), intent(in) :: fhswr, fhlwr, solhr, sup, julian, sppt_amp, dcorr_con, blatc, dphiozc + real(kind=kind_phys), intent(in) :: fhswr, fhlwr, solhr, sup, julian, sppt_amp, dcorr_con real(kind=kind_phys), intent(in) :: con_eps, epsm1, fvirt, rog, rocp, con_rd, con_pi, con_g, con_ttp, con_thgni real(kind=kind_phys), dimension(:), intent(in) :: xlat_d, xlat, xlon, & @@ -252,6 +253,9 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& integer :: iflag integer :: islmsk + ! For NRL Ozone + type(ty_ozphys),intent(in) :: ozphys + integer :: ids, ide, jds, jde, kds, kde, & ims, ime, jms, jme, kms, kme, & its, ite, jts, jte, kts, kte @@ -422,7 +426,6 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& !> - Get layer ozone mass mixing ratio (if use ozone climatology data, -!! call getozn()). if (ntoz > 0) then ! interactive ozone generation do k=1,lmk @@ -431,7 +434,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& enddo enddo else ! climatological ozone - call getozn (prslk1, xlat, im, lmk, top_at_1, latsozc, levozc, blatc, dphiozc, olyr) + call ozphys%oz_clim(xlat, prslk1, con_pi, olyr) endif ! end_if_ntoz !> - Call coszmn(), to compute cosine of zenith angle (only when SW is called) diff --git a/physics/GFS_rrtmg_pre.meta b/physics/GFS_rrtmg_pre.meta index 038f59c27..a29b0ac3c 100644 --- a/physics/GFS_rrtmg_pre.meta +++ b/physics/GFS_rrtmg_pre.meta @@ -2,7 +2,7 @@ name = GFS_rrtmg_pre type = scheme dependencies = funcphys.f90,iounitdef.f,machine.F,module_bfmicrophysics.f,module_mp_radar.F90,module_mp_thompson.F90 - dependencies = module_mp_thompson_make_number_concentrations.F90,radcons.f90,radiation_aerosols.f + dependencies = module_mp_thompson_make_number_concentrations.F90,radcons.f90,radiation_aerosols.f,module_ozphys.F90 dependencies = radiation_astronomy.f,radiation_clouds.f,radiation_gases.f,radlw_param.f,radsw_param.f,surface_perturbation.F90,radiation_cloud_overlap.F90 ######################################################################## @@ -247,6 +247,13 @@ dimensions = () type = integer intent = in +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed + dimensions = () + type = ty_ozphys + intent = in [iaermdl] standard_name = control_for_aerosol_radiation_scheme long_name = control of aerosol scheme in radiation @@ -1503,36 +1510,6 @@ dimensions = () type = integer intent = in -[latsozc] - standard_name = number_of_latitudes_in_ozone_climotology_data - long_name = number of latitude in ozone climotology data - units = count - dimensions = () - type = integer - intent = in -[levozc] - standard_name = number_of_levels_in_ozone_climotology_data - long_name = number of levels in ozone climotology data - units = count - dimensions = () - type = integer - intent = in -[dphiozc] - standard_name = ozone_data_parameter_1 - long_name = ozone data parameter 1 - units = none - dimensions = () - type = real - kind = kind_phys - intent = in -[blatc] - standard_name = ozone_data_parameter_2 - long_name = ozone data parameter 2 - units = none - dimensions = () - type = real - kind = kind_phys - intent = in [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP diff --git a/physics/GFS_rrtmg_setup.F90 b/physics/GFS_rrtmg_setup.F90 index 30917b961..908a364dc 100644 --- a/physics/GFS_rrtmg_setup.F90 +++ b/physics/GFS_rrtmg_setup.F90 @@ -7,7 +7,7 @@ module GFS_rrtmg_setup use machine, only: kind_phys - + use module_ozphys, only: ty_ozphys implicit none public GFS_rrtmg_setup_init, GFS_rrtmg_setup_timestep_init, GFS_rrtmg_setup_finalize @@ -44,7 +44,7 @@ subroutine GFS_rrtmg_setup_init ( si, levr, ictm, isol, solar_file, ico2, & iaermdl, iaerflg, aeros_file, con_pi, con_t0c, con_c, con_boltz, & con_plnk, con_solr_2008, con_solr_2002, con_g, con_rd, co2usr_file, & co2cyc_file, rad_hr_units, inc_minor_gas, icliq_lw, isubcsw, isubclw,& - iswmode, latsozp, levozp, timeozp, ipsd0, ltp, lextop, errmsg, errflg) + iswmode, ipsd0, ltp, lextop, errmsg, errflg) ! ================= subprogram documentation block ================ ! ! ! ! subprogram: GFS_rrtmg_setup_init - a subprogram to initialize radiation ! @@ -155,8 +155,7 @@ subroutine GFS_rrtmg_setup_init ( si, levr, ictm, isol, solar_file, ico2, & integer, intent(in) :: levr, ictm, isol, ico2, iaer, ntcw, num_p3d, & ltp, npdf3d, ntoz, iovr, iovr_rand, iovr_maxrand, iovr_max, & iovr_dcorr, iovr_exp, iovr_exprand, icliq_sw, imp_physics, & - iflip, me, rad_hr_units, icliq_lw, isubcsw, isubclw, iswmode, & - latsozp, levozp, timeozp + iflip, me, rad_hr_units, icliq_lw, isubcsw, isubclw, iswmode integer, intent(in) :: idate(:) logical, intent(in) :: lcrick, lcnorm, lnoprec, do_RRTMGP, lalw1bd, & inc_minor_gas, lextop @@ -219,8 +218,7 @@ subroutine GFS_rrtmg_setup_init ( si, levr, ictm, isol, solar_file, ico2, & con_pi ) call aer_init ( levr, me, iaermdl, iaerflg, lalw1bd, aeros_file, & con_pi, con_t0c, con_c, con_boltz, con_plnk, errflg, errmsg) - call gas_init ( me, co2usr_file, co2cyc_file, ico2, ictm, ntoz, & - con_pi, latsozp, levozp, timeozp, errflg, errmsg) + call gas_init ( me, co2usr_file, co2cyc_file, ico2, ictm, con_pi, errflg, errmsg ) call cld_init ( si, levr, imp_physics, me, con_g, con_rd, errflg, errmsg) call rlwinit ( me, rad_hr_units, inc_minor_gas, icliq_lw, isubcsw, & iovr, iovr_rand, iovr_maxrand, iovr_max, iovr_dcorr, & @@ -246,7 +244,8 @@ end subroutine GFS_rrtmg_setup_init !! subroutine GFS_rrtmg_setup_timestep_init (idate, jdate, deltsw, deltim, & lsswr, me, iaermdl, iaerflg, isol, aeros_file, slag, sdec, cdec, & - solcon, con_pi, co2dat_file, co2gbl_file, ictm, ico2, ntoz, errmsg, errflg) + solcon, con_pi, co2dat_file, co2gbl_file, ictm, ico2, ntoz, ozphys,& + errmsg, errflg) implicit none @@ -259,6 +258,7 @@ subroutine GFS_rrtmg_setup_timestep_init (idate, jdate, deltsw, deltim, & logical, intent(in) :: lsswr integer, intent(in) :: me integer, intent(in) :: iaermdl, iaerflg, isol, ictm, ico2, ntoz + type(ty_ozphys), intent(inout) :: ozphys character(len=26), intent(in) :: aeros_file, co2dat_file, co2gbl_file real(kind=kind_phys), intent(out) :: slag real(kind=kind_phys), intent(out) :: sdec @@ -279,7 +279,7 @@ subroutine GFS_rrtmg_setup_timestep_init (idate, jdate, deltsw, deltim, & errflg = 0 call radupdate(idate,jdate,deltsw,deltim,lsswr,me,iaermdl, iaerflg,isol,aeros_file,& - slag,sdec,cdec,solcon,con_pi,co2dat_file,co2gbl_file,ictm,ico2,ntoz,errflg,errmsg) + slag,sdec,cdec,solcon,con_pi,co2dat_file,co2gbl_file,ictm,ico2,ntoz,ozphys,errflg,errmsg) end subroutine GFS_rrtmg_setup_timestep_init @@ -327,7 +327,7 @@ end subroutine GFS_rrtmg_setup_finalize !----------------------------------- subroutine radupdate( idate,jdate,deltsw,deltim,lsswr,me, iaermdl,& iaerflg, isol, aeros_file, slag,sdec,cdec,solcon, con_pi, & - co2dat_file,co2gbl_file, ictm, ico2, ntoz, errflg, errmsg) + co2dat_file,co2gbl_file, ictm, ico2, ntoz, ozphys, errflg, errmsg) !................................... ! ================= subprogram documentation block ================ ! @@ -371,6 +371,7 @@ subroutine radupdate( idate,jdate,deltsw,deltim,lsswr,me, iaermdl,& ! --- inputs: integer, intent(in) :: idate(:), jdate(:), me, iaermdl, iaerflg, isol, ictm, ntoz, ico2 + type(ty_ozphys),intent(inout) :: ozphys logical, intent(in) :: lsswr character(len=26),intent(in) :: aeros_file,co2dat_file,co2gbl_file @@ -463,8 +464,11 @@ subroutine radupdate( idate,jdate,deltsw,deltim,lsswr,me, iaermdl,& lco2_chg = .false. endif - call gas_update ( kyear,kmon,kday,khour,loz1st,lco2_chg, me, co2dat_file, & - co2gbl_file, ictm, ico2, ntoz, errflg, errmsg ) + call gas_update ( kyear,kmon,kday,khour,lco2_chg, me, co2dat_file, & + co2gbl_file, ictm, ico2, errflg, errmsg ) + if (ntoz == 0) then + call ozphys%update_clim(kmon, kday, khour, loz1st) + endif if ( loz1st ) loz1st = .false. diff --git a/physics/GFS_rrtmg_setup.meta b/physics/GFS_rrtmg_setup.meta index f92d6f8db..35713757b 100644 --- a/physics/GFS_rrtmg_setup.meta +++ b/physics/GFS_rrtmg_setup.meta @@ -2,7 +2,7 @@ name = GFS_rrtmg_setup type = scheme dependencies = iounitdef.f,module_bfmicrophysics.f,radcons.f90,radiation_aerosols.f,radiation_astronomy.f,radiation_clouds.f - dependencies = module_mp_thompson.F90,radiation_gases.f,radlw_main.F90,radlw_param.f,radsw_main.F90,radsw_param.f,machine.F + dependencies = module_mp_thompson.F90,radiation_gases.f,radlw_main.F90,radlw_param.f,radsw_main.F90,radsw_param.f,machine.F,module_ozphys.F90 ######################################################################## [ccpp-arg-table] @@ -173,27 +173,6 @@ dimensions = () type = integer intent = in -[levozp] - standard_name = number_of_levels_in_ozone_climotology_data - long_name = number of levels in ozone climotology data - units = count - dimensions = () - type = integer - intent = in -[timeozp] - standard_name = number_of_times_in_ozone_climotology_data - long_name = number of times in ozone climotology data - units = count - dimensions = () - type = integer - intent = in -[latsozp] - standard_name = number_of_latitudes_in_ozone_climotology_data - long_name = number of latitude in ozone climotology data - units = count - dimensions = () - type = integer - intent = in [icliq_sw] standard_name = control_for_shortwave_radiation_liquid_clouds long_name = sw optical property for liquid clouds @@ -530,6 +509,13 @@ dimensions = () type = integer intent = in +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed + dimensions = () + type = ty_ozphys + intent = inout [con_pi] standard_name = pi long_name = ratio of a circle's circumference to its diameter diff --git a/physics/GFS_rrtmgp_pre.F90 b/physics/GFS_rrtmgp_pre.F90 index dd72a6a1c..9dcc002a0 100644 --- a/physics/GFS_rrtmgp_pre.F90 +++ b/physics/GFS_rrtmgp_pre.F90 @@ -8,7 +8,8 @@ module GFS_rrtmgp_pre use machine, only: kind_phys use funcphys, only: fpvs use module_radiation_astronomy, only: coszmn - use module_radiation_gases, only: NF_VGAS, getgases, getozn + use module_radiation_gases, only: NF_VGAS, getgases + use module_ozphys, only: ty_ozphys use mo_gas_concentrations, only: ty_gas_concs use radiation_tools, only: check_error_msg,cmp_tlev use rrtmgp_lw_gas_optics, only: lw_gas_props @@ -117,25 +118,23 @@ subroutine GFS_rrtmgp_pre_run(me, nCol, nLev, i_o3, doSWrad, doLWrad, fhswr, fhl vmr_n2o, vmr_co2, tsfg, tsfa, qs_lay, q_lay, tv_lay, & relhum, deltaZ, deltaZc, deltaP, active_gases_array, & tsfc_radtime, coszen, coszdg, top_at_1, iSFC, iTOA, nDay, idxday, semis, & - sfc_emiss_byband, ico2, latsozc, levozc, blatc, dphiozc, con_pi, errmsg, errflg) + sfc_emiss_byband, ico2, ozphys, con_pi, errmsg, errflg) - ! Inputs + ! Inputs integer, intent(in) :: & me, & ! MPI rank nCol, & ! Number of horizontal grid points nLev, & ! Number of vertical layers ico2, & ! Flag for co2 radiation scheme - i_o3, & ! Index into tracer array for ozone - latsozc, & ! - levozc + i_o3 ! Index into tracer array for ozone + type(ty_ozphys),intent(in) :: & + ozphys logical, intent(in) :: & doSWrad, & ! Call SW radiation? doLWrad ! Call LW radiation real(kind_phys), intent(in) :: & fhswr, & ! Frequency of SW radiation call. - fhlwr, & ! Frequency of LW radiation call. - blatc, & ! - dphiozc + fhlwr ! Frequency of LW radiation call. real(kind_phys), intent(in) :: & con_g, & ! Physical constant: gravitational constant con_rd, & ! Physical constant: gas-constant for dry air @@ -353,9 +352,8 @@ subroutine GFS_rrtmgp_pre_run(me, nCol, nLev, i_o3, doSWrad, doLWrad, fhswr, fhl enddo enddo ! OR Use climatological ozone data - else - call getozn (prslk(1:NCOL,:), xlat, nCol, nLev, top_at_1, latsozc, levozc, blatc, & - dphiozc, o3_lay) + else + call ozphys%oz_clim(xlat, prslk, con_pi, o3_lay) endif ! ####################################################################################### diff --git a/physics/GFS_rrtmgp_pre.meta b/physics/GFS_rrtmgp_pre.meta index 1a96eee1b..4e2aa3a56 100644 --- a/physics/GFS_rrtmgp_pre.meta +++ b/physics/GFS_rrtmgp_pre.meta @@ -2,7 +2,7 @@ name = GFS_rrtmgp_pre type = scheme dependencies = funcphys.f90,iounitdef.f,machine.F,module_bfmicrophysics.f,physcons.F90,radcons.f90,radiation_aerosols.f - dependencies = radiation_astronomy.f,radiation_gases.f,radiation_tools.F90,rrtmg_lw_cloud_optics.F90 + dependencies = radiation_astronomy.f,radiation_gases.f,radiation_tools.F90,rrtmg_lw_cloud_optics.F90,module_ozphys.F90 ######################################################################## [ccpp-arg-table] @@ -503,35 +503,12 @@ dimensions = (horizontal_loop_extent) type = integer intent = inout -[latsozc] - standard_name = number_of_latitudes_in_ozone_climotology_data - long_name = number of latitude in ozone climotology data - units = count - dimensions = () - type = integer - intent = in -[levozc] - standard_name = number_of_levels_in_ozone_climotology_data - long_name = number of levels in ozone climotology data - units = count - dimensions = () - type = integer - intent = in -[dphiozc] - standard_name = ozone_data_parameter_1 - long_name = ozone data parameter 1 - units = none - dimensions = () - type = real - kind = kind_phys - intent = in -[blatc] - standard_name = ozone_data_parameter_2 - long_name = ozone data parameter 2 - units = none +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed dimensions = () - type = real - kind = kind_phys + type = ty_ozphys intent = in [errmsg] standard_name = ccpp_error_message diff --git a/physics/GFS_rrtmgp_setup.F90 b/physics/GFS_rrtmgp_setup.F90 index 7b5479e60..3e4f57d13 100644 --- a/physics/GFS_rrtmgp_setup.F90 +++ b/physics/GFS_rrtmgp_setup.F90 @@ -6,6 +6,7 @@ module GFS_rrtmgp_setup use module_radiation_astronomy, only : sol_init, sol_update use module_radiation_aerosols, only : aer_init, aer_update use module_radiation_gases, only : gas_init, gas_update + use module_ozphys, only : ty_ozphys implicit none public GFS_rrtmgp_setup_init, GFS_rrtmgp_setup_timestep_init, GFS_rrtmgp_setup_finalize @@ -37,7 +38,7 @@ module GFS_rrtmgp_setup subroutine GFS_rrtmgp_setup_init(do_RRTMGP, imp_physics, imp_physics_fer_hires, & imp_physics_gfdl, imp_physics_thompson, imp_physics_wsm6, imp_physics_zhao_carr, & imp_physics_zhao_carr_pdf, imp_physics_mg, si, levr, ictm, isol, ico2, iaer, & - ntcw, ntoz, iovr, latsozp, levozp, timeozp, isubc_sw, isubc_lw, lalw1bd, idate, & + ntcw, ntoz, iovr, isubc_sw, isubc_lw, lalw1bd, idate, & me, aeros_file, iaermdl, iaerflg, con_pi, con_t0c, con_c, con_boltz, con_plnk, & solar_file, con_solr_2008, con_solr_2002, co2usr_file, co2cyc_file, ipsd0, & errmsg, errflg) @@ -57,8 +58,7 @@ subroutine GFS_rrtmgp_setup_init(do_RRTMGP, imp_physics, imp_physics_fer_hires, con_pi, con_t0c, con_c, con_boltz, con_plnk, con_solr_2008, con_solr_2002 real(kind_phys), dimension(:), intent(in) :: & si - integer, intent(in) :: levr, ictm, isol, ico2, iaer, & - ntcw, ntoz, iovr, isubc_sw, isubc_lw, latsozp, levozp, timeozp, me + integer, intent(in) :: levr, ictm, isol, ico2, iaer, ntcw, ntoz, iovr, isubc_sw, isubc_lw, me logical, intent(in) :: & lalw1bd integer, intent(in), dimension(:) :: & @@ -129,8 +129,7 @@ subroutine GFS_rrtmgp_setup_init(do_RRTMGP, imp_physics, imp_physics_fer_hires, call sol_init ( me, isol, solar_file, con_solr_2008, con_solr_2002, con_pi ) call aer_init ( levr, me, iaermdl, iaerflg, lalw1bd, aeros_file, con_pi, con_t0c, & con_c, con_boltz, con_plnk, errflg, errmsg) - call gas_init ( me, co2usr_file, co2cyc_file, ico2, ictm, ntoz, con_pi, latsozp, & - levozp, timeozp, errflg, errmsg ) + call gas_init ( me, co2usr_file, co2cyc_file, ico2, ictm, con_pi, errflg, errmsg ) if ( me == 0 ) then print *,' return from rad_initialize (GFS_rrtmgp_setup_init) - after calling radinit' @@ -149,7 +148,7 @@ end subroutine GFS_rrtmgp_setup_init !! subroutine GFS_rrtmgp_setup_timestep_init (idate, jdate, deltsw, deltim, doSWrad, me, & iaermdl, aeros_file, isol, slag, sdec, cdec, solcon, con_pi, co2dat_file, & - co2gbl_file, ictm, ico2, ntoz, errmsg, errflg) + co2gbl_file, ictm, ico2, ntoz, ozphys, errmsg, errflg) ! Inputs integer, intent(in) :: idate(:) @@ -161,7 +160,7 @@ subroutine GFS_rrtmgp_setup_timestep_init (idate, jdate, deltsw, deltim, doSWrad integer, intent(in) :: me integer, intent(in) :: iaermdl,isol,ictm,ico2,ntoz character(len=26), intent(in) :: aeros_file,co2dat_file,co2gbl_file - + type(ty_ozphys),intent(inout) :: ozphys ! Outputs real(kind_phys), intent(out) :: slag real(kind_phys), intent(out) :: sdec @@ -241,8 +240,11 @@ subroutine GFS_rrtmgp_setup_timestep_init (idate, jdate, deltsw, deltim, doSWrad else lco2_chg = .false. endif - call gas_update (kyear, kmon, kday, khour, loz1st, lco2_chg, me, co2dat_file, & - co2gbl_file, ictm, ico2, ntoz, errflg, errmsg ) + call gas_update (kyear, kmon, kday, khour, lco2_chg, me, co2dat_file, co2gbl_file, ictm,& + ico2, errflg, errmsg ) + if (ntoz == 0) then + call ozphys%update_clim(kmon, kday, khour, loz1st) + endif if ( loz1st ) loz1st = .false. diff --git a/physics/GFS_rrtmgp_setup.meta b/physics/GFS_rrtmgp_setup.meta index c8ed60650..96f7e24e7 100644 --- a/physics/GFS_rrtmgp_setup.meta +++ b/physics/GFS_rrtmgp_setup.meta @@ -2,7 +2,7 @@ name = GFS_rrtmgp_setup type = scheme dependencies = iounitdef.f,machine.F,module_bfmicrophysics.f,radiation_aerosols.f,radiation_astronomy.f - dependencies = module_mp_thompson.F90,radiation_gases.f + dependencies = module_mp_thompson.F90,radiation_gases.f,module_ozphys.F90 ######################################################################## [ccpp-arg-table] @@ -266,27 +266,6 @@ dimensions = () type = integer intent = inout -[levozp] - standard_name = number_of_levels_in_ozone_climotology_data - long_name = number of levels in ozone climotology data - units = count - dimensions = () - type = integer - intent = in -[timeozp] - standard_name = number_of_times_in_ozone_climotology_data - long_name = number of times in ozone climotology data - units = count - dimensions = () - type = integer - intent = in -[latsozp] - standard_name = number_of_latitudes_in_ozone_climotology_data - long_name = number of latitude in ozone climotology data - units = count - dimensions = () - type = integer - intent = in [iaermdl] standard_name = control_for_aerosol_radiation_scheme long_name = control of aerosol scheme in radiation @@ -410,6 +389,13 @@ dimensions = () type = integer intent = in +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed + dimensions = () + type = ty_ozphys + intent = inout [iaermdl] standard_name = control_for_aerosol_radiation_scheme long_name = control of aerosol scheme in radiation diff --git a/physics/module_ozphys.F90 b/physics/module_ozphys.F90 new file mode 100644 index 000000000..966d27113 --- /dev/null +++ b/physics/module_ozphys.F90 @@ -0,0 +1,476 @@ +! ######################################################################################### +!> \section arg_table_module_ozphys Argument table +!! \htmlinclude module_ozphys.html +!! +! ######################################################################################### +module module_ozphys + use machine, only : kind_phys + use funcphys, only : fpkapx + implicit none + + public ty_ozphys + +! ######################################################################################### +!> \section arg_table_ty_ozphys Argument Table +!! \htmlinclude ty_ozphys.html +!! +!! All data field are ordered from surface-to-toa (j=1=isfc) +!! +! ######################################################################################### + type ty_ozphys + ! Prognostic ozone. + integer :: nlat !< Number of latitudes. + integer :: nlev !< Number of vertical layers. + integer :: ntime !< Number of times. + integer :: ncf !< Number of coefficients. + real(kind_phys), allocatable :: lat(:) !< Latitude. + real(kind_phys), allocatable :: pres(:) !< Pressure levels. + real(kind_phys), allocatable :: po3(:) !< Natural log pressure of levels. + real(kind_phys), allocatable :: time(:) !< Time. + real(kind_phys), allocatable :: data(:,:,:,:) !< Ozone forcing data (raw) + ! Climotological ozone. + integer :: nlatc !< Number of latitudes. + integer :: nlevc !< Number of vertical layers. + integer :: ntimec !< Number of times. + real(kind_phys) :: blatc !< Parameter for ozone climotology + real(kind_phys) :: dphiozc !< Parameter for ozone climotology + real(kind_phys), allocatable :: pkstr(:) !< + real(kind_phys), allocatable :: pstr(:) !< + real(kind_phys), allocatable :: datac(:,:,:) !< Ozone climotological data + integer :: k1oz !< Lower interpolation index in datac(dim=3), time dim + integer :: k2oz !< Upper interpolation index in datac(dim=3), time dim + real(kind_phys) :: facoz !< Parameter for ozone climotology + contains + procedure, public :: load_forcing + procedure, public :: load_clim + procedure, public :: setup_forcing + procedure, public :: update_forcing + procedure, public :: update_clim + procedure, public :: oz_prog_2015 + procedure, public :: oz_prog_2006 + procedure, public :: oz_clim + end type ty_ozphys + +contains + ! ######################################################################################### + ! Procedure (type-bound) for loading ozone forcing data. + ! ######################################################################################### + function load_forcing(this, file, fileID) result (err_message) + class(ty_ozphys), intent(inout) :: this + integer, intent(in) :: fileID + character(len=*), intent(in) :: file + character(len=128) :: err_message + integer :: i1, i2, i3 + real(kind=4), dimension(:), allocatable :: lat4, pres4, time4, tempin + real(kind=4) :: blatc4 + + ! Get dimensions from data file + open(unit=fileID,file=trim(file), form='unformatted', convert='big_endian') + read (fileID) this%ncf, this%nlat, this%nlev, this%ntime + rewind(fileID) + + allocate (this%lat(this%nlat)) + allocate (this%pres(this%nlev)) + allocate (this%po3(this%nlev)) + allocate (this%time(this%ntime+1)) + allocate (this%data(this%nlat,this%nlev,this%ncf,this%ntime)) + + allocate(lat4(this%nlat), pres4(this%nlev), time4(this%ntime+1)) + read (fileID) this%ncf, this%nlat, this%nlev, this%ntime, lat4, pres4, time4 + + ! Store + this%pres(:) = pres4(:) + this%po3(:) = log(100.0*this%pres(:)) ! from mb to ln(Pa) + this%lat(:) = lat4(:) + this%time(:) = time4(:) + deallocate(lat4, pres4, time4) + + allocate(tempin(this%nlat)) + do i1=1,this%ntime + do i2=1,this%ncf + do i3=1,this%nlev + read(fileID) tempin + this%data(:,i3,i2,i1) = tempin(:) + enddo + enddo + enddo + deallocate(tempin) + close(fileID) + + end function load_forcing + + ! ######################################################################################### + ! Procedure for setting up interpolation indices between data and model grid. + ! ######################################################################################### + subroutine setup_forcing(this, lat, idx1, idx2, idxh) + class(ty_ozphys), intent(in) :: this + real(kind_phys), intent(in) :: lat(:) + integer, intent(out) :: idx1(:), idx2(:) + real(kind_phys), intent(out) :: idxh(:) + integer :: i,j + + do j=1,size(lat) + idx2(j) = this%nlat + 1 + do i=1,this%nlat + if (lat(j) < this%lat(i)) then + idx2(j) = i + exit + endif + enddo + idx1(j) = max(idx2(j)-1,1) + idx2(j) = min(idx2(j),this%nlat) + if (idx2(j) .ne. idx1(j)) then + idxh(j) = (lat(j) - this%lat(idx1(j))) / (this%lat(idx2(j)) - this%lat(idx1(j))) + else + idxh(j) = 1.0 + endif + enddo + + end subroutine setup_forcing + + ! ######################################################################################### + ! Procedure (type-bound) for updating ozone data. + ! ######################################################################################### + subroutine update_forcing(this, idx1, idx2, idxh, rjday, idxt1, idxt2, ozpl) + class(ty_ozphys), intent(in) :: this + integer, intent(in) :: idx1(:), idx2(:) + real(kind_phys), intent(in) :: idxh(:) + real(kind_phys), intent(in) :: rjday + integer, intent(in) :: idxt1, idxt2 + real(kind_phys), intent(out) :: ozpl(:,:,:) + integer :: nc, l, j, j1, j2 + real(kind_phys) :: tem, tx1, tx2 + + tx1 = (this%time(idxt2) - rjday) / (this%time(idxt2) - this%time(idxt1)) + tx2 = 1.0 - tx1 + + do nc=1,this%ncf + do l=1,this%nlev + do j=1,size(ozpl(:,1,1)) + j1 = idx1(j) + j2 = idx2(j) + tem = 1.0 - idxh(j) + ozpl(j,l,nc) = tx1*(tem*this%data(j1,l,nc,idxt1)+idxh(j)*this%data(j2,l,nc,idxt1)) & + + tx2*(tem*this%data(j1,l,nc,idxt2)+idxh(j)*this%data(j2,l,nc,idxt2)) + enddo + enddo + enddo + + end subroutine update_forcing + + ! ######################################################################################### + ! Procedure (type-bound) for NRL prognostic ozone (2015). + ! ######################################################################################### + subroutine oz_prog_2015(this, con_1ovg, dt, p, t, dp, ozpl, oz, do3_dt_prd, do3_dt_ozmx, & + do3_dt_temp, do3_dt_ohoz) + class(ty_ozphys), intent(in) :: this + real(kind_phys),intent(in) :: & + con_1ovg ! Physical constant: One divided by gravitational acceleration (m-1 s2) + real(kind_phys), intent(in) :: & + dt ! Model timestep (sec) + real(kind_phys), intent(in), dimension(:,:) :: & + p, & ! Model Pressure (Pa) + t, & ! Model temperature (K) + dp ! Model layer thickness (Pa) + real(kind_phys), intent(in), dimension(:,:,:) :: & + ozpl ! Ozone forcing data + real(kind_phys), intent(inout), dimension(:,:) :: & + oz ! Ozone concentration updated by physics + real(kind_phys), intent(inout), dimension(:,:), pointer, optional :: & + do3_dt_prd, & ! Physics tendency: production and loss effect + do3_dt_ozmx, & ! Physics tendency: ozone mixing ratio effect + do3_dt_temp, & ! Physics tendency: temperature effect + do3_dt_ohoz ! Physics tendency: overhead ozone effect + + integer :: k, kmax, kmin, iLev, iCol, nCol, nLev, iCf + logical, dimension(size(p,1)) :: flg + real(kind_phys) :: pmax, pmin, tem, temp + real(kind_phys), dimension(size(p,1)) :: wk1, wk2, wk3, ozib + real(kind_phys), dimension(size(p,1),this%ncf) :: prod + real(kind_phys), dimension(size(p,1),size(p,2)) :: ozi + real(kind_phys), dimension(size(p,1),size(p,2)+1) :: colo3, coloz + + ! Dimensions + nCol = size(p,1) + nLev = size(p,2) + + ! Temporaries + ozi = oz + + colo3(:,nLev+1) = 0.0 + coloz(:,nLev+1) = 0.0 + + do iLev=nLev,1,-1 + pmin = 1.0e10 + pmax = -1.0e10 + + do iCol=1,nCol + wk1(iCol) = log(p(iCol,iLev)) + pmin = min(wk1(iCol), pmin) + pmax = max(wk1(iCol), pmax) + prod(iCol,:) = 0._kind_phys + enddo + kmax = 1 + kmin = 1 + do k=1,this%nlev-1 + if (pmin < this%po3(k)) kmax = k + if (pmax < this%po3(k)) kmin = k + enddo + ! + do k=kmin,kmax + temp = 1.0 / (this%po3(k) - this%po3(k+1)) + do iCol=1,nCol + flg(iCol) = .false. + if (wk1(iCol) < this%po3(k) .and. wk1(iCol) >= this%po3(k+1)) then + flg(iCol) = .true. + wk2(iCol) = (wk1(iCol) - this%po3(k+1)) * temp + wk3(iCol) = 1.0 - wk2(iCol) + endif + enddo + do iCf=1,this%ncf + do iCol=1,nCol + if (flg(iCol)) then + prod(iCol,iCf) = wk2(iCol) * ozpl(iCol,k,iCf) + wk3(iCol) * ozpl(iCol,k+1,iCf) + endif + enddo + enddo + enddo + + do iCf=1,this%ncf + do iCol=1,nCol + if (wk1(iCol) < this%po3(this%nlev)) then + prod(iCol,iCf) = ozpl(iCol,this%nlev,iCf) + endif + if (wk1(iCol) >= this%po3(1)) then + prod(iCol,iCf) = ozpl(iCol,1,iCf) + endif + enddo + enddo + do iCol=1,nCol + colo3(iCol,iLev) = colo3(iCol,iLev+1) + ozi(iCol,iLev) * dp(iCol,iLev)*con_1ovg + coloz(iCol,iLev) = coloz(iCol,iLev+1) + prod(iCol,6) * dp(iCol,iLev)*con_1ovg + prod(iCol,2) = min(prod(iCol,2), 0.0) + enddo + do iCol=1,nCol + ozib(iCol) = ozi(iCol,iLev) ! no filling + tem = prod(iCol,1) - prod(iCol,2) * prod(iCol,6) & + + prod(iCol,3) * (t(iCol,iLev) - prod(iCol,5)) & + + prod(iCol,4) * (colo3(iCol,iLev)-coloz(iCol,iLev)) + oz(iCol,iLev) = (ozib(iCol) + tem*dt) / (1.0 - prod(iCol,2)*dt) + enddo + + ! Diagnostics (optional) + if (associated(do3_dt_prd)) do3_dt_prd(:,iLev) = (prod(:,1)-prod(:,2)*prod(:,6))*dt + if (associated(do3_dt_ozmx)) do3_dt_ozmx(:,iLev) = (oz(:,iLev) - ozib(:)) + if (associated(do3_dt_temp)) do3_dt_temp(:,iLev) = prod(:,3)*(t(:,iLev)-prod(:,5))*dt + if (associated(do3_dt_ohoz)) do3_dt_ohoz(:,iLev) = prod(:,4) * (colo3(:,iLev)-coloz(:,iLev))*dt + enddo + + return + end subroutine oz_prog_2015 + + ! ######################################################################################### + ! Procedure (type-bound) for NRL prognostic ozone (2006). + ! ######################################################################################### + subroutine oz_prog_2006(this) + class(ty_ozphys), intent(in) :: this + return + end subroutine oz_prog_2006 + + ! ######################################################################################### + ! Procedure (type-bound) for NRL updating climotological ozone. + ! Build this up from getozn. + ! ######################################################################################### + subroutine oz_clim(this, lat, prslk, con_pi, oz) + class(ty_ozphys), intent(in) :: this + real(kind_phys), intent(in) :: & + con_pi ! Physics constant: Pi + real(kind_phys), intent(in), dimension(:) :: & + lat ! Grid latitude + real(kind_phys), intent(in), dimension(:,:) :: & + prslk ! Exner function + real(kind_phys), intent(out), dimension(:,:) :: & + oz ! Ozone concentration updated by climotology + + integer :: nCol, iCol, nLev, iLev, j, j1, j2, l, ll + real(kind_phys) :: elte, deglat, tem, tem1, tem2, tem3, tem4, temp + real(kind_phys), allocatable :: o3i(:,:),wk1(:) + logical :: top_at_1 + + nCol = size(prslk(:,1)) + nLev = size(prslk(1,:)) + allocate(o3i(nCol, this%nlevc),wk1(nCol)) + + ! What is vertical ordering? + top_at_1 = (prslk(1,1) .lt. prslk(1, nLev)) + + elte = this%blatc + (this%nlatc-1)*this%dphiozc + + do iCol = 1, nCol + deglat = lat(iCol) * 180.0 / con_pi + if (deglat > this%blatc .and. deglat < elte) then + tem1 = (deglat - this%blatc) / this%dphiozc + 1 + j1 = tem1 + j2 = j1 + 1 + tem1 = tem1 - j1 + elseif (deglat <= this%blatc) then + j1 = 1 + j2 = 1 + tem1 = 1.0 + elseif (deglat >= elte) then + j1 = this%nlatc + j2 = this%nlatc + tem1 = 1.0 + endif + + tem2 = 1.0 - tem1 + do j = 1, this%nlevc + tem3 = tem2*this%datac(j1,j,this%k1oz) + tem1*this%datac(j2,j,this%k1oz) + tem4 = tem2*this%datac(j1,j,this%k2oz) + tem1*this%datac(j2,j,this%k2oz) + o3i(iCol,j) = tem4*this%facoz + tem3*(1.0 - this%facoz) + enddo + enddo + + do iLev = 1, nLev + ll = iLev + if (.not. top_at_1) ll = nLev - iLev + 1 + + do iCol = 1, nCol + wk1(iCol) = prslk(iCol,ll) + enddo + + do j = 1, this%nlevc-1 + temp = 1.0 / (this%pkstr(j+1) - this%pkstr(j)) + do iCol = 1, nCol + if (wk1(iCol) > this%pkstr(j) .and. wk1(iCol) <= this%pkstr(j+1)) then + tem = (this%pkstr(j+1) - wk1(iCol)) * temp + oz(iCol,ll) = tem * o3i(iCol,j) + (1.0 - tem) * o3i(iCol,j+1) + endif + enddo + enddo + + do iCol = 1, nCol + if (wk1(iCol) > this%pkstr(this%nlevc)) oz(iCol,ll) = o3i(iCol,this%nlevc) + if (wk1(iCol) < this%pkstr(1)) oz(iCol,ll) = o3i(iCol,1) + enddo + enddo + + return + end subroutine oz_clim + + ! ######################################################################################### + ! Procedure (type-bound) for loading ozone climo data. + ! ######################################################################################### + function load_clim(this, file, fileID) result (err_message) + class(ty_ozphys), intent(inout) :: this + integer, intent(in) :: fileID + character(len=*), intent(in) :: file + character(len=128) :: err_message + + ! Locals + real(kind=4) :: blatc4 + integer :: iLev, iLat, imo + real(kind=4), allocatable :: o3clim4(:,:,:), pstr4(:) + integer, allocatable :: imond(:), ilatt(:,:) + + open(unit=fileID,file=trim(file), form='unformatted', convert='big_endian') + read (fileID,end=101) this%nlatc, this%nlevc, this%ntimec, blatc4 +101 if (this%nlevc < 10 .or. this%nlevc > 100) then + rewind (fileID) + this%nlevc = 17 + this%nlatc = 18 + this%blatc = -85.0 + else + this%blatc = blatc4 + endif + this%nlat = 2 + this%nlev = 1 + this%ntimec = 1 + this%ncf = 0 + this%dphiozc = -(this%blatc+this%blatc)/(this%nlatc-1) + + allocate (o3clim4(this%nlatc,this%nlevc,12), pstr4(this%nlevc), imond(12), ilatt(this%nlatc,12) ) + + allocate (this%pkstr(this%nlevc), this%pstr(this%nlevc), this%datac(this%nlatc,this%nlevc,12)) + if ( this%nlevc == 17 ) then ! For the operational ozone climatology + do iLev = 1, this%nlevc + read (fileID,15) pstr4(iLev) +15 format(f10.3) + enddo + + do imo = 1, 12 + do iLat = 1, this%nlatc + read (fileID,16) imond(imo), ilatt(iLat,imo), (o3clim4(iLat,iLev,imo),iLev=1,10) +16 format(i2,i4,10f6.2) + read (fileID,20) (o3clim4(iLat,iLev,imo),iLev=11,this%nlevc) +20 format(6x,10f6.2) + enddo + enddo + else ! For newer ozone climatology + read (fileID) + do iLev = 1, this%nlevc + read (fileID) pstr4(iLev) + enddo + + do imo = 1, 12 + do iLev = 1, this%nlevc + read (fileID) (o3clim4(iLat,iLev,imo),iLat=1,this%nlatc) + enddo + enddo + endif ! end if_this%nlevc_block + + do imo = 1, 12 + do iLev = 1, this%nlevc + do iLat = 1, this%nlatc + this%datac(iLat,iLev,imo) = o3clim4(iLat,iLev,imo) * 1.655e-6 + enddo + enddo + enddo + + do iLev = 1, this%nlevc + this%pstr(iLev) = pstr4(iLev) + this%pkstr(iLev) = fpkapx(this%pstr(iLev)*100.0) + enddo + + end function load_clim + + ! ######################################################################################### + ! Procedure (type-bound) for updating ozone climotological data. + ! ######################################################################################### + subroutine update_clim(this, imon, iday, ihour, loz1st) + class(ty_ozphys), intent(inout) :: this + integer, intent(in) :: imon, iday, ihour + logical, intent(in) :: loz1st + + integer :: midmon=15, midm=15, midp=45, id + integer, parameter, dimension(13) :: mdays = (/31,28,31,30,31,30,31,31,30,31,30,31,30/) + logical :: change + + midmon = mdays(imon)/2 + 1 + change = loz1st .or. ( (iday==midmon) .and. (ihour==0) ) + + if ( change ) then + if ( iday < midmon ) then + this%k1oz = mod(imon+10, 12) + 1 + midm = mdays(this%k1oz)/2 + 1 + this%k2oz = imon + midp = mdays(this%k1oz) + midmon + else + this%k1oz = imon + midm = midmon + this%k2oz = mod(imon, 12) + 1 + midp = mdays(this%k2oz)/2 + 1 + mdays(this%k1oz) + endif + endif + + if (iday < midmon) then + id = iday + mdays(this%k1oz) + else + id = iday + endif + + this%facoz = float(id - midm) / float(midp - midm) + + end subroutine update_clim + +end module module_ozphys diff --git a/physics/module_ozphys.meta b/physics/module_ozphys.meta new file mode 100644 index 000000000..2922d16d7 --- /dev/null +++ b/physics/module_ozphys.meta @@ -0,0 +1,24 @@ +[ccpp-table-properties] + name = ty_ozphys + type = ddt + dependencies = + +[ccpp-arg-table] + name = ty_ozphys + type = ddt + +######################################################################## +[ccpp-table-properties] + name = module_ozphys + type = module + dependencies = machine.F,funcphys.f90 + +[ccpp-arg-table] + name = module_ozphys + type = module +[ty_ozphys] + standard_name = ty_ozphys + long_name = definition of type ty_ozphys + units = DDT + dimensions = () + type = ty_ozphys \ No newline at end of file diff --git a/physics/ozphys_2015.F90 b/physics/ozphys_2015.F90 index 47386bd6e..1478d0d6e 100644 --- a/physics/ozphys_2015.F90 +++ b/physics/ozphys_2015.F90 @@ -3,89 +3,57 @@ !! ! ########################################################################################### module ozphys_2015 - use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec + use machine, only: kind_phys, kind_dbl_prec, kind_sngl_prec + use module_ozphys, only: ty_ozphys implicit none - public ozphys_2015_init, ozphys_2015_run + public ozphys_2015_run contains ! ########################################################################################### !>\defgroup GFS_ozphys_2015 GFS Ozone Photochemistry (2015) Module !! This module contains the CCPP-compliant Ozone 2015 photochemistry scheme. !> @{ -!> The operational GFS currently parameterizes ozone production and -!! destruction based on monthly mean coefficients ( -!! \c ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77) provided by Naval -!! Research Laboratory through CHEM2D chemistry model +!> The operational GFS currently parameterizes ozone production and destruction based on +!! monthly mean coefficients ( \c ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77) provided by +!! Naval Research Laboratory through CHEM2D chemistry model !! (McCormack et al. (2006) \cite mccormack_et_al_2006). !! (https://doi.org/10.5194/acp-6-4943-2006) !! !> \section genal_ozphys_2015 GFS ozphys_2015_run General Algorithm -!> - This code assumes that both prsl and po3 are from bottom to top -!! as are all other variables. -!> - This code is specifically for NRL parameterization and -!! climatological T and O3 are in location 5 and 6 of oz_data array +!> - This code assumes that both 2D fields are ordered from bottom to top. +!> - This code is specifically for NRL parameterization and climatological T and O3 are in +! location 5 and 6 of ozpl array !!\author June 2015 - Shrinivas Moorthi !!\modified May 2023 - Dustin Swales ! ########################################################################################### -! ########################################################################################### -! SUBROUTINE ozphys_2015_init -! ########################################################################################### -!! \section arg_table_ozphys_2015_init Argument Table -!! \htmlinclude ozphys_2015_init.html -!! - subroutine ozphys_2015_init(oz_phys, errmsg, errflg) - ! Inputs - logical, intent(in) :: & - oz_phys - ! Outputs - character(len=*), intent(out) :: & - errmsg - integer, intent(out) :: & - errflg - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - ! Sanity check - if (.not.oz_phys) then - write (errmsg,'(*(a))') 'Logic error: oz_phys_2015 == .false.' - errflg = 1 - return - endif - - end subroutine ozphys_2015_init - ! ########################################################################################### ! SUBROUTINE ozphys_2015_run ! ########################################################################################### !! \section arg_table_ozphys_2015_run Argument Table !! \htmlinclude ozphys_2015_run.html !! - subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_data, & - pl_coeff, delp, con_1ovg, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, errmsg, errflg) + subroutine ozphys_2015_run (oz_phys, ozphys, nCol, nLev, dt, oz, tin, prsl, ozpl, & + delp, con_1ovg, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, errmsg, errflg) ! Inputs logical, intent(in) :: & oz_phys ! Flag for ozone_physics_2015 scheme. + type(ty_ozphys),intent(in) :: & + ozphys real(kind_phys),intent(in) :: & con_1ovg ! Physical constant: One divided by gravitational acceleration (m-1 s2) integer, intent(in) :: & - im, & ! Horizontal dimension - levs, & ! Number of vertical layers - ko3, & ! Number of vertical layers in ozone forcing data - pl_coeff ! Number of coefficients in ozone forcing data + nCol, & ! Horizontal dimension + nLev ! Number of vertical layers real(kind_phys), intent(in) :: & dt ! Physics timestep (seconds) - real(kind_phys), intent(in), dimension(:) :: & - po3 ! Natural log of ozone forcing data pressure levels real(kind_phys), intent(in), dimension(:,:) :: & prsl, & ! Air-pressure (Pa) tin, & ! Temperature of new-state (K) delp ! Difference between mid-layer pressures (Pa) real(kind_phys), intent(in), dimension(:,:,:) :: & - oz_data ! Ozone forcing data + ozpl ! Ozone forcing data ! Outputs (optional) real(kind=kind_phys), intent(inout), dimension(:,:), pointer, optional :: & @@ -96,26 +64,26 @@ subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_d ! Outputs real(kind=kind_phys), intent(inout), dimension(:,:) :: & - oz ! Ozone concentration updated by physics + oz ! Ozone concentration updated by physics character(len=*), intent(out) :: & - errmsg ! CCPP error message + errmsg ! CCPP error message integer, intent(out) :: & - errflg ! CCPP error flag + errflg ! CCPP error flag ! Locals integer :: k, kmax, kmin, l, i, j - logical, dimension(im) :: flg + logical, dimension(nCol) :: flg real(kind_phys) :: pmax, pmin, tem, temp - real(kind_phys), dimension(im) :: wk1, wk2, wk3, ozib - real(kind_phys), dimension(im,pl_coeff) :: prod - real(kind_phys), dimension(im,levs) :: ozi - real(kind_phys), dimension(im,levs+1) :: colo3, coloz + real(kind_phys), dimension(nCol) :: wk1, wk2, wk3, ozib + real(kind_phys), dimension(nCol,ozphys%ncf) :: prod + real(kind_phys), dimension(nCol,nLev) :: ozi + real(kind_phys), dimension(nCol,nLev+1) :: colo3, coloz ! Initialize CCPP error handling variables errmsg = '' errflg = 0 - ! Sanity checkt + ! Sanity checks if (.not.oz_phys) then write (errmsg,'(*(a))') 'Logic error: oz_phys_2015 == .false.' errflg = 1 @@ -125,14 +93,14 @@ subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_d ! Temporaries ozi = oz - colo3(:,levs+1) = 0.0 - coloz(:,levs+1) = 0.0 + colo3(:,nLev+1) = 0.0 + coloz(:,nLev+1) = 0.0 - do l=levs,1,-1 + do l=nLev,1,-1 pmin = 1.0e10 pmax = -1.0e10 - do i=1,im + do i=1,nCol wk1(i) = log(prsl(i,l)) pmin = min(wk1(i), pmin) pmax = max(wk1(i), pmax) @@ -140,46 +108,46 @@ subroutine ozphys_2015_run (oz_phys, im, levs, ko3, dt, oz, tin, po3, prsl, oz_d enddo kmax = 1 kmin = 1 - do k=1,ko3-1 - if (pmin < po3(k)) kmax = k - if (pmax < po3(k)) kmin = k + do k=1,ozphys%nlev-1 + if (pmin < ozphys%po3(k)) kmax = k + if (pmax < ozphys%po3(k)) kmin = k enddo ! do k=kmin,kmax - temp = 1.0 / (po3(k) - po3(k+1)) - do i=1,im + temp = 1.0 / (ozphys%po3(k) - ozphys%po3(k+1)) + do i=1,nCol flg(i) = .false. - if (wk1(i) < po3(k) .and. wk1(i) >= po3(k+1)) then + if (wk1(i) < ozphys%po3(k) .and. wk1(i) >= ozphys%po3(k+1)) then flg(i) = .true. - wk2(i) = (wk1(i) - po3(k+1)) * temp + wk2(i) = (wk1(i) - ozphys%po3(k+1)) * temp wk3(i) = 1.0 - wk2(i) endif enddo - do j=1,pl_coeff - do i=1,im + do j=1,ozphys%ncf + do i=1,nCol if (flg(i)) then - prod(i,j) = wk2(i) * oz_data(i,k,j) + wk3(i) * oz_data(i,k+1,j) + prod(i,j) = wk2(i) * ozpl(i,k,j) + wk3(i) * ozpl(i,k+1,j) endif enddo enddo enddo - do j=1,pl_coeff - do i=1,im - if (wk1(i) < po3(ko3)) then - prod(i,j) = oz_data(i,ko3,j) + do j=1,ozphys%ncf + do i=1,nCol + if (wk1(i) < ozphys%po3(ozphys%nlev)) then + prod(i,j) = ozpl(i,ozphys%nlev,j) endif - if (wk1(i) >= po3(1)) then - prod(i,j) = oz_data(i,1,j) + if (wk1(i) >= ozphys%po3(1)) then + prod(i,j) = ozpl(i,1,j) endif enddo enddo - do i=1,im + do i=1,nCol colo3(i,l) = colo3(i,l+1) + ozi(i,l) * delp(i,l)*con_1ovg coloz(i,l) = coloz(i,l+1) + prod(i,6) * delp(i,l)*con_1ovg prod(i,2) = min(prod(i,2), 0.0) enddo - do i=1,im + do i=1,nCol ozib(i) = ozi(i,l) ! no filling tem = prod(i,1) - prod(i,2) * prod(i,6) + prod(i,3) * (tin(i,l) - prod(i,5)) & + prod(i,4) * (colo3(i,l)-coloz(i,l)) diff --git a/physics/ozphys_2015.meta b/physics/ozphys_2015.meta index 1d8fba74e..ca2d56e4e 100644 --- a/physics/ozphys_2015.meta +++ b/physics/ozphys_2015.meta @@ -1,11 +1,11 @@ [ccpp-table-properties] name = ozphys_2015 type = scheme - dependencies = machine.F + dependencies = machine.F,module_ozphys.F90 ######################################################################## [ccpp-arg-table] - name = ozphys_2015_init + name = ozphys_2015_run type = scheme [oz_phys] standard_name = flag_for_nrl_2015_ozone_scheme @@ -14,54 +14,27 @@ dimensions = () type = logical intent = in -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - -######################################################################## -[ccpp-arg-table] - name = ozphys_2015_run - type = scheme -[oz_phys] - standard_name = flag_for_nrl_2015_ozone_scheme - long_name = flag for new (2015) ozone physics - units = flag +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed dimensions = () - type = logical + type = ty_ozphys intent = in -[im] +[nCol] standard_name = horizontal_loop_extent long_name = horizontal loop extent units = count dimensions = () type = integer intent = in -[levs] +[nLev] standard_name = vertical_layer_dimension long_name = number of vertical layers units = count dimensions = () type = integer intent = in -[ko3] - standard_name = number_of_levels_in_ozone_data - long_name = number of vertical layers in ozone forcing data - units = count - dimensions = () - type = integer - intent = in [dt] standard_name = timestep_for_physics long_name = physics time step @@ -86,14 +59,6 @@ type = real kind = kind_phys intent = in -[po3] - standard_name = natural_log_of_ozone_data_pressure_levels - long_name = natural log of ozone forcing data pressure levels - units = 1 - dimensions = (number_of_levels_in_ozone_data) - type = real - kind = kind_phys - intent = in [prsl] standard_name = air_pressure long_name = mid-layer pressure @@ -102,7 +67,7 @@ type = real kind = kind_phys intent = in -[oz_data] +[ozpl] standard_name = ozone_forcing long_name = ozone forcing data units = mixed @@ -110,13 +75,6 @@ type = real kind = kind_phys intent = in -[pl_coeff] - standard_name = number_of_coefficients_in_ozone_data - long_name = number of coefficients in ozone forcing data - units = count - dimensions = () - type = integer - intent = in [delp] standard_name = air_pressure_difference_between_midlayers long_name = difference between mid-layer pressures diff --git a/physics/ozphys_time_vary.F90 b/physics/ozphys_time_vary.F90 deleted file mode 100644 index ddac1dcd4..000000000 --- a/physics/ozphys_time_vary.F90 +++ /dev/null @@ -1,165 +0,0 @@ -! ########################################################################################### -!> \file ozphys_time_vary.F90 -!! -! ########################################################################################### -module ozphys_time_vary - use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec - implicit none - public ozphys_time_vary_init, ozphys_time_vary_timestep_init -contains - -! ########################################################################################### -!>\defgroup GFS Ozone Data Module -!! This module updates the ozone data used by physics. -!> @{ -!> \section arg_table_ozphys_time_vary_init Argument Table -!! \htmlinclude ozphys_time_vary_init.html -!! -! ########################################################################################### - subroutine ozphys_time_vary_init(nPts, latsozp, oz_lat, dlat, jindx1, jindx2, ddy, & - errmsg, errflg) - ! Inputs - integer, intent(in) :: & - nPts, & ! Horizontal dimension - latsozp ! Number of latitudes in ozone data - real(kind_phys), intent(in), dimension(:) :: & - oz_lat, & ! Latitudes of ozone data - dlat ! Latitudes of grid - ! Outputs - integer, intent(inout), dimension(:) :: & - jindx1, & ! Interpolation index (low) for ozone data - jindx2 ! Interpolation index (high) for ozone data - real(kind_phys), intent(inout), dimension(:) :: & - ddy ! Interpolation high index for ozone data - character(len=*), intent(out) :: & - errmsg ! CCPP error message - integer, intent(out) :: & - errflg ! CCPP error flag - - ! Local - integer i,j - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - ! Set indices - do j=1,nPts - jindx2(j) = latsozp + 1 - do i=1,latsozp - if (dlat(j) < oz_lat(i)) then - jindx2(j) = i - exit - endif - enddo - jindx1(j) = max(jindx2(j)-1,1) - jindx2(j) = min(jindx2(j),latsozp) - if (jindx2(j) .ne. jindx1(j)) then - ddy(j) = (dlat(j) - oz_lat(jindx1(j))) / (oz_lat(jindx2(j)) - oz_lat(jindx1(j))) - else - ddy(j) = 1.0 - endif - enddo - - end subroutine ozphys_time_vary_init - -! ########################################################################################### -!> \section arg_table_ozphys_time_vary_timestep_init Argument Table -!! \htmlinclude ozphys_time_vary_timestep_init.html -!! -! ########################################################################################### - subroutine ozphys_time_vary_timestep_init(nPts, idate, fhour, jindx1, jindx2, latsozp, & - levozp, oz_coeff, timeoz, ozplin, oz_time, oz_lat, ddy, oz_data, errmsg, errflg) - ! Inputs - integer, intent(in) :: & - nPts, & ! Horizontal dimension - latsozp, & ! Number of latitudes in ozone data - levozp, & ! Number of vertical layers in ozone data - oz_coeff, & ! Number of coefficients in ozone data - timeoz ! Number of times in ozone data - integer, intent(in),dimension(:) :: & - idate, & ! Initial date with different size and ordering - jindx1, & ! Interpolation index (low) for ozone - jindx2 ! Interpolation index (high) for ozone - real(kind_phys), intent(in) :: & - fhour ! Forecast hour - real(kind_phys), intent(in), dimension(:) :: & - ddy, & ! Interpolation high index for ozone data - oz_lat, & ! Latitudes for ozone data - oz_time ! Time for ozone data - real(kind_phys), intent(in), dimension(:,:,:,:) :: & - ozplin ! Ozone data - - ! Outputs - real(kind_phys), intent(inout), dimension(:,:,:) :: & - oz_data ! Ozone forcing data - character(len=*), intent(out) :: & - errmsg ! CCPP error message - integer, intent(out) :: & - errflg ! CCPP error flag - - ! Local - integer :: idat(8),jdat(8),iday,j,j1,j2,l,nc,n1,n2,jdow,jdoy,& - jday,w3kindreal,w3kindint - real(kind_phys) :: tem, tx1, tx2, rjday - real(kind_dbl_prec) :: rinc(5) - real(kind_sngl_prec) :: rinc4(5) - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - ! - idat=0 - idat(1)=idate(4) - idat(2)=idate(2) - idat(3)=idate(3) - idat(5)=idate(1) - rinc=0. - rinc(2)=fhour - call w3kind(w3kindreal,w3kindint) - if(w3kindreal==4) then - rinc4=rinc - CALL w3movdat(rinc4,idat,jdat) - else - CALL w3movdat(rinc,idat,jdat) - endif - ! - jdow = 0 - jdoy = 0 - jday = 0 - call w3doxdat(jdat,jdow,jdoy,jday) - rjday = jdoy + jdat(5) / 24. - IF (RJDAY < oz_time(1)) RJDAY = RJDAY + 365. - ! - n2 = timeoz + 1 - do j=2,timeoz - if (rjday < oz_time(j)) then - n2 = j - exit - endif - enddo - n1 = n2 - 1 - - tx1 = (oz_time(n2) - rjday) / (oz_time(n2) - oz_time(n1)) - tx2 = 1.0 - tx1 - - if (n2 > timeoz) n2 = n2 - timeoz - ! - do nc=1,oz_coeff - do L=1,levozp - do J=1,npts - J1 = jindx1(J) - J2 = jindx2(J) - TEM = 1.0 - ddy(J) - oz_data(j,L,nc) = tx1*(TEM*ozplin(J1,L,nc,n1)+ddy(J)*ozplin(J2,L,nc,n1)) & - + tx2*(TEM*ozplin(J1,L,nc,n2)+ddy(J)*ozplin(J2,L,nc,n2)) - enddo - enddo - enddo - - return - - end subroutine ozphys_time_vary_timestep_init -!> @} -end module ozphys_time_vary diff --git a/physics/ozphys_time_vary.meta b/physics/ozphys_time_vary.meta deleted file mode 100644 index 75b8b8e4f..000000000 --- a/physics/ozphys_time_vary.meta +++ /dev/null @@ -1,200 +0,0 @@ -[ccpp-table-properties] - name = ozphys_time_vary - type = scheme - dependencies = machine.F - -######################################################################## -[ccpp-arg-table] - name = ozphys_time_vary_init - type = scheme -[nPts] - standard_name = horizontal_dimension - long_name = horizontal dimension - units = count - dimensions = () - type = integer - intent = in -[latsozp] - standard_name = number_of_latitudes_in_ozone_data - long_name = number of latitude in ozone data - units = count - dimensions = () - type = integer - intent = in -[oz_lat] - standard_name = ozone_data_latitude - long_name = ozone data latitude - units = deg - dimensions = (number_of_latitudes_in_ozone_data) - type = real - kind = kind_phys - intent = in -[dlat] - standard_name = latitude_in_degree - long_name = latitude in degree north - units = degree_north - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = in -[jindx1] - standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation low index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = inout -[jindx2] - standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation high index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = inout -[ddy] - standard_name = latitude_interpolation_weight_for_ozone_forcing - long_name = interpolation high index for ozone - units = none - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = inout -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - -######################################################################## -[ccpp-arg-table] - name = ozphys_time_vary_timestep_init - type = scheme -[nPts] - standard_name = horizontal_dimension - long_name = horizontal dimension - units = count - dimensions = () - type = integer - intent = in -[idate] - standard_name = date_and_time_at_model_initialization_in_united_states_order - long_name = initial date with different size and ordering - units = none - dimensions = (4) - type = integer - intent = in -[fhour] - standard_name = forecast_time - long_name = current forecast time - units = h - dimensions = () - type = real - kind = kind_phys - intent = in -[jindx1] - standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation low index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[jindx2] - standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation high index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[latsozp] - standard_name = number_of_latitudes_in_ozone_data - long_name = number of latitude in ozone data - units = count - dimensions = () - type = integer - intent = in -[levozp] - standard_name = number_of_levels_in_ozone_data - long_name = number of levels in ozone data - units = count - dimensions = () - type = integer - intent = in -[oz_coeff] - standard_name = number_of_coefficients_in_ozone_data - long_name = number of coefficients in ozone data - units = count - dimensions = () - type = integer - intent = in -[timeoz] - standard_name = number_of_times_in_ozone_data - long_name = number of times in ozone data - units = count - dimensions = () - type = integer - intent = in -[ozplin] - standard_name = ozone_data - long_name = ozone data - units = 1 - dimensions = (number_of_latitudes_in_ozone_data,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data,number_of_times_in_ozone_data) - type = real - kind = kind_phys - intent = in -[oz_time] - standard_name = ozone_data_time - long_name = ozone data time - units = none - dimensions = (13) - type = real - kind = kind_phys - intent = in -[oz_lat] - standard_name = ozone_data_latitude - long_name = ozone data latitude - units = deg - dimensions = (number_of_latitudes_in_ozone_data) - type = real - kind = kind_phys - intent = in -[ddy] - standard_name = latitude_interpolation_weight_for_ozone_forcing - long_name = interpolation high index for ozone - units = none - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = in -[oz_data] - standard_name = ozone_forcing - long_name = ozone forcing data - units = mixed - dimensions = (horizontal_dimension,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) - type = real - kind = kind_phys - intent = inout -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out diff --git a/physics/radiation_gases.f b/physics/radiation_gases.f index 5f017598f..4c626b348 100644 --- a/physics/radiation_gases.f +++ b/physics/radiation_gases.f @@ -1,17 +1,14 @@ !> \file radiation_gases.f -!! This file contains routines that set up ozone climatological -!! profiles and other constant gas profiles, such as co2, ch4, n2o, -!! o2, and those of cfc gases. All data are entered as mixing ratio -!! by volume, except ozone which is mass mixing ratio (g/g). +!! This file contains routines that set up gas profiles, such as co2, +!! ch4, n2o, o2, and those of cfc gases. All data are entered as mixing +!! ratio by volume ! ========================================================== !!!!! ! 'module_radiation_gases' description !!!!! ! ========================================================== !!!!! ! ! -! set up ozone climatological profiles and other constant gas ! -! profiles, such as co2, ch4, n2o, o2, and those of cfc gases. All ! -! data are entered as mixing ratio by volume, except ozone which is ! -! mass mixing ratio (g/g). ! +! set up constant gas profiles, such as co2, ch4, n2o, o2, and those ! +! of cfc gases. All data are entered as mixing ratio by volume ! ! ! ! in the module, the externally callabe subroutines are : ! ! ! @@ -23,16 +20,10 @@ ! ! ! 'gas_update' -- read in data and update with time ! ! input: ! -! ( iyear, imon, iday, ihour, loz1st, ldoco2, me ) ! +! ( iyear, imon, iday, ihour, ldoco2, me ) ! ! output: ! ! ( errflg, errmsg ) ! ! ! -! 'getozn' -- setup climatological ozone profile ! -! input: ! -! ( prslk,xlat, ! -! IMAX, LM ) ! -! output: ! -! ( o3mmr ) ! ! ! ! 'getgases' -- setup constant gas profiles for LW and SW ! ! input: ! @@ -47,7 +38,6 @@ ! 'module module_iounitdef' in 'iounitdef.f' ! ! ! ! unit used for radiative active gases: ! -! ozone : mass mixing ratio (g/g) ! ! co2 : volume mixing ratio (p/p) ! ! n2o : volume mixing ratio (p/p) ! ! ch4 : volume mixing ratio (p/p) ! @@ -81,15 +71,6 @@ ! seasonal cycle calculations ! ! aug 2011 - y-t hou fix a bug in subr getgases doing vertical ! ! co2 mapping. (for top_at_1 case, not affact opr). ! -! aug 2012 - y-t hou modified subr getozn. moved the if-first ! -! block to subr gas_init to ensure threading safe in ! -! climatology ozone applications. (not affect gfs) ! -! also changed the initialization subr into two parts:! -! 'gas_init' is called at the start of run to set up ! -! module parameters; and 'gas_update' is called within! -! the time loop to check and update data sets. defined! -! the climatology ozone parameters k1oz,k2oz,facoz as ! -! module variables and are set in subr 'gas_update' ! ! nov 2012 - y-t hou modified control parameters thru module ! ! 'physparam'. ! ! jan 2013 - z. janjic/y. hou modified ilon (longitude index) ! @@ -105,10 +86,8 @@ !> \defgroup module_radiation_gases_mod Radiation Gases Module !> @{ -!> This module sets up ozone climatological profiles and other constant -!! gas profiles, such as co2, ch4, n2o, o2, and those of cfc gases. All -!! data are entered as mixing ratio by volume, except ozone which is -!! mass mixing ratio (g/g). +!> This module sets up constant gas profiles, such as co2, ch4, n2o, o2, +!! and those of cfc gases. All data are entered as mixing ratio by volume. !!\image html rad_gas_AGGI.png "Figure 1: Atmospheric radiative forcing, relative to 1750, by long-lived greenhouse gases and the 2016 update of the NOAA Annual Greenhouse Gas Index (AGGI)" !! NOAA Annual Greenhouse Gas Index (AGGI) shows that from 1990 to 2016, !! radiative forcing by long-lived greenhouse gases (LLGHGs) increased by @@ -121,10 +100,6 @@ !!\n ICO2=1: use observed global annual mean value !!\n ICO2=2: use observed monthly 2-d data table in \f$15^o\f$ horizontal resolution !! -!! O3 Distribution (namelist control parameter -\b NTOZ): -!!\n NTOZ=0: use seasonal and zonal averaged climatological ozone -!!\n NTOZ>0: use 3-D prognostic ozone -!! !! Trace Gases (currently using the global mean climatology in unit of ppmv): !! \f$CH_4-1.50\times10^{-6}\f$; !! \f$N_2O-0.31\times10^{-6}\f$; @@ -137,8 +112,8 @@ !! !!\version NCEP-Radiation_gases v5.1 Nov 2012 -!> This module sets up ozone climatological profiles and other constant gas -!! profiles, such as co2, ch4, n2o, o2, and those of cfc gases. +!> This module sets up constant gas rofiles, such as co2, ch4, n2o, o2, and those +!! of cfc gases. module module_radiation_gases use machine, only : kind_phys, kind_io4 use funcphys, only : fpkapx @@ -179,22 +154,8 @@ module module_radiation_gases ! gfdl 1999 value real (kind=kind_phys), parameter :: f113vmr_def= 8.2000e-11 -! --- ozone seasonal climatology parameters defined in module ozne_def -! - 4x5 ozone data parameter -! integer, parameter :: JMR=45, LOZ=17 -! real (kind=kind_phys), parameter :: blte=-86.0, dlte=4.0 -! - geos ozone data -! integer, parameter :: JMR=18, LOZ=17 -! real (kind=kind_phys), parameter :: blte=-85.0, dlte=10.0 - ! --- module variables to be set in subroutin gas_init and/or gas_update -! variables for climatology ozone (ioznflg = 0) - - real (kind=kind_phys), allocatable :: pkstr(:), o3r(:,:,:) - integer :: k1oz = 0, k2oz = 0 - real (kind=kind_phys) :: facoz = 0.0 - ! arrays for co2 2-d monthly data and global mean values from observed data real (kind=kind_phys), allocatable :: co2vmr_sav(:,:,:) @@ -209,33 +170,30 @@ module module_radiation_gases ! --- public interfaces - public gas_init, gas_update, getgases, getozn + public gas_init, gas_update, getgases ! ================= contains ! ================= -!> This subroutine sets up ozone, co2, etc. parameters. If climatology -!! ozone then read in monthly ozone data. +!> This subroutine sets up co2, etc. parameters. !!\param me print message control flag !!\param co2usr_file co2 user defined data table !!\param co2cyc_file co2 climotology monthly cycle data table !!\param ictmflg data ic time/date control flag !!\param ico2flg co2 data source control flag -!!\param ioznflg ozone data control flag !!\param con_pi physical constant Pi !!\param errflg error flag !!\param errmsg error message !>\section gas_init_gen gas_init General Algorithm !----------------------------------- subroutine gas_init( me, co2usr_file, co2cyc_file, ico2flg, & - & ictmflg, ioznflg, con_pi, JMR, LOZ, timeozc, errflg, errmsg) + & ictmflg, con_pi, errflg, errmsg) ! =================================================================== ! ! ! -! gas_init sets up ozone, co2, etc. parameters. if climatology ozone ! -! then read in monthly ozone data. ! +! gas_init sets up co2, etc. parameters. ! ! ! ! inputs: ! ! me - print message control flag ! @@ -256,9 +214,6 @@ subroutine gas_init( me, co2usr_file, co2cyc_file, ico2flg, & ! further data extrapolation. ! ! =yyyy1: use yyyy data for the fcst. if needed, do ! ! extrapolation to match the fcst time. ! -! ioznflg - ozone data control flag ! -! =0: use climatological ozone profile ! -! >0: use interactive ozone profile ! ! co2usr_file - external co2 user defined data table ! ! co2cyc_file - external co2 climotology monthly cycle data table ! ! con_pi - physical constant Pi ! @@ -267,9 +222,6 @@ subroutine gas_init( me, co2usr_file, co2cyc_file, ico2flg, & ! errflg - error flag ! ! errmsg - error message ! ! ! -! internal module variables: ! -! pkstr, o3r - arrays for climatology ozone data ! -! ! ! usage: call gas_init ! ! ! ! subprograms called: none ! @@ -279,8 +231,7 @@ subroutine gas_init( me, co2usr_file, co2cyc_file, ico2flg, & implicit none ! --- inputs: - integer, intent(in) :: me, ictmflg, ioznflg, ico2flg - integer, intent(in) :: JMR, LOZ, timeozc + integer, intent(in) :: me, ictmflg, ico2flg character(len=26),intent(in) :: co2usr_file,co2cyc_file real(kind=kind_phys), intent(in) :: con_pi @@ -291,10 +242,7 @@ subroutine gas_init( me, co2usr_file, co2cyc_file, ico2flg, & ! --- locals: real (kind=kind_phys), dimension(IMXCO2,JMXCO2) :: co2dat real (kind=kind_phys) :: co2g1, co2g2 - real (kind=kind_phys) :: pstr(LOZ) - real (kind=kind_io4) :: o3clim4(JMR,LOZ,12), pstr4(LOZ) - integer :: imond(12), ilat(JMR,12) integer :: i, j, k, iyr, imo logical :: file_exist, lextpl character :: cline*100, cform*8 @@ -316,78 +264,6 @@ subroutine gas_init( me, co2usr_file, co2cyc_file, ico2flg, & kyrsav = 0 kmonsav = 1 -! --- ... climatology ozone data section - - if ( ioznflg > 0 ) then - if ( me == 0 ) then - print *,' - Using interactive ozone distribution' - endif - else - if ( timeozc /= 12 ) then - print *,' - Using climatology ozone distribution' - print *,' timeozc=',timeozc, ' is not monthly mean', & - & ' - job aborting in subroutin gas_init!!!' - errflg = 1 - errmsg = 'ERROR(gas_init): Climatological o3 distribution '// & - & 'is not monthly mean' - return - endif - - allocate (pkstr(LOZ), o3r(JMR,LOZ,12)) - rewind NIO3CLM - - if ( LOZ == 17 ) then ! For the operational ozone climatology - do k = 1, LOZ - read (NIO3CLM,15) pstr4(k) - 15 format(f10.3) - enddo - - do imo = 1, 12 - do j = 1, JMR - read (NIO3CLM,16) imond(imo), ilat(j,imo), & - & (o3clim4(j,k,imo),k=1,10) - 16 format(i2,i4,10f6.2) - read (NIO3CLM,20) (o3clim4(j,k,imo),k=11,LOZ) - 20 format(6x,10f6.2) - enddo - enddo - else ! For newer ozone climatology - read (NIO3CLM) - do k = 1, LOZ - read (NIO3CLM) pstr4(k) - enddo - - do imo = 1, 12 - do k = 1, LOZ - read (NIO3CLM) (o3clim4(j,k,imo),j=1,JMR) - enddo - enddo - endif ! end if_LOZ_block -! - do imo = 1, 12 - do k = 1, LOZ - do j = 1, JMR - o3r(j,k,imo) = o3clim4(j,k,imo) * 1.655e-6 - enddo - enddo - enddo - - do k = 1, LOZ - pstr(k) = pstr4(k) - enddo - - if ( me == 0 ) then - print *,' - Using climatology ozone distribution' - print *,' Found ozone data for levels pstr=', & - & (pstr(k),k=1,LOZ) -! print *,' O3=',(o3r(15,k,1),k=1,LOZ) - endif - - do k = 1, LOZ - pkstr(k) = fpkapx(pstr(k)*100.0) - enddo - endif ! end if_ioznflg_block - ! --- ... co2 data section co2_glb = co2vmr_def @@ -541,20 +417,18 @@ end subroutine gas_init !!\param imon month of the year !!\param iday day of the month !!\param ihour hour of the day -!!\param loz1st clim ozone 1st time update control flag !!\param ldoco2 co2 update control flag !!\param me print message control flag !!\param co2dat_file co2 2d monthly obsv data table !!\param co2gbl_file co2 global annual mean data table !!\param ictmflg data ic time/date control flag !!\param ico2flg co2 data source control flag -!!\param ioznflg ozone data control flag !!\param errflg error flag !!\param errmsg error message !>\section gen_gas_update gas_update General Algorithm !----------------------------------- - subroutine gas_update(iyear, imon, iday, ihour, loz1st, ldoco2, & - & me, co2dat_file, co2gbl_file, ictmflg, ico2flg, ioznflg, & + subroutine gas_update(iyear, imon, iday, ihour, ldoco2, & + & me, co2dat_file, co2gbl_file, ictmflg, ico2flg, & & errflg, errmsg ) ! =================================================================== ! @@ -567,7 +441,6 @@ subroutine gas_update(iyear, imon, iday, ihour, loz1st, ldoco2, & ! imon - month of the year 1 ! ! iday - day of the month 1 ! ! ihour - hour of the day 1 ! -! loz1st - clim ozone 1st time update control flag 1 ! ! ldoco2 - co2 update control flag 1 ! ! me - print message control flag 1 ! ! ico2flg - co2 data source control flag ! @@ -587,9 +460,6 @@ subroutine gas_update(iyear, imon, iday, ihour, loz1st, ldoco2, & ! further data extrapolation. ! ! =yyyy1: use yyyy data for the fcst. if needed, do ! ! extrapolation to match the fcst time. ! -! ioznflg - ozone data control flag ! -! =0: use climatological ozone profile ! -! >0: use interactive ozone profile ! ! ivflip - vertical profile indexing flag ! ! co2dat_file - external co2 2d monthly obsv data table ! ! co2gbl_file - external co2 global annual mean data table ! @@ -603,8 +473,6 @@ subroutine gas_update(iyear, imon, iday, ihour, loz1st, ldoco2, & ! co2cyc_sav - monthly cycle co2 vol mixing ratio IMXCO2*JMXCO2*12 ! ! co2_glb - global annual mean co2 mixing ratio ! ! gco2cyc - global monthly mean co2 variation 12 ! -! k1oz,k2oz,facoz ! -! - climatology ozone parameters 1 ! ! ! ! usage: call gas_update ! ! ! @@ -616,9 +484,8 @@ subroutine gas_update(iyear, imon, iday, ihour, loz1st, ldoco2, & ! --- inputs: integer, intent(in) :: iyear,imon,iday,ihour,me,ictmflg,ico2flg - integer, intent(in) :: ioznflg character(len=26),intent(in) :: co2dat_file, co2gbl_file - logical, intent(in) :: loz1st, ldoco2 + logical, intent(in) :: ldoco2 ! --- output: character(len=*), intent(out) :: errmsg @@ -643,35 +510,6 @@ subroutine gas_update(iyear, imon, iday, ihour, loz1st, ldoco2, & errmsg = '' errflg = 0 -!> - Ozone data section - - if ( ioznflg == 0 ) then - midmon = mdays(imon)/2 + 1 - change = loz1st .or. ( (iday==midmon) .and. (ihour==0) ) -! - if ( change ) then - if ( iday < midmon ) then - k1oz = mod(imon+10, 12) + 1 - midm = mdays(k1oz)/2 + 1 - k2oz = imon - midp = mdays(k1oz) + midmon - else - k1oz = imon - midm = midmon - k2oz = mod(imon, 12) + 1 - midp = mdays(k2oz)/2 + 1 + mdays(k1oz) - endif - endif -! - if (iday < midmon) then - id = iday + mdays(k1oz) - else - id = iday - endif - - facoz = float(id - midm) / float(midp - midm) - endif - !> - co2 data section if ( ico2flg == 0 ) return ! use prescribed global mean co2 data @@ -1103,121 +941,6 @@ subroutine getgases( plvl, xlon, xlat, IMAX, LMAX, ico2flg, & end subroutine getgases !----------------------------------- -!> This subroutine sets up climatological ozone profile for radiation -!! calculation. This code is originally written by Shrinivas Moorthi. -!!\param prslk (IMAX,LM), exner function = \f$(p/p0)^{rocp}\f$ -!!\param xlat (IMAX), latitude in radians, default to pi/2 -> -!! -pi/2 range, otherwise see in-line comment -!!\param IMAX, LM (1), horizontal and vertical dimensions -!!\param top_at_1 (1), vertical profile indexing flag -!!\param o3mmr (IMAX,LM), output ozone profile in mass mixing -!! ratio (g/g) -!>\section getozn_gen getozn General Algorithm -!----------------------------------- - subroutine getozn( prslk,xlat, IMAX, LM, top_at_1, JMR, LOZ, blte,& - & dlte, o3mmr) - -! =================================================================== ! -! ! -! getozn sets up climatological ozone profile for radiation calculation! -! ! -! this code is originally written By Shrinivas Moorthi ! -! ! -! inputs: ! -! prslk (IMAX,LM) - exner function = (p/p0)**rocp ! -! xlat (IMAX) - latitude in radians, default to pi/2 -> -pi/2 ! -! range, otherwise see in-line comment ! -! IMAX, LM - horizontal and vertical dimensions ! -! top_at_1 - vertical profile indexing flag ! -! ! -! outputs: ! -! o3mmr (IMAX,LM) - output ozone profile in mass mixing ratio (g/g)! -! ! -! module variables: ! -! k1oz, k2oz - ozone data interpolation indices ! -! facoz - ozone data interpolation factor ! -! ! -! usage: call getozn ! -! ! -! =================================================================== ! -! - implicit none - -! --- inputs: - integer, intent(in) :: IMAX, LM, JMR, LOZ - real(kind=kind_phys), intent(in) :: blte, dlte - logical, intent(in) :: top_at_1 - real (kind=kind_phys), intent(in) :: prslk(:,:), xlat(:) - -! --- outputs: - real (kind=kind_phys), intent(out) :: o3mmr(:,:) - -! --- locals: - real (kind=kind_phys) :: o3i(IMAX,LOZ), wk1(IMAX), deglat, elte, & - & tem, tem1, tem2, tem3, tem4, temp - integer :: i, j, k, l, j1, j2, ll -! -!===> ... begin here -! - elte = blte + (JMR-1)*dlte - - do i = 1, IMAX - deglat = xlat(i) * raddeg ! if xlat in pi/2 -> -pi/2 range -! deglat = 90.0 - xlat(i)*raddeg ! if xlat in 0 -> pi range - - if (deglat > blte .and. deglat < elte) then - tem1 = (deglat - blte) / dlte + 1 - j1 = tem1 - j2 = j1 + 1 - tem1 = tem1 - j1 - elseif (deglat <= blte) then - j1 = 1 - j2 = 1 - tem1 = 1.0 - elseif (deglat >= elte) then - j1 = JMR - j2 = JMR - tem1 = 1.0 - endif - - tem2 = 1.0 - tem1 - do j = 1, LOZ - tem3 = tem2*o3r(j1,j,k1oz) + tem1*o3r(j2,j,k1oz) - tem4 = tem2*o3r(j1,j,k2oz) + tem1*o3r(j2,j,k2oz) - o3i(i,j) = tem4*facoz + tem3*(1.0 - facoz) - enddo - enddo - - do l = 1, LM - ll = l - if (.not. top_at_1) ll = LM -l + 1 - - do i = 1, IMAX - wk1(i) = prslk(i,ll) - enddo - - do k = 1, LOZ-1 - temp = 1.0 / (pkstr(k+1) - pkstr(k)) - - do i = 1, IMAX - if (wk1(i) > pkstr(k) .and. wk1(i) <= pkstr(k+1)) then - tem = (pkstr(k+1) - wk1(i)) * temp - o3mmr(I,ll) = tem * o3i(i,k) + (1.0 - tem) * o3i(i,k+1) - endif - enddo - enddo - - do i = 1, IMAX - if (wk1(i) > pkstr(LOZ)) o3mmr(i,ll) = o3i(i,LOZ) - if (wk1(i) < pkstr(1)) o3mmr(i,ll) = o3i(i,1) - enddo - enddo -! - return -!................................... - end subroutine getozn -!----------------------------------- - ! !........................................! end module module_radiation_gases ! diff --git a/physics/rrtmgp_lw_main.F90 b/physics/rrtmgp_lw_main.F90 index 67f7f749a..01b25c925 100644 --- a/physics/rrtmgp_lw_main.F90 +++ b/physics/rrtmgp_lw_main.F90 @@ -19,7 +19,6 @@ module rrtmgp_lw_main use rrtmgp_lw_gas_optics, only: lw_gas_props,rrtmgp_lw_gas_optics_init use rrtmgp_lw_cloud_optics, only: lw_cloud_props, rrtmgp_lw_cloud_optics_init, abssnow0, & abssnow1, absrain - use module_radiation_gases, only: NF_VGAS, getgases, getozn use GFS_rrtmgp_pre, only: iStr_h2o, iStr_co2, iStr_o3, iStr_n2o, iStr_ch4, & iStr_o2, iStr_ccl4, iStr_cfc11, iStr_cfc12, iStr_cfc22, & eps, oneminus, ftiny From 2886df96f645f9366d7d0496ac654fc178264e7d Mon Sep 17 00:00:00 2001 From: dustinswales Date: Wed, 27 Sep 2023 14:23:36 -0600 Subject: [PATCH 11/25] Small cosmetic changes --- physics/GFS_phys_time_vary.fv3.F90 | 53 ++++++++++++++---------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/physics/GFS_phys_time_vary.fv3.F90 b/physics/GFS_phys_time_vary.fv3.F90 index af2dd9b00..f72763c3a 100644 --- a/physics/GFS_phys_time_vary.fv3.F90 +++ b/physics/GFS_phys_time_vary.fv3.F90 @@ -219,14 +219,6 @@ subroutine GFS_phys_time_vary_init ( !$OMP sections -!$OMP section -!> - Setup spatial interpolation indices for ozone physics. - if (ntoz > 0) then - !$OMP CRITICAL - call ozphys%setup_forcing(xlat_d, jindx1_o3, jindx2_o3, ddy_o3) - !$OMP END CRITICAL - endif - !$OMP section !> - Call read_h2odata() to read stratospheric water vapor data call read_h2odata (h2o_phys, me, master) @@ -294,6 +286,12 @@ subroutine GFS_phys_time_vary_init ( !$OMP sections +!$OMP section +!> - Setup spatial interpolation indices for ozone physics. + if (ntoz > 0) then + call ozphys%setup_forcing(xlat_d, jindx1_o3, jindx2_o3, ddy_o3) + endif + !$OMP section !> - Call setindxh2o() to initialize stratospheric water vapor data if (h2o_phys) then @@ -803,21 +801,7 @@ subroutine GFS_phys_time_vary_timestep_init ( return end if -!$OMP parallel num_threads(nthrds) default(none) & -!$OMP shared(kdt,nsswr,lsswr,clstp,imfdeepcnv,cal_pre,random_clds) & -!$OMP shared(fhswr,fhour,seed0,cnx,cny,nrcm,wrk,rannie,rndval) & -!$OMP shared(rann,im,isc,jsc,imap,jmap,ntoz,me,idate,jindx1_o3,jindx2_o3) & -!$OMP shared(ozpl,ddy_o3,h2o_phys,jindx1_h,jindx2_h,h2opl,ddy_h,iaerclm,master) & -!$OMP shared(levs,prsl,iccn,jindx1_ci,jindx2_ci,ddy_ci,iindx1_ci,iindx2_ci) & -!$OMP shared(ddx_ci,in_nm,ccn_nm,do_ugwp_v1,jindx1_tau,jindx2_tau,ddy_j1tau) & -!$OMP shared(ddy_j2tau,tau_amf,iflip,ozphys) & -!$OMP private(iseed,iskip,i,j,rjday,idat,rinc,w3kindreal,w3kindint,jdat)& -!$OMP private(jdow,jdoy,jday,rinc4,n1,n2) - -!$OMP sections - -!$OMP section -!> - Compute temporal interpolation indices for updating gas concentrations. + !> - Compute temporal interpolation indices for updating gas concentrations. idat=0 idat(1)=idate(4) idat(2)=idate(2) @@ -849,12 +833,17 @@ subroutine GFS_phys_time_vary_timestep_init ( n1 = n2 - 1 if (n2 > ozphys%ntime) n2 = n2 - ozphys%ntime - !> - Update ozone concentration. - if (ntoz > 0) then - !$OMP CRITICAL - call ozphys%update_forcing(jindx1_o3, jindx2_o3, ddy_o3, rjday, n1, n2, ozpl) - !$OMP END CRITICAL - endif +!$OMP parallel num_threads(nthrds) default(none) & +!$OMP shared(kdt,nsswr,lsswr,clstp,imfdeepcnv,cal_pre,random_clds) & +!$OMP shared(fhswr,fhour,seed0,cnx,cny,nrcm,wrk,rannie,rndval) & +!$OMP shared(rann,im,isc,jsc,imap,jmap,ntoz,me,idate,jindx1_o3,jindx2_o3) & +!$OMP shared(ozpl,ddy_o3,h2o_phys,jindx1_h,jindx2_h,h2opl,ddy_h,iaerclm,master) & +!$OMP shared(levs,prsl,iccn,jindx1_ci,jindx2_ci,ddy_ci,iindx1_ci,iindx2_ci) & +!$OMP shared(ddx_ci,in_nm,ccn_nm,do_ugwp_v1,jindx1_tau,jindx2_tau,ddy_j1tau) & +!$OMP shared(ddy_j2tau,tau_amf,iflip,ozphys) & +!$OMP private(iseed,iskip,i,j) + +!$OMP sections !$OMP section @@ -901,6 +890,12 @@ subroutine GFS_phys_time_vary_timestep_init ( endif ! imfdeepcnv, cal_re, random_clds +!$OMP section +!> - Update ozone concentration. + if (ntoz > 0) then + call ozphys%update_forcing(jindx1_o3, jindx2_o3, ddy_o3, rjday, n1, n2, ozpl) + endif + !$OMP section !> - Call h2ointerpol() to make stratospheric water vapor data interpolation if (h2o_phys) then From 17b057ce219479a3e46e9c8d7825736a0935083c Mon Sep 17 00:00:00 2001 From: dustinswales Date: Wed, 27 Sep 2023 14:28:52 -0600 Subject: [PATCH 12/25] Housekeeping --- physics/GFS_phys_time_vary.fv3.F90 | 2 +- physics/GFS_phys_time_vary.fv3.meta | 59 ++++++++++++++--------------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/physics/GFS_phys_time_vary.fv3.F90 b/physics/GFS_phys_time_vary.fv3.F90 index f72763c3a..6fa188471 100644 --- a/physics/GFS_phys_time_vary.fv3.F90 +++ b/physics/GFS_phys_time_vary.fv3.F90 @@ -841,7 +841,7 @@ subroutine GFS_phys_time_vary_timestep_init ( !$OMP shared(levs,prsl,iccn,jindx1_ci,jindx2_ci,ddy_ci,iindx1_ci,iindx2_ci) & !$OMP shared(ddx_ci,in_nm,ccn_nm,do_ugwp_v1,jindx1_tau,jindx2_tau,ddy_j1tau) & !$OMP shared(ddy_j2tau,tau_amf,iflip,ozphys) & -!$OMP private(iseed,iskip,i,j) +!$OMP private(iseed,iskip,i,j,k) !$OMP sections diff --git a/physics/GFS_phys_time_vary.fv3.meta b/physics/GFS_phys_time_vary.fv3.meta index bf5a3fa04..639e2db6a 100644 --- a/physics/GFS_phys_time_vary.fv3.meta +++ b/physics/GFS_phys_time_vary.fv3.meta @@ -30,6 +30,13 @@ dimensions = () type = logical intent = in +[ntoz] + standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array + long_name = tracer index for ozone mixing ratio + units = index + dimensions = () + type = integer + intent = in [iaerclm] standard_name = flag_for_aerosol_input_MG_radiation long_name = flag for using aerosols in Morrison-Gettelman MP_radiation @@ -72,36 +79,6 @@ dimensions = () type = integer intent = in - intent = in -[ntoz] - standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array - long_name = tracer index for ozone mixing ratio - units = index - dimensions = () - type = integer - intent = in -[jindx1_o3] - standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation low index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[jindx2_o3] - standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation - long_name = interpolation high index for ozone - units = index - dimensions = (horizontal_dimension) - type = integer - intent = in -[ddy_o3] - standard_name = latitude_interpolation_weight_for_ozone_forcing - long_name = interpolation high index for ozone - units = none - dimensions = (horizontal_dimension) - type = real - kind = kind_phys - intent = in [nx] standard_name = number_of_points_in_x_direction_for_this_MPI_rank long_name = number of points in x direction for this MPI rank @@ -139,6 +116,28 @@ type = real kind = kind_phys intent = in +[jindx1_o3] + standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation low index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = inout +[jindx2_o3] + standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation high index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = inout +[ddy_o3] + standard_name = latitude_interpolation_weight_for_ozone_forcing + long_name = interpolation high index for ozone + units = none + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = inout [jindx1_h] standard_name = lower_latitude_index_of_stratospheric_water_vapor_forcing_for_interpolation long_name = interpolation low index for stratospheric water vapor From 17203fe06a90612ad09a357e8084510c4a277d58 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Wed, 27 Sep 2023 14:32:20 -0600 Subject: [PATCH 13/25] Housekeeping --- physics/GFS_phys_time_vary.fv3.meta | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/physics/GFS_phys_time_vary.fv3.meta b/physics/GFS_phys_time_vary.fv3.meta index 639e2db6a..ad543e146 100644 --- a/physics/GFS_phys_time_vary.fv3.meta +++ b/physics/GFS_phys_time_vary.fv3.meta @@ -23,13 +23,6 @@ dimensions = () type = integer intent = in -[h2o_phys] - standard_name = flag_for_stratospheric_water_vapor_physics - long_name = flag for stratospheric water vapor physics - units = flag - dimensions = () - type = logical - intent = in [ntoz] standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array long_name = tracer index for ozone mixing ratio @@ -37,6 +30,13 @@ dimensions = () type = integer intent = in +[h2o_phys] + standard_name = flag_for_stratospheric_water_vapor_physics + long_name = flag for stratospheric water vapor physics + units = flag + dimensions = () + type = logical + intent = in [iaerclm] standard_name = flag_for_aerosol_input_MG_radiation long_name = flag for using aerosols in Morrison-Gettelman MP_radiation From 3f6168b12443a79adf7abcdf326bcfa6813c8d84 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Wed, 27 Sep 2023 15:49:35 -0600 Subject: [PATCH 14/25] More reorg. --- physics/GFS_phys_time_vary.fv3.F90 | 9 +- physics/GFS_rrtmg_pre.F90 | 2 +- physics/GFS_rrtmg_setup.F90 | 2 +- physics/GFS_rrtmgp_pre.F90 | 2 +- physics/GFS_rrtmgp_setup.F90 | 2 +- physics/GFS_suite_stateout_update.F90 | 135 +++++++++++++++---------- physics/GFS_suite_stateout_update.meta | 95 ++++++++++++++++- physics/module_ozphys.F90 | 50 ++++----- 8 files changed, 209 insertions(+), 88 deletions(-) diff --git a/physics/GFS_phys_time_vary.fv3.F90 b/physics/GFS_phys_time_vary.fv3.F90 index 6fa188471..70eeb81e1 100644 --- a/physics/GFS_phys_time_vary.fv3.F90 +++ b/physics/GFS_phys_time_vary.fv3.F90 @@ -95,6 +95,7 @@ subroutine GFS_phys_time_vary_init ( integer, intent(in) :: lkm integer, intent(inout) :: use_lake_model(:) real(kind=kind_phys), intent(in ) :: lakefrac(:), lakedepth(:) + integer, intent(inout) :: jindx1_o3(:), jindx2_o3(:), jindx1_h(:), jindx2_h(:) real(kind_phys), intent(inout) :: ddy_o3(:), ddy_h(:) real(kind_phys), intent(in) :: h2opl(:,:,:) @@ -289,7 +290,7 @@ subroutine GFS_phys_time_vary_init ( !$OMP section !> - Setup spatial interpolation indices for ozone physics. if (ntoz > 0) then - call ozphys%setup_forcing(xlat_d, jindx1_o3, jindx2_o3, ddy_o3) + call ozphys%setup_o3prog(xlat_d, jindx1_o3, jindx2_o3, ddy_o3) endif !$OMP section @@ -729,7 +730,7 @@ subroutine GFS_phys_time_vary_timestep_init ( lakefrac, min_seaice, min_lakeice, smc, slc, stc, smois, sh2o, tslb, tiice, tg3, tref, & tsfc, tsfco, tisfc, hice, fice, facsf, facwf, alvsf, alvwf, alnsf, alnwf, zorli, zorll, & zorlo, weasd, slope, snoalb, canopy, vfrac, vtype, stype,scolor, shdmin, shdmax, snowd, & - cv, cvb, cvt, oro, oro_uf, xlat_d, xlon_d, slmsk, landfrac, ozphys, & + cv, cvb, cvt, oro, oro_uf, xlat_d, xlon_d, slmsk, landfrac, ozphys, & do_ugwp_v1, jindx1_tau, jindx2_tau, ddy_j1tau, ddy_j2tau, tau_amf, errmsg, errflg) implicit none @@ -841,7 +842,7 @@ subroutine GFS_phys_time_vary_timestep_init ( !$OMP shared(levs,prsl,iccn,jindx1_ci,jindx2_ci,ddy_ci,iindx1_ci,iindx2_ci) & !$OMP shared(ddx_ci,in_nm,ccn_nm,do_ugwp_v1,jindx1_tau,jindx2_tau,ddy_j1tau) & !$OMP shared(ddy_j2tau,tau_amf,iflip,ozphys) & -!$OMP private(iseed,iskip,i,j,k) +!$OMP private(iseed,iskip,i,j,k,rjday,n1,n2) !$OMP sections @@ -893,7 +894,7 @@ subroutine GFS_phys_time_vary_timestep_init ( !$OMP section !> - Update ozone concentration. if (ntoz > 0) then - call ozphys%update_forcing(jindx1_o3, jindx2_o3, ddy_o3, rjday, n1, n2, ozpl) + call ozphys%update_o3prog(jindx1_o3, jindx2_o3, ddy_o3, rjday, n1, n2, ozpl) endif !$OMP section diff --git a/physics/GFS_rrtmg_pre.F90 b/physics/GFS_rrtmg_pre.F90 index 69be4f8d0..108d6f407 100644 --- a/physics/GFS_rrtmg_pre.F90 +++ b/physics/GFS_rrtmg_pre.F90 @@ -434,7 +434,7 @@ subroutine GFS_rrtmg_pre_run (im, levs, lm, lmk, lmp, n_var_lndp, lextop,& enddo enddo else ! climatological ozone - call ozphys%oz_clim(xlat, prslk1, con_pi, olyr) + call ozphys%run_o3clim(xlat, prslk1, con_pi, olyr) endif ! end_if_ntoz !> - Call coszmn(), to compute cosine of zenith angle (only when SW is called) diff --git a/physics/GFS_rrtmg_setup.F90 b/physics/GFS_rrtmg_setup.F90 index 908a364dc..e48a60ac8 100644 --- a/physics/GFS_rrtmg_setup.F90 +++ b/physics/GFS_rrtmg_setup.F90 @@ -467,7 +467,7 @@ subroutine radupdate( idate,jdate,deltsw,deltim,lsswr,me, iaermdl,& call gas_update ( kyear,kmon,kday,khour,lco2_chg, me, co2dat_file, & co2gbl_file, ictm, ico2, errflg, errmsg ) if (ntoz == 0) then - call ozphys%update_clim(kmon, kday, khour, loz1st) + call ozphys%update_o3clim(kmon, kday, khour, loz1st) endif if ( loz1st ) loz1st = .false. diff --git a/physics/GFS_rrtmgp_pre.F90 b/physics/GFS_rrtmgp_pre.F90 index 9dcc002a0..cbf8d161b 100644 --- a/physics/GFS_rrtmgp_pre.F90 +++ b/physics/GFS_rrtmgp_pre.F90 @@ -353,7 +353,7 @@ subroutine GFS_rrtmgp_pre_run(me, nCol, nLev, i_o3, doSWrad, doLWrad, fhswr, fhl enddo ! OR Use climatological ozone data else - call ozphys%oz_clim(xlat, prslk, con_pi, o3_lay) + call ozphys%run_o3clim(xlat, prslk, con_pi, o3_lay) endif ! ####################################################################################### diff --git a/physics/GFS_rrtmgp_setup.F90 b/physics/GFS_rrtmgp_setup.F90 index 3e4f57d13..9f2b2a9f9 100644 --- a/physics/GFS_rrtmgp_setup.F90 +++ b/physics/GFS_rrtmgp_setup.F90 @@ -243,7 +243,7 @@ subroutine GFS_rrtmgp_setup_timestep_init (idate, jdate, deltsw, deltim, doSWrad call gas_update (kyear, kmon, kday, khour, lco2_chg, me, co2dat_file, co2gbl_file, ictm,& ico2, errflg, errmsg ) if (ntoz == 0) then - call ozphys%update_clim(kmon, kday, khour, loz1st) + call ozphys%update_o3clim(kmon, kday, khour, loz1st) endif if ( loz1st ) loz1st = .false. diff --git a/physics/GFS_suite_stateout_update.F90 b/physics/GFS_suite_stateout_update.F90 index 2771c3e82..41f44e0de 100644 --- a/physics/GFS_suite_stateout_update.F90 +++ b/physics/GFS_suite_stateout_update.F90 @@ -1,63 +1,90 @@ +! ######################################################################################### !> \file GFS_suite_stateout_update.f90 -!! Contains code to update the state variables due to process-split physics from accumulated tendencies during that phase. +!! Update the state variables due to process-split physics from accumulated tendencies +!! during that phase. +!! Update gas concentrations, if using prognostic photolysis schemes. !! Also, set bounds on the mass-weighted rime factor when using Ferrier-Aligo microphysics. - - module GFS_suite_stateout_update - - contains - +! ######################################################################################### +module GFS_suite_stateout_update + use machine, only: kind_phys + use module_ozphys, only: ty_ozphys + implicit none +contains +! ######################################################################################### !> \section arg_table_GFS_suite_stateout_update_run Argument Table !! \htmlinclude GFS_suite_stateout_update_run.html !! - subroutine GFS_suite_stateout_update_run (im, levs, ntrac, dtp, & - tgrs, ugrs, vgrs, qgrs, dudt, dvdt, dtdt, dqdt, & - gt0, gu0, gv0, gq0, ntiw, nqrimef, imp_physics, & - imp_physics_fer_hires, epsq, errmsg, errflg) - - use machine, only: kind_phys - - implicit none - - ! Interface variables - integer, intent(in ) :: im - integer, intent(in ) :: levs - integer, intent(in ) :: ntrac - integer, intent(in ) :: imp_physics,imp_physics_fer_hires - integer, intent(in ) :: ntiw, nqrimef - real(kind=kind_phys), intent(in ) :: dtp, epsq - - real(kind=kind_phys), intent(in ), dimension(:,:) :: tgrs, ugrs, vgrs - real(kind=kind_phys), intent(in ), dimension(:,:,:) :: qgrs - real(kind=kind_phys), intent(in ), dimension(:,:) :: dudt, dvdt, dtdt - real(kind=kind_phys), intent(in ), dimension(:,:,:) :: dqdt - real(kind=kind_phys), intent(out), dimension(:,:) :: gt0, gu0, gv0 - real(kind=kind_phys), intent(out), dimension(:,:,:) :: gq0 - - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg - - integer :: i, k - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - gt0(:,:) = tgrs(:,:) + dtdt(:,:) * dtp - gu0(:,:) = ugrs(:,:) + dudt(:,:) * dtp - gv0(:,:) = vgrs(:,:) + dvdt(:,:) * dtp - gq0(:,:,:) = qgrs(:,:,:) + dqdt(:,:,:) * dtp - - if (imp_physics == imp_physics_fer_hires) then +! ######################################################################################### + subroutine GFS_suite_stateout_update_run (im, levs, ntrac, dtp, tgrs, ugrs, vgrs, qgrs, & + dudt, dvdt, dtdt, dqdt, gt0, gu0, gv0, gq0, oz0, ntiw, nqrimef, imp_physics, & + imp_physics_fer_hires, epsq, ozphys, oz_phys_2015, oz_phys_2006, con_1ovg, prsl, & + dp, ozpl, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, errmsg, errflg) + + ! Inputs + integer, intent(in ) :: im + integer, intent(in ) :: levs + integer, intent(in ) :: ntrac + integer, intent(in ) :: imp_physics,imp_physics_fer_hires + integer, intent(in ) :: ntiw, nqrimef + real(kind=kind_phys), intent(in ) :: dtp, epsq, con_1ovg + real(kind=kind_phys), intent(in ), dimension(:,:) :: tgrs, ugrs, vgrs, prsl, dp + real(kind=kind_phys), intent(in ), dimension(:,:,:) :: qgrs, ozpl + real(kind=kind_phys), intent(in ), dimension(:,:) :: dudt, dvdt, dtdt + real(kind=kind_phys), intent(in ), dimension(:,:,:) :: dqdt + logical, intent(in) :: oz_phys_2015 + logical, intent(in) :: oz_phys_2006 + type(ty_ozphys), intent(in) :: ozphys + + ! Outputs (optional) + real(kind=kind_phys), intent(inout), dimension(:,:), pointer, optional :: & + do3_dt_prd, & ! Physics tendency: production and loss effect + do3_dt_ozmx, & ! Physics tendency: ozone mixing ratio effect + do3_dt_temp, & ! Physics tendency: temperature effect + do3_dt_ohoz ! Physics tendency: overhead ozone effect + + ! Outputs + real(kind=kind_phys), intent(out), dimension(:,:) :: gt0, gu0, gv0, oz0 + real(kind=kind_phys), intent(out), dimension(:,:,:) :: gq0 + character(len=*), intent(out) :: errmsg + integer, intent(out) :: errflg + + ! Locals + integer :: i, k + + ! Initialize CCPP error handling variables + errmsg = '' + errflg = 0 + + ! Update prognostic state varaibles using accumulated tendencies from "process-split" + ! section of GFS suite. + gt0(:,:) = tgrs(:,:) + dtdt(:,:) * dtp + gu0(:,:) = ugrs(:,:) + dudt(:,:) * dtp + gv0(:,:) = vgrs(:,:) + dvdt(:,:) * dtp + gq0(:,:,:) = qgrs(:,:,:) + dqdt(:,:,:) * dtp + + ! If using photolysis physics schemes, update (prognostic) gas concentrations using + ! updated state. + if (oz_phys_2015) then + call ozphys%run_o3prog_2015(con_1ovg, dtp, prsl, gt0, dp, ozpl, oz0, do3_dt_prd, & + do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz) + endif + if (oz_phys_2006) then + call ozphys%run_o3prog_2006() + endif + + ! If using Ferrier-Aligo microphysics, set bounds on the mass-weighted rime factor. + if (imp_physics == imp_physics_fer_hires) then do k=1,levs - do i=1,im - if(gq0(i,k,ntiw) > epsq) then - gq0(i,k,nqrimef) = max(1., gq0(i,k,nqrimef)/gq0(i,k,ntiw)) - else - gq0(i,k,nqrimef) = 1. - end if - end do + do i=1,im + if(gq0(i,k,ntiw) > epsq) then + gq0(i,k,nqrimef) = max(1., gq0(i,k,nqrimef)/gq0(i,k,ntiw)) + else + gq0(i,k,nqrimef) = 1. + end if + end do end do - end if + end if - end subroutine GFS_suite_stateout_update_run + end subroutine GFS_suite_stateout_update_run - end module GFS_suite_stateout_update \ No newline at end of file +end module GFS_suite_stateout_update diff --git a/physics/GFS_suite_stateout_update.meta b/physics/GFS_suite_stateout_update.meta index 580482b71..8cbab9139 100644 --- a/physics/GFS_suite_stateout_update.meta +++ b/physics/GFS_suite_stateout_update.meta @@ -2,7 +2,7 @@ [ccpp-table-properties] name = GFS_suite_stateout_update type = scheme - dependencies = machine.F + dependencies = machine.F,module_ozphys.F90 ######################################################################## [ccpp-arg-table] @@ -37,6 +37,27 @@ type = real kind = kind_phys intent = in +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed + dimensions = () + type = ty_ozphys + intent = in +[oz_phys_2015] + standard_name = flag_for_nrl_2015_ozone_scheme + long_name = flag for new (2015) ozone physics + units = flag + dimensions = () + type = logical + intent = in +[oz_phys_2006] + standard_name = flag_for_nrl_2006_ozone_scheme + long_name = flag for new (2006) ozone physics + units = flag + dimensions = () + type = logical + intent = in [tgrs] standard_name = air_temperature long_name = model layer mean temperature @@ -133,6 +154,14 @@ type = real kind = kind_phys intent = out +[oz0] + standard_name = ozone_concentration_of_new_state + long_name = ozone concentration updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout [ntiw] standard_name = index_of_cloud_ice_mixing_ratio_in_tracer_concentration_array long_name = tracer index for ice water @@ -169,6 +198,70 @@ type = real kind = kind_phys intent = in +[con_1ovg] + standard_name = one_divided_by_the_gravitational_acceleration + long_name = inverse of gravitational acceleration + units = s2 m-1 + dimensions = () + type = real + kind = kind_phys + intent = in +[prsl] + standard_name = air_pressure + long_name = mid-layer pressure + units = Pa + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[ozpl] + standard_name = ozone_forcing + long_name = ozone forcing data + units = mixed + dimensions = (horizontal_loop_extent,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) + type = real + kind = kind_phys + intent = in +[dp] + standard_name = air_pressure_difference_between_midlayers + long_name = difference between mid-layer pressures + units = Pa + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = in +[do3_dt_prd] + standard_name = ozone_tendency_due_to_production_and_loss_rate + long_name = ozone tendency due to production and loss rate + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[do3_dt_ozmx] + standard_name = ozone_tendency_due_to_ozone_mixing_ratio + long_name = ozone tendency due to ozone mixing ratio + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[do3_dt_temp] + standard_name = ozone_tendency_due_to_temperature + long_name = ozone tendency due to temperature + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout +[do3_dt_ohoz] + standard_name = ozone_tendency_due_to_overhead_ozone_column + long_name = ozone tendency due to overhead ozone column + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + intent = inout [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP diff --git a/physics/module_ozphys.F90 b/physics/module_ozphys.F90 index 966d27113..205a02b46 100644 --- a/physics/module_ozphys.F90 +++ b/physics/module_ozphys.F90 @@ -41,21 +41,22 @@ module module_ozphys integer :: k2oz !< Upper interpolation index in datac(dim=3), time dim real(kind_phys) :: facoz !< Parameter for ozone climotology contains - procedure, public :: load_forcing - procedure, public :: load_clim - procedure, public :: setup_forcing - procedure, public :: update_forcing - procedure, public :: update_clim - procedure, public :: oz_prog_2015 - procedure, public :: oz_prog_2006 - procedure, public :: oz_clim + procedure, public :: load_o3prog + procedure, public :: setup_o3prog + procedure, public :: update_o3prog + procedure, public :: run_o3prog_2015 + procedure, public :: run_o3prog_2006 + ! + procedure, public :: load_o3clim + procedure, public :: update_o3clim + procedure, public :: run_o3clim end type ty_ozphys contains ! ######################################################################################### ! Procedure (type-bound) for loading ozone forcing data. ! ######################################################################################### - function load_forcing(this, file, fileID) result (err_message) + function load_o3prog(this, file, fileID) result (err_message) class(ty_ozphys), intent(inout) :: this integer, intent(in) :: fileID character(len=*), intent(in) :: file @@ -97,12 +98,12 @@ function load_forcing(this, file, fileID) result (err_message) deallocate(tempin) close(fileID) - end function load_forcing + end function load_o3prog ! ######################################################################################### ! Procedure for setting up interpolation indices between data and model grid. ! ######################################################################################### - subroutine setup_forcing(this, lat, idx1, idx2, idxh) + subroutine setup_o3prog(this, lat, idx1, idx2, idxh) class(ty_ozphys), intent(in) :: this real(kind_phys), intent(in) :: lat(:) integer, intent(out) :: idx1(:), idx2(:) @@ -126,12 +127,12 @@ subroutine setup_forcing(this, lat, idx1, idx2, idxh) endif enddo - end subroutine setup_forcing + end subroutine setup_o3prog ! ######################################################################################### ! Procedure (type-bound) for updating ozone data. ! ######################################################################################### - subroutine update_forcing(this, idx1, idx2, idxh, rjday, idxt1, idxt2, ozpl) + subroutine update_o3prog(this, idx1, idx2, idxh, rjday, idxt1, idxt2, ozpl) class(ty_ozphys), intent(in) :: this integer, intent(in) :: idx1(:), idx2(:) real(kind_phys), intent(in) :: idxh(:) @@ -156,12 +157,12 @@ subroutine update_forcing(this, idx1, idx2, idxh, rjday, idxt1, idxt2, ozpl) enddo enddo - end subroutine update_forcing + end subroutine update_o3prog ! ######################################################################################### ! Procedure (type-bound) for NRL prognostic ozone (2015). ! ######################################################################################### - subroutine oz_prog_2015(this, con_1ovg, dt, p, t, dp, ozpl, oz, do3_dt_prd, do3_dt_ozmx, & + subroutine run_o3prog_2015(this, con_1ovg, dt, p, t, dp, ozpl, oz, do3_dt_prd, do3_dt_ozmx, & do3_dt_temp, do3_dt_ohoz) class(ty_ozphys), intent(in) :: this real(kind_phys),intent(in) :: & @@ -267,21 +268,20 @@ subroutine oz_prog_2015(this, con_1ovg, dt, p, t, dp, ozpl, oz, do3_dt_prd, do3_ enddo return - end subroutine oz_prog_2015 + end subroutine run_o3prog_2015 ! ######################################################################################### ! Procedure (type-bound) for NRL prognostic ozone (2006). ! ######################################################################################### - subroutine oz_prog_2006(this) + subroutine run_o3prog_2006(this) class(ty_ozphys), intent(in) :: this return - end subroutine oz_prog_2006 + end subroutine run_o3prog_2006 ! ######################################################################################### ! Procedure (type-bound) for NRL updating climotological ozone. - ! Build this up from getozn. ! ######################################################################################### - subroutine oz_clim(this, lat, prslk, con_pi, oz) + subroutine run_o3clim(this, lat, prslk, con_pi, oz) class(ty_ozphys), intent(in) :: this real(kind_phys), intent(in) :: & con_pi ! Physics constant: Pi @@ -356,12 +356,12 @@ subroutine oz_clim(this, lat, prslk, con_pi, oz) enddo return - end subroutine oz_clim + end subroutine run_o3clim ! ######################################################################################### ! Procedure (type-bound) for loading ozone climo data. ! ######################################################################################### - function load_clim(this, file, fileID) result (err_message) + function load_o3clim(this, file, fileID) result (err_message) class(ty_ozphys), intent(inout) :: this integer, intent(in) :: fileID character(len=*), intent(in) :: file @@ -432,12 +432,12 @@ function load_clim(this, file, fileID) result (err_message) this%pkstr(iLev) = fpkapx(this%pstr(iLev)*100.0) enddo - end function load_clim + end function load_o3clim ! ######################################################################################### ! Procedure (type-bound) for updating ozone climotological data. ! ######################################################################################### - subroutine update_clim(this, imon, iday, ihour, loz1st) + subroutine update_o3clim(this, imon, iday, ihour, loz1st) class(ty_ozphys), intent(inout) :: this integer, intent(in) :: imon, iday, ihour logical, intent(in) :: loz1st @@ -471,6 +471,6 @@ subroutine update_clim(this, imon, iday, ihour, loz1st) this%facoz = float(id - midm) / float(midp - midm) - end subroutine update_clim + end subroutine update_o3clim end module module_ozphys From d0a4bfd63fae9f4e4a06cb5598049f1019aed945 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Wed, 27 Sep 2023 15:50:51 -0600 Subject: [PATCH 15/25] Remove ozphysics modules. Now part of ty_ozphys --- physics/ozphys_2015.F90 | 167 --------------------------------------- physics/ozphys_2015.meta | 140 -------------------------------- 2 files changed, 307 deletions(-) delete mode 100644 physics/ozphys_2015.F90 delete mode 100644 physics/ozphys_2015.meta diff --git a/physics/ozphys_2015.F90 b/physics/ozphys_2015.F90 deleted file mode 100644 index 1478d0d6e..000000000 --- a/physics/ozphys_2015.F90 +++ /dev/null @@ -1,167 +0,0 @@ -! ########################################################################################### -!> \file ozphys_2015.F90 -!! -! ########################################################################################### -module ozphys_2015 - use machine, only: kind_phys, kind_dbl_prec, kind_sngl_prec - use module_ozphys, only: ty_ozphys - implicit none - public ozphys_2015_run -contains - -! ########################################################################################### -!>\defgroup GFS_ozphys_2015 GFS Ozone Photochemistry (2015) Module -!! This module contains the CCPP-compliant Ozone 2015 photochemistry scheme. -!> @{ -!> The operational GFS currently parameterizes ozone production and destruction based on -!! monthly mean coefficients ( \c ozprdlos_2015_new_sbuvO3_tclm15_nuchem.f77) provided by -!! Naval Research Laboratory through CHEM2D chemistry model -!! (McCormack et al. (2006) \cite mccormack_et_al_2006). -!! (https://doi.org/10.5194/acp-6-4943-2006) -!! -!> \section genal_ozphys_2015 GFS ozphys_2015_run General Algorithm -!> - This code assumes that both 2D fields are ordered from bottom to top. -!> - This code is specifically for NRL parameterization and climatological T and O3 are in -! location 5 and 6 of ozpl array -!!\author June 2015 - Shrinivas Moorthi -!!\modified May 2023 - Dustin Swales -! ########################################################################################### - -! ########################################################################################### -! SUBROUTINE ozphys_2015_run -! ########################################################################################### -!! \section arg_table_ozphys_2015_run Argument Table -!! \htmlinclude ozphys_2015_run.html -!! - subroutine ozphys_2015_run (oz_phys, ozphys, nCol, nLev, dt, oz, tin, prsl, ozpl, & - delp, con_1ovg, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, errmsg, errflg) - - ! Inputs - logical, intent(in) :: & - oz_phys ! Flag for ozone_physics_2015 scheme. - type(ty_ozphys),intent(in) :: & - ozphys - real(kind_phys),intent(in) :: & - con_1ovg ! Physical constant: One divided by gravitational acceleration (m-1 s2) - integer, intent(in) :: & - nCol, & ! Horizontal dimension - nLev ! Number of vertical layers - real(kind_phys), intent(in) :: & - dt ! Physics timestep (seconds) - real(kind_phys), intent(in), dimension(:,:) :: & - prsl, & ! Air-pressure (Pa) - tin, & ! Temperature of new-state (K) - delp ! Difference between mid-layer pressures (Pa) - real(kind_phys), intent(in), dimension(:,:,:) :: & - ozpl ! Ozone forcing data - - ! Outputs (optional) - real(kind=kind_phys), intent(inout), dimension(:,:), pointer, optional :: & - do3_dt_prd, & ! Physics tendency: production and loss effect - do3_dt_ozmx, & ! Physics tendency: ozone mixing ratio effect - do3_dt_temp, & ! Physics tendency: temperature effect - do3_dt_ohoz ! Physics tendency: overhead ozone effect - - ! Outputs - real(kind=kind_phys), intent(inout), dimension(:,:) :: & - oz ! Ozone concentration updated by physics - character(len=*), intent(out) :: & - errmsg ! CCPP error message - integer, intent(out) :: & - errflg ! CCPP error flag - - ! Locals - integer :: k, kmax, kmin, l, i, j - logical, dimension(nCol) :: flg - real(kind_phys) :: pmax, pmin, tem, temp - real(kind_phys), dimension(nCol) :: wk1, wk2, wk3, ozib - real(kind_phys), dimension(nCol,ozphys%ncf) :: prod - real(kind_phys), dimension(nCol,nLev) :: ozi - real(kind_phys), dimension(nCol,nLev+1) :: colo3, coloz - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - ! Sanity checks - if (.not.oz_phys) then - write (errmsg,'(*(a))') 'Logic error: oz_phys_2015 == .false.' - errflg = 1 - return - endif - - ! Temporaries - ozi = oz - - colo3(:,nLev+1) = 0.0 - coloz(:,nLev+1) = 0.0 - - do l=nLev,1,-1 - pmin = 1.0e10 - pmax = -1.0e10 - - do i=1,nCol - wk1(i) = log(prsl(i,l)) - pmin = min(wk1(i), pmin) - pmax = max(wk1(i), pmax) - prod(i,:) = 0.0 - enddo - kmax = 1 - kmin = 1 - do k=1,ozphys%nlev-1 - if (pmin < ozphys%po3(k)) kmax = k - if (pmax < ozphys%po3(k)) kmin = k - enddo - ! - do k=kmin,kmax - temp = 1.0 / (ozphys%po3(k) - ozphys%po3(k+1)) - do i=1,nCol - flg(i) = .false. - if (wk1(i) < ozphys%po3(k) .and. wk1(i) >= ozphys%po3(k+1)) then - flg(i) = .true. - wk2(i) = (wk1(i) - ozphys%po3(k+1)) * temp - wk3(i) = 1.0 - wk2(i) - endif - enddo - do j=1,ozphys%ncf - do i=1,nCol - if (flg(i)) then - prod(i,j) = wk2(i) * ozpl(i,k,j) + wk3(i) * ozpl(i,k+1,j) - endif - enddo - enddo - enddo - - do j=1,ozphys%ncf - do i=1,nCol - if (wk1(i) < ozphys%po3(ozphys%nlev)) then - prod(i,j) = ozpl(i,ozphys%nlev,j) - endif - if (wk1(i) >= ozphys%po3(1)) then - prod(i,j) = ozpl(i,1,j) - endif - enddo - enddo - do i=1,nCol - colo3(i,l) = colo3(i,l+1) + ozi(i,l) * delp(i,l)*con_1ovg - coloz(i,l) = coloz(i,l+1) + prod(i,6) * delp(i,l)*con_1ovg - prod(i,2) = min(prod(i,2), 0.0) - enddo - do i=1,nCol - ozib(i) = ozi(i,l) ! no filling - tem = prod(i,1) - prod(i,2) * prod(i,6) + prod(i,3) * (tin(i,l) - prod(i,5)) & - + prod(i,4) * (colo3(i,l)-coloz(i,l)) - oz(i,l) = (ozib(i) + tem*dt) / (1.0 - prod(i,2)*dt) - enddo - - ! Diagnostics (optional) - if (associated(do3_dt_prd)) do3_dt_prd(:,l) = (prod(:,1)-prod(:,2)*prod(:,6))*dt - if (associated(do3_dt_ozmx)) do3_dt_ozmx(:,l) = (oz(:,l) - ozib(:)) - if (associated(do3_dt_temp)) do3_dt_temp(:,l) = prod(:,3)*(tin(:,l)-prod(:,5))*dt - if (associated(do3_dt_ohoz)) do3_dt_ohoz(:,l) = prod(:,4) * (colo3(:,l)-coloz(:,l))*dt - enddo - - return - end subroutine ozphys_2015_run -!> @} -end module ozphys_2015 diff --git a/physics/ozphys_2015.meta b/physics/ozphys_2015.meta deleted file mode 100644 index ca2d56e4e..000000000 --- a/physics/ozphys_2015.meta +++ /dev/null @@ -1,140 +0,0 @@ -[ccpp-table-properties] - name = ozphys_2015 - type = scheme - dependencies = machine.F,module_ozphys.F90 - -######################################################################## -[ccpp-arg-table] - name = ozphys_2015_run - type = scheme -[oz_phys] - standard_name = flag_for_nrl_2015_ozone_scheme - long_name = flag for new (2015) ozone physics - units = flag - dimensions = () - type = logical - intent = in -[ozphys] - standard_name = dataset_for_ozone_physics - long_name = dataset for NRL ozone physics - units = mixed - dimensions = () - type = ty_ozphys - intent = in -[nCol] - standard_name = horizontal_loop_extent - long_name = horizontal loop extent - units = count - dimensions = () - type = integer - intent = in -[nLev] - standard_name = vertical_layer_dimension - long_name = number of vertical layers - units = count - dimensions = () - type = integer - intent = in -[dt] - standard_name = timestep_for_physics - long_name = physics time step - units = s - dimensions = () - type = real - kind = kind_phys - intent = in -[oz] - standard_name = ozone_concentration_of_new_state - long_name = ozone concentration updated by physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[tin] - standard_name = air_temperature_of_new_state - long_name = updated air temperature - units = K - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = in -[prsl] - standard_name = air_pressure - long_name = mid-layer pressure - units = Pa - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = in -[ozpl] - standard_name = ozone_forcing - long_name = ozone forcing data - units = mixed - dimensions = (horizontal_loop_extent,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) - type = real - kind = kind_phys - intent = in -[delp] - standard_name = air_pressure_difference_between_midlayers - long_name = difference between mid-layer pressures - units = Pa - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = in -[con_1ovg] - standard_name = one_divided_by_the_gravitational_acceleration - long_name = inverse of gravitational acceleration - units = s2 m-1 - dimensions = () - type = real - kind = kind_phys - intent = in -[do3_dt_prd] - standard_name = ozone_tendency_due_to_production_and_loss_rate - long_name = ozone tendency due to production and loss rate - units = kg kg-1 s-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[do3_dt_ozmx] - standard_name = ozone_tendency_due_to_ozone_mixing_ratio - long_name = ozone tendency due to ozone mixing ratio - units = kg kg-1 s-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[do3_dt_temp] - standard_name = ozone_tendency_due_to_temperature - long_name = ozone tendency due to temperature - units = kg kg-1 s-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[do3_dt_ohoz] - standard_name = ozone_tendency_due_to_overhead_ozone_column - long_name = ozone tendency due to overhead ozone column - units = kg kg-1 s-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out From 385ef4e2802a838fd3099b17ee479ebaae1a6402 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Wed, 27 Sep 2023 22:19:36 -0600 Subject: [PATCH 16/25] Some polishing. Merge 2006 ozone into module_ozphys --- physics/GFS_phys_time_vary.fv3.F90 | 69 ++++----- physics/GFS_suite_stateout_update.F90 | 3 +- physics/module_ozphys.F90 | 127 +++++++++++++++- physics/ozphys.f | 211 -------------------------- physics/ozphys.meta | 208 ------------------------- 5 files changed, 158 insertions(+), 460 deletions(-) delete mode 100644 physics/ozphys.f delete mode 100644 physics/ozphys.meta diff --git a/physics/GFS_phys_time_vary.fv3.F90 b/physics/GFS_phys_time_vary.fv3.F90 index 70eeb81e1..cd1f8287a 100644 --- a/physics/GFS_phys_time_vary.fv3.F90 +++ b/physics/GFS_phys_time_vary.fv3.F90 @@ -802,38 +802,6 @@ subroutine GFS_phys_time_vary_timestep_init ( return end if - !> - Compute temporal interpolation indices for updating gas concentrations. - idat=0 - idat(1)=idate(4) - idat(2)=idate(2) - idat(3)=idate(3) - idat(5)=idate(1) - rinc=0. - rinc(2)=fhour - call w3kind(w3kindreal,w3kindint) - if(w3kindreal==4) then - rinc4=rinc - CALL w3movdat(rinc4,idat,jdat) - else - CALL w3movdat(rinc,idat,jdat) - endif - jdow = 0 - jdoy = 0 - jday = 0 - call w3doxdat(jdat,jdow,jdoy,jday) - rjday = jdoy + jdat(5) / 24. - if (rjday < ozphys%time(1)) rjday = rjday + 365. - - n2 = ozphys%ntime + 1 - do j=2,ozphys%ntime - if (rjday < ozphys%time(j)) then - n2 = j - exit - endif - enddo - n1 = n2 - 1 - if (n2 > ozphys%ntime) n2 = n2 - ozphys%ntime - !$OMP parallel num_threads(nthrds) default(none) & !$OMP shared(kdt,nsswr,lsswr,clstp,imfdeepcnv,cal_pre,random_clds) & !$OMP shared(fhswr,fhour,seed0,cnx,cny,nrcm,wrk,rannie,rndval) & @@ -841,8 +809,9 @@ subroutine GFS_phys_time_vary_timestep_init ( !$OMP shared(ozpl,ddy_o3,h2o_phys,jindx1_h,jindx2_h,h2opl,ddy_h,iaerclm,master) & !$OMP shared(levs,prsl,iccn,jindx1_ci,jindx2_ci,ddy_ci,iindx1_ci,iindx2_ci) & !$OMP shared(ddx_ci,in_nm,ccn_nm,do_ugwp_v1,jindx1_tau,jindx2_tau,ddy_j1tau) & -!$OMP shared(ddy_j2tau,tau_amf,iflip,ozphys) & -!$OMP private(iseed,iskip,i,j,k,rjday,n1,n2) +!$OMP shared(ddy_j2tau,tau_amf,iflip,ozphys,rjday,n1,n2,idat,jdat,rinc,rinc4) & +!$OMP shared(w3kindreal,w3kindint,jdow,jdoy,jday) & +!$OMP private(iseed,iskip,i,j,k) !$OMP sections @@ -892,6 +861,38 @@ subroutine GFS_phys_time_vary_timestep_init ( endif ! imfdeepcnv, cal_re, random_clds !$OMP section + !> - Compute temporal interpolation indices for updating gas concentrations. + idat=0 + idat(1)=idate(4) + idat(2)=idate(2) + idat(3)=idate(3) + idat(5)=idate(1) + rinc=0. + rinc(2)=fhour + call w3kind(w3kindreal,w3kindint) + if(w3kindreal==4) then + rinc4=rinc + CALL w3movdat(rinc4,idat,jdat) + else + CALL w3movdat(rinc,idat,jdat) + endif + jdow = 0 + jdoy = 0 + jday = 0 + call w3doxdat(jdat,jdow,jdoy,jday) + rjday = jdoy + jdat(5) / 24. + if (rjday < ozphys%time(1)) rjday = rjday + 365. + + n2 = ozphys%ntime + 1 + do j=2,ozphys%ntime + if (rjday < ozphys%time(j)) then + n2 = j + exit + endif + enddo + n1 = n2 - 1 + if (n2 > ozphys%ntime) n2 = n2 - ozphys%ntime + !> - Update ozone concentration. if (ntoz > 0) then call ozphys%update_o3prog(jindx1_o3, jindx2_o3, ddy_o3, rjday, n1, n2, ozpl) diff --git a/physics/GFS_suite_stateout_update.F90 b/physics/GFS_suite_stateout_update.F90 index 41f44e0de..e9e477fce 100644 --- a/physics/GFS_suite_stateout_update.F90 +++ b/physics/GFS_suite_stateout_update.F90 @@ -69,7 +69,8 @@ subroutine GFS_suite_stateout_update_run (im, levs, ntrac, dtp, tgrs, ugrs, vgrs do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz) endif if (oz_phys_2006) then - call ozphys%run_o3prog_2006() + call ozphys%run_o3prog_2006(con_1ovg, dtp, prsl, gt0, dp, ozpl, oz0, do3_dt_prd, & + do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz) endif ! If using Ferrier-Aligo microphysics, set bounds on the mass-weighted rime factor. diff --git a/physics/module_ozphys.F90 b/physics/module_ozphys.F90 index 205a02b46..d24585d4d 100644 --- a/physics/module_ozphys.F90 +++ b/physics/module_ozphys.F90 @@ -162,12 +162,12 @@ end subroutine update_o3prog ! ######################################################################################### ! Procedure (type-bound) for NRL prognostic ozone (2015). ! ######################################################################################### - subroutine run_o3prog_2015(this, con_1ovg, dt, p, t, dp, ozpl, oz, do3_dt_prd, do3_dt_ozmx, & - do3_dt_temp, do3_dt_ohoz) + subroutine run_o3prog_2015(this, con_1ovg, dt, p, t, dp, ozpl, oz, do3_dt_prd, & + do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz) class(ty_ozphys), intent(in) :: this - real(kind_phys),intent(in) :: & + real(kind_phys), intent(in) :: & con_1ovg ! Physical constant: One divided by gravitational acceleration (m-1 s2) - real(kind_phys), intent(in) :: & + real(kind_phys), intent(in) :: & dt ! Model timestep (sec) real(kind_phys), intent(in), dimension(:,:) :: & p, & ! Model Pressure (Pa) @@ -253,7 +253,7 @@ subroutine run_o3prog_2015(this, con_1ovg, dt, p, t, dp, ozpl, oz, do3_dt_prd, d prod(iCol,2) = min(prod(iCol,2), 0.0) enddo do iCol=1,nCol - ozib(iCol) = ozi(iCol,iLev) ! no filling + ozib(iCol) = ozi(iCol,iLev) tem = prod(iCol,1) - prod(iCol,2) * prod(iCol,6) & + prod(iCol,3) * (t(iCol,iLev) - prod(iCol,5)) & + prod(iCol,4) * (colo3(iCol,iLev)-coloz(iCol,iLev)) @@ -273,8 +273,123 @@ end subroutine run_o3prog_2015 ! ######################################################################################### ! Procedure (type-bound) for NRL prognostic ozone (2006). ! ######################################################################################### - subroutine run_o3prog_2006(this) + subroutine run_o3prog_2006(this, con_1ovg, dt, p, t, dp, ozpl, oz, do3_dt_prd, & + do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz) class(ty_ozphys), intent(in) :: this + real(kind_phys), intent(in) :: & + con_1ovg ! Physical constant: One divided by gravitational acceleration (m-1 s2) + real(kind_phys), intent(in) :: & + dt ! Model timestep (sec) + real(kind_phys), intent(in), dimension(:,:) :: & + p, & ! Model Pressure (Pa) + t, & ! Model temperature (K) + dp ! Model layer thickness (Pa) + real(kind_phys), intent(in), dimension(:,:,:) :: & + ozpl ! Ozone forcing data + real(kind_phys), intent(inout), dimension(:,:) :: & + oz ! Ozone concentration updated by physics + real(kind_phys), intent(inout), dimension(:,:), pointer, optional :: & + do3_dt_prd, & ! Physics tendency: production and loss effect + do3_dt_ozmx, & ! Physics tendency: ozone mixing ratio effect + do3_dt_temp, & ! Physics tendency: temperature effect + do3_dt_ohoz ! Physics tendency: overhead ozone effect + + ! Locals + integer :: k, kmax, kmin, iLev, iCol, nCol, nLev, iCf + logical, dimension(size(p,1)) :: flg + real(kind_phys) :: pmax, pmin, tem, temp + real(kind_phys), dimension(size(p,1)) :: wk1, wk2, wk3, ozib + real(kind_phys), dimension(size(p,1),this%ncf) :: prod + real(kind_phys), dimension(size(p,1),size(p,2)) :: ozi + real(kind_phys), dimension(size(p,1),size(p,2)+1) :: colo3, coloz + + ! Dimensions + nCol = size(p,1) + nLev = size(p,2) + + ! Temporaries + ozi = oz + + !> - Calculate vertical integrated column ozone values. + if (this%ncf > 2) then + colo3(:,nLev+1) = 0.0 + do iLev=nLev,1,-1 + do iCol=1,nCol + colo3(iCol,iLev) = colo3(iCol,iLev+1) + ozi(iCol,iLev) * dp(iCol,iLev) * con_1ovg + enddo + enddo + endif + + !> - Apply vertically linear interpolation to the ozone coefficients. + do iLev=1,nLev + pmin = 1.0e10 + pmax = -1.0e10 + + do iCol=1,nCol + wk1(iCol) = log(p(iCol,iLev)) + pmin = min(wk1(iCol), pmin) + pmax = max(wk1(iCol), pmax) + prod(iCol,:) = 0._kind_phys + enddo + kmax = 1 + kmin = 1 + do k=1,this%nlev-1 + if (pmin < this%po3(k)) kmax = k + if (pmax < this%po3(k)) kmin = k + enddo + + do k=kmin,kmax + temp = 1.0 / (this%po3(k) - this%po3(k+1)) + do iCol=1,nCol + flg(iCol) = .false. + if (wk1(iCol) < this%po3(k) .and. wk1(iCol) >= this%po3(k+1)) then + flg(iCol) = .true. + wk2(iCol) = (wk1(iCol) - this%po3(k+1)) * temp + wk3(iCol) = 1.0 - wk2(iCol) + endif + enddo + do iCf=1,this%ncf + do iCol=1,nCol + if (flg(iCol)) then + prod(iCol,iCf) = wk2(iCol) * ozpl(iCol,k,iCf) + wk3(iCol) * ozpl(iCol,k+1,iCf) + endif + enddo + enddo + enddo + + do iCf=1,this%ncf + do iCol=1,nCol + if (wk1(iCol) < this%po3(this%nlev)) then + prod(iCol,iCf) = ozpl(iCol,this%nlev,iCf) + endif + if (wk1(iCol) >= this%po3(1)) then + prod(iCol,iCf) = ozpl(iCol,1,iCf) + endif + enddo + enddo + + if (this%ncf == 2) then + do iCol=1,nCol + ozib(iCol) = ozi(iCol,iLev) + oz(iCol,iLev) = (ozib(iCol) + prod(iCol,1)*dt) / (1.0 + prod(iCol,2)*dt) + enddo + endif + + if (this%ncf == 4) then + do iCol=1,nCol + ozib(iCol) = ozi(iCol,iLev) + tem = prod(iCol,1) + prod(iCol,3)*t(iCol,iLev) + prod(iCol,4)*colo3(iCol,iLev+1) + oz(iCol,iLev) = (ozib(iCol) + tem*dt) / (1.0 + prod(iCol,2)*dt) + enddo + endif + ! Diagnostics (optional) + if (associated(do3_dt_prd)) do3_dt_prd(:,iLev) = prod(:,1)*dt + if (associated(do3_dt_ozmx)) do3_dt_ozmx(:,iLev) = (oz(:,iLev) - ozib(:)) + if (associated(do3_dt_temp)) do3_dt_temp(:,iLev) = prod(:,3) * t(:,iLev) * dt + if (associated(do3_dt_ohoz)) do3_dt_ohoz(:,iLev) = prod(:,4) * colo3(:,iLev) * dt + + enddo + return end subroutine run_o3prog_2006 diff --git a/physics/ozphys.f b/physics/ozphys.f deleted file mode 100644 index 18a9ae46f..000000000 --- a/physics/ozphys.f +++ /dev/null @@ -1,211 +0,0 @@ -!> \file ozphys.f -!! This file is ozone sources and sinks (previous version). - - -!> This module contains the CCPP-compliant Ozone photochemistry scheme. - module ozphys - - contains - -! \brief Brief description of the subroutine -! -!> \section arg_table_ozphys_init Argument Table -!! \htmlinclude ozphys_init.html -!! - subroutine ozphys_init(oz_phys, errmsg, errflg) - - implicit none - logical, intent(in) :: oz_phys - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - if (.not.oz_phys) then - write (errmsg,'(*(a))') 'Logic error: oz_phys == .false.' - errflg = 1 - return - endif - - end subroutine ozphys_init - -!>\defgroup GFS_ozphys GFS ozphys Main -!! \brief The operational GFS currently parameterizes ozone production and -!! destruction based on monthly mean coefficients (\c global_o3prdlos.f77) provided by Naval -!! Research Laboratory through CHEM2D chemistry model -!! (McCormack et al. (2006) \cite mccormack_et_al_2006). -!! \section arg_table_ozphys_run Argument Table -!! \htmlinclude ozphys_run.html -!! -!> \section genal_ozphys GFS ozphys_run General Algorithm -!> @{ - subroutine ozphys_run ( & - & im, levs, ko3, dt, oz, tin, po3, & - & prsl, prdout, oz_coeff, delp, ldiag3d, & - & ntoz, dtend, dtidx, index_of_process_prod_loss, & - & index_of_process_ozmix, index_of_process_temp, & - & index_of_process_overhead_ozone, con_g, me, errmsg, errflg) -! -! this code assumes that both prsl and po3 are from bottom to top -! as are all other variables -! - use machine , only : kind_phys - implicit none -! - ! Interface variables - integer, intent(in) :: im, levs, ko3, oz_coeff, me - real(kind=kind_phys), intent(inout) :: oz(:,:) - real(kind=kind_phys), intent(inout) :: dtend(:,:,:) - integer, intent(in) :: dtidx(:,:), ntoz, & - & index_of_process_prod_loss, index_of_process_ozmix, & - & index_of_process_temp, index_of_process_overhead_ozone - real(kind=kind_phys), intent(in) :: & - & dt, po3(:), prdout(:,:,:), & - & prsl(:,:), tin(:,:), delp(:,:), & - & con_g - real :: gravi - logical, intent(in) :: ldiag3d - - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg -! - ! Local variables - integer k,kmax,kmin,l,i,j, idtend(4) - logical flg(im) - real(kind=kind_phys) pmax, pmin, tem, temp - real(kind=kind_phys) wk1(im), wk2(im), wk3(im), prod(im,oz_coeff), - & ozib(im), colo3(im,levs+1), ozi(im,levs) -! - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 -! -! save input oz in ozi - ozi = oz - gravi=1.0/con_g - - - if(ldiag3d) then - idtend(1) = dtidx(100+ntoz,index_of_process_prod_loss) ! was ozp1 - idtend(2) = dtidx(100+ntoz,index_of_process_ozmix) ! was ozp2 - idtend(3) = dtidx(100+ntoz,index_of_process_temp) ! was ozp3 - idtend(4) = dtidx(100+ntoz,index_of_process_overhead_ozone) ! was ozp4 - else - idtend=0 - endif - -! -!> - Calculate vertical integrated column ozone values. - if (oz_coeff > 2) then - colo3(:,levs+1) = 0.0 - do l=levs,1,-1 - do i=1,im - colo3(i,l) = colo3(i,l+1) + ozi(i,l) * delp(i,l) * gravi - enddo - enddo - endif -! -!> - Apply vertically linear interpolation to the ozone coefficients. - do l=1,levs - pmin = 1.0e10 - pmax = -1.0e10 -! - do i=1,im - wk1(i) = log(prsl(i,l)) - pmin = min(wk1(i), pmin) - pmax = max(wk1(i), pmax) - prod(i,:) = 0.0 - enddo - kmax = 1 - kmin = 1 - do k=1,ko3-1 - if (pmin < po3(k)) kmax = k - if (pmax < po3(k)) kmin = k - enddo -! - do k=kmin,kmax - temp = 1.0 / (po3(k) - po3(k+1)) - do i=1,im - flg(i) = .false. - if (wk1(i) < po3(k) .and. wk1(i) >= po3(k+1)) then - flg(i) = .true. - wk2(i) = (wk1(i) - po3(k+1)) * temp - wk3(i) = 1.0 - wk2(i) - endif - enddo - do j=1,oz_coeff - do i=1,im - if (flg(i)) then - prod(i,j) = wk2(i) * prdout(i,k,j) - & + wk3(i) * prdout(i,k+1,j) - endif - enddo - enddo - enddo -! - do j=1,oz_coeff - do i=1,im - if (wk1(i) < po3(ko3)) then - prod(i,j) = prdout(i,ko3,j) - endif - if (wk1(i) >= po3(1)) then - prod(i,j) = prdout(i,1,j) - endif - enddo - enddo - - if (oz_coeff == 2) then - do i=1,im - ozib(i) = ozi(i,l) ! no filling - oz(i,l) = (ozib(i) + prod(i,1)*dt) / (1.0 + prod(i,2)*dt) - enddo -! - if(idtend(1)>=1) then - dtend(:,l,idtend(1)) = dtend(:,l,idtend(1)) + ! was ozp1 - & prod(:,1)*dt - endif - if(idtend(2)>=1) then - dtend(:,l,idtend(2)) = dtend(:,l,idtend(2)) + ! was ozp2 - & (oz(:,l) - ozib(:)) - endif - endif -!> - Calculate the 4 terms of prognostic ozone change during time \a dt: -!! - ozp1(:,:) - Ozone production from production/loss ratio -!! - ozp2(:,:) - Ozone production from ozone mixing ratio -!! - ozp3(:,:) - Ozone production from temperature term at model layers -!! - ozp4(:,:) - Ozone production from column ozone term at model layers - if (oz_coeff == 4) then - do i=1,im - ozib(i) = ozi(i,l) ! no filling - tem = prod(i,1) + prod(i,3)*tin(i,l) - & + prod(i,4)*colo3(i,l+1) -! if (me .eq. 0) print *,'ozphys tem=',tem,' prod=',prod(i,:) -! &,' ozib=',ozib(i),' l=',l,' tin=',tin(i,l),'colo3=',colo3(i,l+1) - oz(i,l) = (ozib(i) + tem*dt) / (1.0 + prod(i,2)*dt) - enddo - if(idtend(1)>=1) then - dtend(:,l,idtend(1)) = dtend(:,l,idtend(1)) + ! was ozp1 - & prod(:,1)*dt - endif - if(idtend(2)>=1) then - dtend(:,l,idtend(2)) = dtend(:,l,idtend(2)) + ! was ozp2 - & (oz(:,l)-ozib(:)) - endif - if(idtend(3)>=1) then - dtend(:,l,idtend(3)) = dtend(:,l,idtend(3)) + ! was ozp3 - & prod(:,3)*tin(:,l)*dt - endif - if(idtend(4)>=1) then - dtend(:,l,idtend(4)) = dtend(:,l,idtend(4)) + ! was ozp4 - & prod(:,4)*colo3(:,l+1)*dt - endif - endif - enddo ! vertical loop -! - return - end subroutine ozphys_run -!> @} - - end module ozphys diff --git a/physics/ozphys.meta b/physics/ozphys.meta deleted file mode 100644 index 485e2a491..000000000 --- a/physics/ozphys.meta +++ /dev/null @@ -1,208 +0,0 @@ -[ccpp-table-properties] - name = ozphys - type = scheme - dependencies = machine.F - -######################################################################## -[ccpp-arg-table] - name = ozphys_init - type = scheme -[oz_phys] - standard_name = flag_for_nrl_2006_ozone_scheme - long_name = flag for old (2006) ozone physics - units = flag - dimensions = () - type = logical - intent = in -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - -######################################################################## -[ccpp-arg-table] - name = ozphys_run - type = scheme -[im] - standard_name = horizontal_loop_extent - long_name = horizontal loop extent - units = count - dimensions = () - type = integer - intent = in -[levs] - standard_name = vertical_layer_dimension - long_name = number of vertical layers - units = count - dimensions = () - type = integer - intent = in -[ko3] - standard_name = vertical_dimension_of_ozone_forcing_data - long_name = number of vertical layers in ozone forcing data - units = count - dimensions = () - type = integer - intent = in -[dt] - standard_name = timestep_for_physics - long_name = physics time step - units = s - dimensions = () - type = real - kind = kind_phys - intent = in -[oz] - standard_name = ozone_concentration_of_new_state - long_name = ozone concentration updated by physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = inout -[tin] - standard_name = air_temperature_of_new_state - long_name = updated air temperature - units = K - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = in -[po3] - standard_name = natural_log_of_ozone_forcing_data_pressure_levels - long_name = natural log of ozone forcing data pressure levels - units = 1 - dimensions = (vertical_dimension_of_ozone_forcing_data) - type = real - kind = kind_phys - intent = in -[prsl] - standard_name = air_pressure - long_name = mid-layer pressure - units = Pa - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = in -[prdout] - standard_name = ozone_forcing - long_name = ozone forcing coefficients - units = mixed - dimensions = (horizontal_loop_extent,vertical_dimension_of_ozone_forcing_data,number_of_coefficients_in_ozone_forcing_data) - type = real - kind = kind_phys - intent = in -[oz_coeff] - standard_name = number_of_coefficients_in_ozone_forcing_data - long_name = number of coefficients in ozone forcing data - units = index - dimensions = () - type = integer - intent = in -[delp] - standard_name = air_pressure_difference_between_midlayers - long_name = difference between mid-layer pressures - units = Pa - dimensions = (horizontal_loop_extent,vertical_layer_dimension) - type = real - kind = kind_phys - intent = in -[ldiag3d] - standard_name = flag_for_diagnostics_3D - long_name = flag for calculating 3-D diagnostic fields - units = flag - dimensions = () - type = logical - intent = in -[dtend] - standard_name = cumulative_change_of_state_variables - long_name = diagnostic tendencies for state variables - units = mixed - dimensions = (horizontal_loop_extent,vertical_layer_dimension,cumulative_change_of_state_variables_outer_index_max) - type = real - kind = kind_phys - active = (flag_for_diagnostics_3D) - intent = inout -[dtidx] - standard_name = cumulative_change_of_state_variables_outer_index - long_name = index of state-variable and process in last dimension of diagnostic tendencies array AKA cumulative_change_index - units = index - dimensions = (number_of_tracers_plus_one_hundred,number_of_cumulative_change_processes) - type = integer - intent = in -[ntoz] - standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array - long_name = tracer index for ozone mixing ratio - units = index - dimensions = () - type = integer - intent = in -[index_of_process_prod_loss] - standard_name = index_of_production_and_loss_process_in_cumulative_change_index - long_name = index of production and loss effect in photochemistry process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[index_of_process_ozmix] - standard_name = index_of_ozone_mixing_ratio_process_in_cumulative_change_index - long_name = index of ozone mixing ratio effect in photochemistry process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[index_of_process_temp] - standard_name = index_of_temperature_process_in_cumulative_change_index - long_name = index of temperature effect in photochemistry process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[index_of_process_overhead_ozone] - standard_name = index_of_overhead_process_in_cumulative_change_index - long_name = index of overhead ozone effect in photochemistry process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[con_g] - standard_name = gravitational_acceleration - long_name = gravitational acceleration - units = m s-2 - dimensions = () - type = real - kind = kind_phys - intent = in -[me] - standard_name = mpi_rank - long_name = rank of the current MPI task - units = index - dimensions = () - type = integer - intent = in -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out From 00d90608a08f13ac367f2c002b8ae18eea4e8f6b Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Thu, 28 Sep 2023 17:19:33 +0000 Subject: [PATCH 17/25] Added documentation --- physics/GFS_physics_post.F90 | 12 +++- physics/module_ozphys.F90 | 119 +++++++++++++++++++++++------------ 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/physics/GFS_physics_post.F90 b/physics/GFS_physics_post.F90 index d034c1999..e6a50cc3a 100644 --- a/physics/GFS_physics_post.F90 +++ b/physics/GFS_physics_post.F90 @@ -1,6 +1,11 @@ ! ########################################################################################### !> \file GFS_physics_post.F90 !! +!! This module contains GFS specific calculations (e.g. diagnostics) and suite specific +!! code (e.g Saving fields for subsequent physics timesteps). For interoperability across a +!! wide range of hosts, CCPP compliant schemes should avoid including such calculations. This +!! module/scheme is intended for such "host-specific" computations. +!! ! ########################################################################################### module GFS_physics_post use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec @@ -30,9 +35,10 @@ end subroutine GFS_physics_post_init !! \section arg_table_GFS_physics_post_run Argument Table !! \htmlinclude GFS_physics_post_run.html !! - subroutine GFS_physics_post_run(nCol, nLev, ntoz, dtidx, ip_prod_loss, ip_ozmix, & - ip_temp, ip_overhead_ozone, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, dtend,& - errmsg, errflg) + subroutine GFS_physics_post_run(nCol, nLev, ntoz, dtidx, ip_prod_loss, ip_ozmix, ip_temp, & + ip_overhead_ozone, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, dtend, errmsg, & + errflg) + ! Inputs integer, intent(in) :: & nCol, & ! Horizontal dimension diff --git a/physics/module_ozphys.F90 b/physics/module_ozphys.F90 index d24585d4d..f824736b1 100644 --- a/physics/module_ozphys.F90 +++ b/physics/module_ozphys.F90 @@ -2,6 +2,39 @@ !> \section arg_table_module_ozphys Argument table !! \htmlinclude module_ozphys.html !! +! +!> The operational GFS currently parameterizes ozone production and destruction based on +!! monthly mean coefficients (\c global_o3prdlos.f77) provided by Naval Research Laboratory +!! through CHEM2D chemistry model (McCormack et al. (2006) \cite mccormack_et_al_2006). +!! +!! There are two implementations of this parameterization within this module. +!! run_o3prog_2006 - Relies on either two/four mean monthly coefficients. This is explained +!! in (https://doi.org/10.5194/acp-6-4943-2006. See Eq.(4)). +!! run_o3prog_2015 - Relies on six mean monthly coefficients, specifically for NRL +!! parameterization and climatological T and O3 are in location 5 and 6 of +!! the coefficient array. +!! +!! Both of these rely on the scheme being setup correctly by invoking the load(), setup(), +!! and update() procedures prior to calling the run() procedure. +!! +!! load_o3prog() - Read in data and load into type ty_ozphys (called once from host) +!! setup_o3prog() - Create spatial interpolation indices (called once, after model grid is known) +!! update_o3prog() - Update ozone concentration in time (call in physics loop, before run()) +!! *CAVEAT* Since the radiation is often run at a lower temporal resolution +!! than the rest of the physics, update_o3prog() needs to be +!! called before the radiation, which is called before the physics. +!! For example, within the physics loop: +!! update_o3prog() -> radiation() -> run_o3prog() -> physics.... +!! +!! Additionally, there is the functionality to not use interactive ozone, instead reverting +!! to ozone climatology. In this case, analagous to when using prognostic ozone, there are +!! update() and run() procedures that need to be called before the radiation. +!! For example, within the physics loop: +!! update_o3clim() -> run_o3clim() -> radiation() -> physics... +!! +!!\author June 2015 - Shrinivas Moorthi +!!\modified Sep 2023 - Dustin Swales +!! ! ######################################################################################### module module_ozphys use machine, only : kind_phys @@ -14,7 +47,8 @@ module module_ozphys !> \section arg_table_ty_ozphys Argument Table !! \htmlinclude ty_ozphys.html !! -!! All data field are ordered from surface-to-toa (j=1=isfc) +!> Derived type containing data and procedures needed by ozone photochemistry parameterization +!! *Note* All data field are ordered from surface-to-toa. !! ! ######################################################################################### type ty_ozphys @@ -54,7 +88,7 @@ module module_ozphys contains ! ######################################################################################### - ! Procedure (type-bound) for loading ozone forcing data. + ! Procedure (type-bound) for loading data for prognostic ozone. ! ######################################################################################### function load_o3prog(this, file, fileID) result (err_message) class(ty_ozphys), intent(inout) :: this @@ -101,7 +135,9 @@ function load_o3prog(this, file, fileID) result (err_message) end function load_o3prog ! ######################################################################################### - ! Procedure for setting up interpolation indices between data and model grid. + ! Procedure (type-bound) for setting up interpolation indices between data-grid and + ! model-grid. + ! Called once during initialization ! ######################################################################################### subroutine setup_o3prog(this, lat, idx1, idx2, idxh) class(ty_ozphys), intent(in) :: this @@ -130,7 +166,7 @@ subroutine setup_o3prog(this, lat, idx1, idx2, idxh) end subroutine setup_o3prog ! ######################################################################################### - ! Procedure (type-bound) for updating ozone data. + ! Procedure (type-bound) for updating data used in prognostic ozone scheme. ! ######################################################################################### subroutine update_o3prog(this, idx1, idx2, idxh, rjday, idxt1, idxt2, ozpl) class(ty_ozphys), intent(in) :: this @@ -474,7 +510,7 @@ subroutine run_o3clim(this, lat, prslk, con_pi, oz) end subroutine run_o3clim ! ######################################################################################### - ! Procedure (type-bound) for loading ozone climo data. + ! Procedure (type-bound) for loading data for climotological ozone. ! ######################################################################################### function load_o3clim(this, file, fileID) result (err_message) class(ty_ozphys), intent(inout) :: this @@ -546,46 +582,47 @@ function load_o3clim(this, file, fileID) result (err_message) this%pstr(iLev) = pstr4(iLev) this%pkstr(iLev) = fpkapx(this%pstr(iLev)*100.0) enddo - + end function load_o3clim - ! ######################################################################################### - ! Procedure (type-bound) for updating ozone climotological data. - ! ######################################################################################### - subroutine update_o3clim(this, imon, iday, ihour, loz1st) - class(ty_ozphys), intent(inout) :: this - integer, intent(in) :: imon, iday, ihour - logical, intent(in) :: loz1st - - integer :: midmon=15, midm=15, midp=45, id - integer, parameter, dimension(13) :: mdays = (/31,28,31,30,31,30,31,31,30,31,30,31,30/) - logical :: change - - midmon = mdays(imon)/2 + 1 - change = loz1st .or. ( (iday==midmon) .and. (ihour==0) ) + ! ######################################################################################### + ! Procedure (type-bound) for updating temporal interpolation index when using climotological + ! ozone + ! ######################################################################################### + subroutine update_o3clim(this, imon, iday, ihour, loz1st) + class(ty_ozphys), intent(inout) :: this + integer, intent(in) :: imon, iday, ihour + logical, intent(in) :: loz1st + + integer :: midmon=15, midm=15, midp=45, id + integer, parameter, dimension(13) :: mdays = (/31,28,31,30,31,30,31,31,30,31,30,31,30/) + logical :: change + + midmon = mdays(imon)/2 + 1 + change = loz1st .or. ( (iday==midmon) .and. (ihour==0) ) - if ( change ) then - if ( iday < midmon ) then - this%k1oz = mod(imon+10, 12) + 1 - midm = mdays(this%k1oz)/2 + 1 - this%k2oz = imon - midp = mdays(this%k1oz) + midmon - else - this%k1oz = imon - midm = midmon - this%k2oz = mod(imon, 12) + 1 - midp = mdays(this%k2oz)/2 + 1 + mdays(this%k1oz) - endif - endif + if ( change ) then + if ( iday < midmon ) then + this%k1oz = mod(imon+10, 12) + 1 + midm = mdays(this%k1oz)/2 + 1 + this%k2oz = imon + midp = mdays(this%k1oz) + midmon + else + this%k1oz = imon + midm = midmon + this%k2oz = mod(imon, 12) + 1 + midp = mdays(this%k2oz)/2 + 1 + mdays(this%k1oz) + endif + endif - if (iday < midmon) then - id = iday + mdays(this%k1oz) - else - id = iday - endif + if (iday < midmon) then + id = iday + mdays(this%k1oz) + else + id = iday + endif - this%facoz = float(id - midm) / float(midp - midm) + this%facoz = float(id - midm) / float(midp - midm) - end subroutine update_o3clim + end subroutine update_o3clim -end module module_ozphys + end module module_ozphys From e08ecd648a3f984a79e1dfd042f66edfbfb54d62 Mon Sep 17 00:00:00 2001 From: Helin Wei Date: Fri, 6 Oct 2023 15:07:48 -0400 Subject: [PATCH 18/25] land surface updates for hr3 --- physics/module_sf_noahmplsm.F90 | 15 +++++++++------ physics/noahmpdrv.F90 | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/physics/module_sf_noahmplsm.F90 b/physics/module_sf_noahmplsm.F90 index 86853dabe..8ced8930f 100644 --- a/physics/module_sf_noahmplsm.F90 +++ b/physics/module_sf_noahmplsm.F90 @@ -2116,7 +2116,7 @@ subroutine energy (parameters,ice ,vegtyp ,ist ,nsnow ,nsoil , & !in ! thermal properties of soil, snow, lake, and frozen soil call thermoprop (parameters,nsoil ,nsnow ,isnow ,ist ,dzsnso , & !in - dt ,snowh ,snice ,snliq , & !in + dt ,snowh ,snice ,snliq , shdfac, & !in smc ,sh2o ,tg ,stc ,ur , & !in lat ,z0m ,zlvl ,vegtyp , & !in df ,hcpct ,snicev ,snliqv ,epore , & !out @@ -2463,7 +2463,7 @@ end subroutine energy !>\ingroup NoahMP_LSM subroutine thermoprop (parameters,nsoil ,nsnow ,isnow ,ist ,dzsnso , & !in - dt ,snowh ,snice ,snliq , & !in + dt ,snowh ,snice ,snliq , shdfac, & !in smc ,sh2o ,tg ,stc ,ur , & !in lat ,z0m ,zlvl ,vegtyp , & !in df ,hcpct ,snicev ,snliqv ,epore , & !out @@ -2480,6 +2480,7 @@ subroutine thermoprop (parameters,nsoil ,nsnow ,isnow ,ist ,dzsnso , real (kind=kind_phys) , intent(in) :: dt !< time step [s] real (kind=kind_phys), dimension(-nsnow+1: 0), intent(in) :: snice !< snow ice mass (kg/m2) real (kind=kind_phys), dimension(-nsnow+1: 0), intent(in) :: snliq !< snow liq mass (kg/m2) + real (kind=kind_phys) , intent(in) :: shdfac !< green vegetation fraction [0.0-1.0] real (kind=kind_phys), dimension(-nsnow+1:nsoil), intent(in) :: dzsnso !< thickness of snow/soil layers [m] real (kind=kind_phys), dimension( 1:nsoil), intent(in) :: smc !< soil moisture (ice + liq.) [m3/m3] real (kind=kind_phys), dimension( 1:nsoil), intent(in) :: sh2o !< liquid soil moisture [m3/m3] @@ -2539,6 +2540,7 @@ subroutine thermoprop (parameters,nsoil ,nsnow ,isnow ,ist ,dzsnso , ! not in use because of the separation of the canopy layer from the ground. ! but this may represent the effects of leaf litter (niu comments) ! df1 = df1 * exp (sbeta * shdfac) + df(1) = df(1) * exp (sbeta * shdfac) ! compute lake thermal properties ! (no consideration of turbulent mixing for this version) @@ -4888,7 +4890,7 @@ subroutine bare_flux (parameters,nsnow ,nsoil ,isnow ,dt ,sag , & end if endif ! 4 -! use sfc_diag to calculate t2mv and q2v for opt_sfc=1&3 +! use sfc_diag to calculate t2mb and q2b for opt_sfc=1&3 if(opt_diag ==3) then if(opt_sfc == 1 .or. opt_sfc == 3) then @@ -5823,7 +5825,8 @@ subroutine thermalz0(parameters, fveg, z0m, z0mg, zlvl, elseif (opt_trs == chen09) then - z0m_out = exp(fveg * log(z0m) + (1.0 - fveg) * log(z0mg)) +! z0m_out = exp(fveg * log(z0m) + (1.0 - fveg) * log(z0mg)) +! z0m_out = fveg * z0m + (1.0 - fveg) * z0mg czil = 10.0 ** (- 0.4 * parameters%hvt) reyn = ustarx*z0m_out/viscosity ! Blumel99 eqn 36c @@ -5873,7 +5876,7 @@ subroutine thermalz0(parameters, fveg, z0m, z0mg, zlvl, z0h_out = z0m_out - elseif (opt_trs == tessel) then + elseif (opt_trs == chen09 .or. opt_trs == tessel) then if (vegtyp <= 5) then z0h_out = z0m_out @@ -5881,7 +5884,7 @@ subroutine thermalz0(parameters, fveg, z0m, z0mg, zlvl, z0h_out = z0m_out * 0.01 endif - elseif (opt_trs == blumel99 .or. opt_trs == chen09) then + elseif (opt_trs == blumel99) then reyn = ustarx*z0m_out/viscosity ! Blumel99 eqn 36c if (reyn > 2.0) then diff --git a/physics/noahmpdrv.F90 b/physics/noahmpdrv.F90 index 4500d51a8..c2c03d0de 100644 --- a/physics/noahmpdrv.F90 +++ b/physics/noahmpdrv.F90 @@ -450,7 +450,7 @@ subroutine noahmpdrv_run & integer :: iopt_pedo = 1 ! option for pedotransfer function integer :: iopt_crop = 0 ! option for crop model integer :: iopt_gla = 2 ! option for glacier treatment - integer :: iopt_z0m = 2 ! option for z0m treatment + integer :: iopt_z0m = 1 ! option for z0m treatment ! ! --- local inputs to noah-mp and glacier subroutines; listed in order in noah-mp call From 4f8004ab57b85d76884858849a5f4211f28d3084 Mon Sep 17 00:00:00 2001 From: Helin Wei Date: Fri, 6 Oct 2023 18:05:17 -0400 Subject: [PATCH 19/25] remove one printout from sfcsub.f and uncomment z0m composition in module_sf_noahmplsm.F90 --- physics/module_sf_noahmplsm.F90 | 2 +- physics/sfcsub.F | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/physics/module_sf_noahmplsm.F90 b/physics/module_sf_noahmplsm.F90 index 8ced8930f..6abd59f69 100644 --- a/physics/module_sf_noahmplsm.F90 +++ b/physics/module_sf_noahmplsm.F90 @@ -5826,7 +5826,7 @@ subroutine thermalz0(parameters, fveg, z0m, z0mg, zlvl, elseif (opt_trs == chen09) then ! z0m_out = exp(fveg * log(z0m) + (1.0 - fveg) * log(z0mg)) -! z0m_out = fveg * z0m + (1.0 - fveg) * z0mg + z0m_out = fveg * z0m + (1.0 - fveg) * z0mg czil = 10.0 ** (- 0.4 * parameters%hvt) reyn = ustarx*z0m_out/viscosity ! Blumel99 eqn 36c diff --git a/physics/sfcsub.F b/physics/sfcsub.F index 7be07b39c..494b8f7dc 100644 --- a/physics/sfcsub.F +++ b/physics/sfcsub.F @@ -7491,9 +7491,6 @@ subroutine clima(lugb,iy,im,id,ih,fh,len,lsoil,slmskl,slmskw, & endif call abort endif -! -! soil type - print *,'in FIXREAD fnsotc =',fnsotc ! if(fnsotc(1:8).ne.' ') then if ( index(fnsotc, "tileX.nc") == 0) then ! grib file From 1b2239714a949341409261ebbfb8a0bdf6a4f5da Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Thu, 12 Oct 2023 03:40:06 +0000 Subject: [PATCH 20/25] Some more cleanup --- physics/GFS_physics_post.F90 | 99 ++++++++++++++++++++++++++++++----- physics/GFS_physics_post.meta | 49 +++++++++++++++++ physics/phys_tend.F90 | 96 --------------------------------- physics/phys_tend.meta | 95 --------------------------------- 4 files changed, 134 insertions(+), 205 deletions(-) delete mode 100644 physics/phys_tend.F90 delete mode 100644 physics/phys_tend.meta diff --git a/physics/GFS_physics_post.F90 b/physics/GFS_physics_post.F90 index e6a50cc3a..def38cd1a 100644 --- a/physics/GFS_physics_post.F90 +++ b/physics/GFS_physics_post.F90 @@ -35,47 +35,62 @@ end subroutine GFS_physics_post_init !! \section arg_table_GFS_physics_post_run Argument Table !! \htmlinclude GFS_physics_post_run.html !! - subroutine GFS_physics_post_run(nCol, nLev, ntoz, dtidx, ip_prod_loss, ip_ozmix, ip_temp, & - ip_overhead_ozone, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, dtend, errmsg, & - errflg) + subroutine GFS_physics_post_run(nCol, nLev, ntoz, ntracp100, nprocess, nprocess_summed, & + dtidx, is_photochem, ldiag3d, ip_physics, ip_photochem, & + ip_prod_loss, ip_ozmix, ip_temp, ip_overhead_ozone, do3_dt_prd, do3_dt_ozmx, & + do3_dt_temp, do3_dt_ohoz, dtend, errmsg, errflg) ! Inputs integer, intent(in) :: & nCol, & ! Horizontal dimension nLev, & ! Number of vertical layers ntoz, & ! Index for ozone mixing ratio + ntracp100, & ! Number of tracers plus 100 + nprocess, & ! Number of processes that cause changes in state variables + nprocess_summed,& ! Number of causes in dtidx per tracer summed for total physics tendency + ip_physics, & ! Index for process in diagnostic tendency output + ip_photochem, & ! ip_prod_loss, & ! Index for process in diagnostic tendency output ip_ozmix, & ! Index for process in diagnostic tendency output ip_temp, & ! Index for process in diagnostic tendency output ip_overhead_ozone ! Index for process in diagnostic tendency output integer, intent(in), dimension(:,:) :: & dtidx ! Bookkeeping indices for GFS diagnostic tendencies + logical, intent(in) :: & + ldiag3d ! Flag for 3d diagnostic fields + logical, intent(in), dimension(:) :: & + is_photochem ! Flags for photochemistry processes to sum ! Inputs (optional) real(kind=kind_phys), intent(in), dimension(:,:), pointer, optional :: & - do3_dt_prd, & ! Physics tendency: production and loss effect - do3_dt_ozmx, & ! Physics tendency: ozone mixing ratio effect - do3_dt_temp, & ! Physics tendency: temperature effect - do3_dt_ohoz ! Physics tendency: overhead ozone effect + do3_dt_prd, & ! Physics tendency: production and loss effect + do3_dt_ozmx, & ! Physics tendency: ozone mixing ratio effect + do3_dt_temp, & ! Physics tendency: temperature effect + do3_dt_ohoz ! Physics tendency: overhead ozone effect ! Outputs real(kind=kind_phys), intent(inout), dimension(:,:,:) :: & - dtend ! Diagnostic tendencies for state variables + dtend ! Diagnostic tendencies for state variables character(len=*), intent(out) :: & - errmsg ! CCPP error message + errmsg ! CCPP error message integer, intent(out) :: & - errflg ! CCPP error flag + errflg ! CCPP error flag ! Locals - integer :: idtend - + integer :: idtend, ichem, iphys, itrac + logical :: all_true(nprocess) + ! Initialize CCPP error handling variables errmsg = '' errflg = 0 + if(.not.ldiag3d) then + return + endif + ! ####################################################################################### ! - ! Ozone physics diagnostic + ! Ozone physics diagnostics ! ! ####################################################################################### idtend = dtidx(100+ntoz,ip_prod_loss) @@ -98,6 +113,62 @@ subroutine GFS_physics_post_run(nCol, nLev, ntoz, dtidx, ip_prod_loss, ip_ozmix, dtend(:,:,idtend) = dtend(:,:,idtend) + do3_dt_ohoz endif - end subroutine GFS_physics_post_run + ! ####################################################################################### + ! + ! Total (photochemical) tendencies. + ! + ! ####################################################################################### + itrac = ntoz+100 + ichem = dtidx(itrac, ip_photochem) + if(ichem >= 1) then + call sum_it(ichem, itrac, is_photochem) + endif + ! ####################################################################################### + ! + ! Total (physics) tendencies + ! + ! ####################################################################################### + all_true = .true. + do itrac = 2,ntracp100 + iphys = dtidx(itrac,ip_physics) + if(iphys >= 1) then + call sum_it(iphys, itrac, all_true) + endif + enddo + + contains + + subroutine sum_it(isum,itrac,sum_me) + integer, intent(in) :: isum ! third index of dtend of summary process + integer, intent(in) :: itrac ! tracer or state variable being summed + logical, intent(in) :: sum_me(nprocess) ! false = skip this process + logical :: first + integer :: idtend, iprocess + + first=.true. + do iprocess=1,nprocess + if(iprocess>nprocess_summed) then + exit ! Don't sum up the sums. + else if(.not.sum_me(iprocess)) then + cycle ! We were asked to skip this one. + endif + idtend = dtidx(itrac,iprocess) + if(idtend>=1) then + ! This tendency was calculated for this tracer, so + ! accumulate it into the total tendency. + if(first) then + dtend(:,:,isum) = dtend(:,:,idtend) + first=.false. + else + dtend(:,:,isum) = dtend(:,:,isum) + dtend(:,:,idtend) + endif + endif + enddo + if(first) then + ! No tendencies were calculated, so sum is 0: + dtend(:,:,isum) = 0 + endif + end subroutine sum_it + end subroutine GFS_physics_post_run end module GFS_physics_post diff --git a/physics/GFS_physics_post.meta b/physics/GFS_physics_post.meta index 8b5120b9e..649ef6491 100644 --- a/physics/GFS_physics_post.meta +++ b/physics/GFS_physics_post.meta @@ -63,6 +63,55 @@ dimensions = () type = integer intent = in +[ntracp100] + standard_name = number_of_tracers_plus_one_hundred + long_name = number of tracers plus one hundred + units = count + dimensions = () + type = integer + intent = in +[nprocess] + standard_name = number_of_cumulative_change_processes + long_name = number of processes that cause changes in state variables + units = count + dimensions = () + type = integer + intent = in +[nprocess_summed] + standard_name = number_of_physics_causes_of_tracer_changes + long_name = number of causes in dtidx per tracer summed for total physics tendency + units = count + dimensions = () + type = integer + intent = in +[ip_physics] + standard_name = index_of_all_physics_process_in_cumulative_change_index + long_name = index of all physics transport process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer + intent = in +[ip_photochem] + standard_name = index_of_photochemistry_process_in_cumulative_change_index + long_name = index of photochemistry process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer + intent = in +[is_photochem] + standard_name = flags_for_photochemistry_processes_to_sum + long_name = flags for photochemistry processes to sum as the total photochemistry process cumulative change + units = flag + dimensions = (number_of_cumulative_change_processes) + type = logical + intent = in +[ldiag3d] + standard_name = flag_for_diagnostics_3D + long_name = flag for 3d diagnostic fields + units = flag + dimensions = () + type = logical + intent = in [ip_prod_loss] standard_name = index_of_production_and_loss_process_in_cumulative_change_index long_name = index of production and loss effect in photochemistry process in second dimension of array cumulative change index diff --git a/physics/phys_tend.F90 b/physics/phys_tend.F90 deleted file mode 100644 index e63f44be5..000000000 --- a/physics/phys_tend.F90 +++ /dev/null @@ -1,96 +0,0 @@ -!>\file phys_tend.F90 -!! -module phys_tend - - use machine, only: kind_phys - - implicit none - - private - - public phys_tend_run - -contains - -!> \section arg_table_phys_tend_run Argument Table -!! \htmlinclude phys_tend_run.html -!! - subroutine phys_tend_run(ldiag3d, dtend, dtidx, ntracp100, & - index_of_process_physics, index_of_process_photochem, & - nprocess, nprocess_summed, is_photochem, ntoz, errmsg, errflg) - - ! Interface variables - logical, intent(in) :: ldiag3d, is_photochem(:) - real(kind=kind_phys), optional, intent(inout) :: dtend(:,:,:) - integer, intent(in) :: dtidx(:,:), index_of_process_physics, ntoz, & - ntracp100, nprocess, nprocess_summed, index_of_process_photochem - character(len=*), intent(out) :: errmsg - integer, intent(out) :: errflg - - integer :: ichem, iphys, itrac - logical :: all_true(nprocess) - - ! Initialize CCPP error handling variables - errmsg = '' - errflg = 0 - - if(.not.ldiag3d) then - return - endif - - all_true = .true. - - ! Total photochemical tendencies - itrac=ntoz+100 - ichem = dtidx(itrac,index_of_process_photochem) - if(ichem>=1) then - call sum_it(ichem,itrac,is_photochem) - endif - - - do itrac=2,ntracp100 - ! Total physics tendencies - iphys = dtidx(itrac,index_of_process_physics) - if(iphys>=1) then - call sum_it(iphys,itrac,all_true) - endif - enddo - - contains - - subroutine sum_it(isum,itrac,sum_me) - implicit none - integer, intent(in) :: isum ! third index of dtend of summary process - integer, intent(in) :: itrac ! tracer or state variable being summed - logical, intent(in) :: sum_me(nprocess) ! false = skip this process - logical :: first - integer :: idtend, iprocess - - first=.true. - do iprocess=1,nprocess - if(iprocess>nprocess_summed) then - exit ! Don't sum up the sums. - else if(.not.sum_me(iprocess)) then - cycle ! We were asked to skip this one. - endif - idtend = dtidx(itrac,iprocess) - if(idtend>=1) then - ! This tendency was calculated for this tracer, so - ! accumulate it into the total tendency. - if(first) then - dtend(:,:,isum) = dtend(:,:,idtend) - first=.false. - else - dtend(:,:,isum) = dtend(:,:,isum) + dtend(:,:,idtend) - endif - endif - enddo - if(first) then - ! No tendencies were calculated, so sum is 0: - dtend(:,:,isum) = 0 - endif - end subroutine sum_it - - end subroutine phys_tend_run - -end module phys_tend diff --git a/physics/phys_tend.meta b/physics/phys_tend.meta deleted file mode 100644 index 0f78af20b..000000000 --- a/physics/phys_tend.meta +++ /dev/null @@ -1,95 +0,0 @@ -[ccpp-table-properties] - name = phys_tend - type = scheme - dependencies = machine.F - -######################################################################## -[ccpp-arg-table] - name = phys_tend_run - type = scheme -[ldiag3d] - standard_name = flag_for_diagnostics_3D - long_name = flag for 3d diagnostic fields - units = flag - dimensions = () - type = logical - intent = in -[dtend] - standard_name = cumulative_change_of_state_variables - long_name = diagnostic tendencies for state variables - units = mixed - dimensions = (horizontal_loop_extent,vertical_layer_dimension,cumulative_change_of_state_variables_outer_index_max) - type = real - kind = kind_phys - intent = inout -[dtidx] - standard_name = cumulative_change_of_state_variables_outer_index - long_name = index of state-variable and process in last dimension of diagnostic tendencies array AKA cumulative_change_index - units = index - dimensions = (number_of_tracers_plus_one_hundred,number_of_cumulative_change_processes) - type = integer - intent = in -[ntracp100] - standard_name = number_of_tracers_plus_one_hundred - long_name = number of tracers plus one hundred - units = count - dimensions = () - type = integer - intent = in -[index_of_process_physics] - standard_name = index_of_all_physics_process_in_cumulative_change_index - long_name = index of all physics transport process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[index_of_process_photochem] - standard_name = index_of_photochemistry_process_in_cumulative_change_index - long_name = index of photochemistry process in second dimension of array cumulative change index - units = index - dimensions = () - type = integer - intent = in -[nprocess] - standard_name = number_of_cumulative_change_processes - long_name = number of processes that cause changes in state variables - units = count - dimensions = () - type = integer - intent = in -[nprocess_summed] - standard_name = number_of_physics_causes_of_tracer_changes - long_name = number of causes in dtidx per tracer summed for total physics tendency - units = count - dimensions = () - type = integer - intent = in -[is_photochem] - standard_name = flags_for_photochemistry_processes_to_sum - long_name = flags for photochemistry processes to sum as the total photochemistry process cumulative change - units = flag - dimensions = (number_of_cumulative_change_processes) - type = logical - intent = in -[ntoz] - standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array - long_name = tracer index for ozone mixing ratio - units = index - dimensions = () - type = integer - intent = in -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out From 06bb2bcc9ea2fa5dd52d8f0aa8be2f41b65ab8c0 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Thu, 12 Oct 2023 15:17:00 +0000 Subject: [PATCH 21/25] Final cleanup --- physics/GFS_phys_time_vary.scm.F90 | 83 +++++++++++++++++++++++------ physics/GFS_phys_time_vary.scm.meta | 75 +++++++++++++++++++++++++- physics/GFS_physics_post.F90 | 24 ++------- physics/GFS_physics_post.meta | 20 ------- 4 files changed, 144 insertions(+), 58 deletions(-) diff --git a/physics/GFS_phys_time_vary.scm.F90 b/physics/GFS_phys_time_vary.scm.F90 index 97460ac98..075bfc039 100644 --- a/physics/GFS_phys_time_vary.scm.F90 +++ b/physics/GFS_phys_time_vary.scm.F90 @@ -2,15 +2,17 @@ !! Contains code related to GFS physics suite setup (physics part of time_vary_step) !>\defgroup mod_GFS_phys_time_vary GFS Physics Time Update -!! This module contains GFS physics time vary subroutines including, stratospheric water vapor, +!! This module contains GFS physics time vary subroutines including stratospheric water vapor, !! aerosol, IN&CCN and surface properties updates. !> @{ module GFS_phys_time_vary - use machine, only : kind_phys + use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec use mersenne_twister, only: random_setseed, random_number + use module_ozphys, only: ty_ozphys + use h2o_def, only : levh2o, h2o_coeff, h2o_lat, h2o_pres, h2o_time, h2oplin use h2ointerp, only : read_h2odata, setindxh2o, h2ointerpol @@ -58,8 +60,8 @@ module GFS_phys_time_vary !>\section gen_GFS_phys_time_vary_init GFS_phys_time_vary_init General Algorithm !! @{ subroutine GFS_phys_time_vary_init ( & - me, master, h2o_phys, iaerclm, iccn, iflip, im, nx, ny, idate, xlat_d, xlon_d, & - jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & + me, master, ntoz, h2o_phys, iaerclm, iccn, iflip, im, nx, ny, idate, xlat_d, xlon_d, & + jindx1_o3, jindx2_o3, ddy_o3, ozphys, jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & jindx1_aer, jindx2_aer, ddy_aer, iindx1_aer, iindx2_aer, ddx_aer, aer_nm, & jindx1_ci, jindx2_ci, ddy_ci, iindx1_ci, iindx2_ci, ddx_ci, imap, jmap, & do_ugwp_v1, jindx1_tau, jindx2_tau, ddy_j1tau, ddy_j2tau, & @@ -76,14 +78,14 @@ subroutine GFS_phys_time_vary_init ( implicit none ! Interface variables - integer, intent(in) :: me, master, iccn, iflip, im, nx, ny + integer, intent(in) :: me, master, ntoz, iccn, iflip, im, nx, ny logical, intent(in) :: h2o_phys, iaerclm, lsm_cold_start integer, intent(in) :: idate(:) real(kind_phys), intent(in) :: fhour real(kind_phys), intent(in) :: xlat_d(:), xlon_d(:) - integer, intent(inout) :: jindx1_h(:), jindx2_h(:) - real(kind_phys), intent(inout) :: ddy_h(:) + integer, intent(inout) :: jindx1_o3(:), jindx2_o3(:), jindx1_h(:), jindx2_h(:) + real(kind_phys), intent(inout) :: ddy_o3(:), ddy_h(:) real(kind_phys), intent(in) :: h2opl(:,:,:) integer, intent(inout) :: jindx1_aer(:), jindx2_aer(:), iindx1_aer(:), iindx2_aer(:) real(kind_phys), intent(inout) :: ddy_aer(:), ddx_aer(:) @@ -101,6 +103,7 @@ subroutine GFS_phys_time_vary_init ( real(kind_phys), intent(in) :: min_seaice, fice(:) real(kind_phys), intent(in) :: landfrac(:) real(kind_phys), intent(inout) :: weasd(:) + type(ty_ozphys), intent(in) :: ozphys ! NoahMP - only allocated when NoahMP is used integer, intent(in) :: lsoil, lsnow_lsm_lbound, lsnow_lsm_ubound @@ -244,6 +247,11 @@ subroutine GFS_phys_time_vary_init ( !> - Initialize soil vegetation (needed for sncovr calculation further down) call set_soilveg(me, isot, ivegsrc, nlunit, errmsg, errflg) +!> - Setup spatial interpolation indices for ozone physics. + if (ntoz > 0) then + call ozphys%setup_o3prog(xlat_d, jindx1_o3, jindx2_o3, ddy_o3) + endif + !> - Call setindxh2o() to initialize stratospheric water vapor data if (h2o_phys) then call setindxh2o (im, xlat_d, jindx1_h, jindx2_h, ddy_h) @@ -625,8 +633,8 @@ end subroutine GFS_phys_time_vary_init !! @{ subroutine GFS_phys_time_vary_timestep_init ( & me, master, cnx, cny, isc, jsc, nrcm, im, levs, kdt, idate, nsswr, fhswr, lsswr, fhour, & - imfdeepcnv, cal_pre, random_clds, h2o_phys, iaerclm, iccn, clstp, & - jindx1_h, jindx2_h, ddy_h, h2opl, iflip, & + imfdeepcnv, cal_pre, random_clds, ozphys, ntoz, h2o_phys, iaerclm, iccn, clstp, & + jindx1_o3, jindx2_o3, ddy_o3, ozpl, jindx1_h, jindx2_h, ddy_h, h2opl, iflip, & jindx1_aer, jindx2_aer, ddy_aer, iindx1_aer, iindx2_aer, ddx_aer, aer_nm, & jindx1_ci, jindx2_ci, ddy_ci, iindx1_ci, iindx2_ci, ddx_ci, in_nm, ccn_nm, & imap, jmap, prsl, seed0, rann, do_ugwp_v1, jindx1_tau, jindx2_tau, ddy_j1tau, ddy_j2tau,& @@ -636,14 +644,14 @@ subroutine GFS_phys_time_vary_timestep_init ( ! Interface variables integer, intent(in) :: me, master, cnx, cny, isc, jsc, nrcm, im, levs, kdt, & - nsswr, imfdeepcnv, iccn, iflip + nsswr, imfdeepcnv, iccn, ntoz, iflip integer, intent(in) :: idate(:) real(kind_phys), intent(in) :: fhswr, fhour logical, intent(in) :: lsswr, cal_pre, random_clds, h2o_phys, iaerclm real(kind_phys), intent(out) :: clstp - integer, intent(in) :: jindx1_h(:), jindx2_h(:) - real(kind_phys), intent(in) :: ddy_h(:) - real(kind_phys), intent(inout) :: h2opl(:,:,:) + integer, intent(in) :: jindx1_o3(:), jindx2_o3(:), jindx1_h(:), jindx2_h(:) + real(kind_phys), intent(in) :: ddy_o3(:), ddy_h(:) + real(kind_phys), intent(inout) :: ozpl(:,:,:), h2opl(:,:,:) integer, intent(in) :: jindx1_aer(:), jindx2_aer(:), iindx1_aer(:), iindx2_aer(:) real(kind_phys), intent(in) :: ddy_aer(:), ddx_aer(:) real(kind_phys), intent(inout) :: aer_nm(:,:,:) @@ -659,15 +667,19 @@ subroutine GFS_phys_time_vary_timestep_init ( integer, intent(in) :: jindx1_tau(:), jindx2_tau(:) real(kind_phys), intent(in) :: ddy_j1tau(:), ddy_j2tau(:) real(kind_phys), intent(inout) :: tau_amf(:) + type(ty_ozphys), intent(in) :: ozphys integer, intent(in) :: nthrds character(len=*), intent(out) :: errmsg integer, intent(out) :: errflg ! Local variables - integer :: i, j, k, iseed, iskip, ix - real(kind=kind_phys) :: wrk(1) - real(kind=kind_phys) :: rannie(cny) - real(kind=kind_phys) :: rndval(cnx*cny*nrcm) + integer :: i, j, k, iseed, iskip, ix, idat(8), jdat(8), iday, j1, j2, nc, n1, n2, jdow, & + jdoy, jday, w3kindreal, w3kindint + real(kind_phys) :: wrk(1), tem, tx1, tx2, rjday + real(kind_phys) :: rannie(cny) + real(kind_phys) :: rndval(cnx*cny*nrcm) + real(kind_dbl_prec) :: rinc(5) + real(kind_sngl_prec) :: rinc4(5) ! Initialize CCPP error handling variables errmsg = '' @@ -721,6 +733,43 @@ subroutine GFS_phys_time_vary_timestep_init ( endif ! imfdeepcnv, cal_re, random_clds + !> - Compute temporal interpolation indices for updating gas concentrations. + idat=0 + idat(1)=idate(4) + idat(2)=idate(2) + idat(3)=idate(3) + idat(5)=idate(1) + rinc=0. + rinc(2)=fhour + call w3kind(w3kindreal,w3kindint) + if(w3kindreal==4) then + rinc4=rinc + CALL w3movdat(rinc4,idat,jdat) + else + CALL w3movdat(rinc,idat,jdat) + endif + jdow = 0 + jdoy = 0 + jday = 0 + call w3doxdat(jdat,jdow,jdoy,jday) + rjday = jdoy + jdat(5) / 24. + if (rjday < ozphys%time(1)) rjday = rjday + 365. + + n2 = ozphys%ntime + 1 + do j=2,ozphys%ntime + if (rjday < ozphys%time(j)) then + n2 = j + exit + endif + enddo + n1 = n2 - 1 + if (n2 > ozphys%ntime) n2 = n2 - ozphys%ntime + +!> - Update ozone concentration. + if (ntoz > 0) then + call ozphys%update_o3prog(jindx1_o3, jindx2_o3, ddy_o3, rjday, n1, n2, ozpl) + endif + !> - Call h2ointerpol() to make stratospheric water vapor data interpolation if (h2o_phys) then call h2ointerpol (me, im, idate, fhour, & diff --git a/physics/GFS_phys_time_vary.scm.meta b/physics/GFS_phys_time_vary.scm.meta index 21d1f2736..cf5ad15ca 100644 --- a/physics/GFS_phys_time_vary.scm.meta +++ b/physics/GFS_phys_time_vary.scm.meta @@ -2,7 +2,7 @@ name = GFS_phys_time_vary type = scheme dependencies = aerclm_def.F,aerinterp.F90,h2o_def.f,h2ointerp.f90,iccn_def.F,iccninterp.F90,machine.F,mersenne_twister.f - dependencies = namelist_soilveg.f,set_soilveg.f,cires_tauamf_data.F90,noahmp_tables.f90 + dependencies = namelist_soilveg.f,set_soilveg.f,module_ozphys.F90,cires_tauamf_data.F90,noahmp_tables.f90 ######################################################################## [ccpp-arg-table] @@ -23,6 +23,13 @@ dimensions = () type = integer intent = in +[ntoz] + standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array + long_name = tracer index for ozone mixing ratio + units = index + dimensions = () + type = integer + intent = in [h2o_phys] standard_name = flag_for_stratospheric_water_vapor_physics long_name = flag for stratospheric water vapor physics @@ -95,6 +102,28 @@ type = real kind = kind_phys intent = in +[jindx1_o3] + standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation low index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = inout +[jindx2_o3] + standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation high index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = inout +[ddy_o3] + standard_name = latitude_interpolation_weight_for_ozone_forcing + long_name = interpolation high index for ozone + units = none + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = inout [jindx1_h] standard_name = lower_latitude_index_of_stratospheric_water_vapor_forcing_for_interpolation long_name = interpolation low index for stratospheric water vapor @@ -1019,6 +1048,13 @@ dimensions = () type = logical intent = in +[ntoz] + standard_name = index_of_ozone_mixing_ratio_in_tracer_concentration_array + long_name = tracer index for ozone mixing ratio + units = index + dimensions = () + type = integer + intent = in [h2o_phys] standard_name = flag_for_stratospheric_water_vapor_physics long_name = flag for stratospheric water vapor physics @@ -1048,6 +1084,36 @@ type = real kind = kind_phys intent = out +[jindx1_o3] + standard_name = lower_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation low index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[jindx2_o3] + standard_name = upper_latitude_index_of_ozone_forcing_for_interpolation + long_name = interpolation high index for ozone + units = index + dimensions = (horizontal_dimension) + type = integer + intent = in +[ddy_o3] + standard_name = latitude_interpolation_weight_for_ozone_forcing + long_name = interpolation high index for ozone + units = none + dimensions = (horizontal_dimension) + type = real + kind = kind_phys + intent = in +[ozpl] + standard_name = ozone_forcing + long_name = ozone forcing data + units = mixed + dimensions = (horizontal_dimension,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) + type = real + kind = kind_phys + intent = inout [jindx1_h] standard_name = lower_latitude_index_of_stratospheric_water_vapor_forcing_for_interpolation long_name = interpolation low index for stratospheric water vapor @@ -1279,6 +1345,13 @@ type = real kind = kind_phys intent = inout +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed + dimensions = () + type = ty_ozphys + intent = in [nthrds] standard_name = number_of_openmp_threads long_name = number of OpenMP threads available for physics schemes diff --git a/physics/GFS_physics_post.F90 b/physics/GFS_physics_post.F90 index def38cd1a..f89b257a8 100644 --- a/physics/GFS_physics_post.F90 +++ b/physics/GFS_physics_post.F90 @@ -13,22 +13,6 @@ module GFS_physics_post public GFS_physics_post_init, GFS_physics_post_run contains -! ########################################################################################### -! SUBROUTINE GFS_physics_post_init -! ########################################################################################### -!! \section arg_table_GFS_physics_post_init Argument Table -!! \htmlinclude GFS_physics_post_init.html -!! - subroutine GFS_physics_post_init(errmsg, errflg) - - ! Outputs - character(len=*), intent(out) :: & - errmsg ! CCPP error message - integer, intent(out) :: & - errflg ! CCPP error flag - - end subroutine GFS_physics_post_init - ! ########################################################################################### ! SUBROUTINE GFS_physics_post_run ! ########################################################################################### @@ -36,9 +20,9 @@ end subroutine GFS_physics_post_init !! \htmlinclude GFS_physics_post_run.html !! subroutine GFS_physics_post_run(nCol, nLev, ntoz, ntracp100, nprocess, nprocess_summed, & - dtidx, is_photochem, ldiag3d, ip_physics, ip_photochem, & - ip_prod_loss, ip_ozmix, ip_temp, ip_overhead_ozone, do3_dt_prd, do3_dt_ozmx, & - do3_dt_temp, do3_dt_ohoz, dtend, errmsg, errflg) + dtidx, is_photochem, ldiag3d, ip_physics, ip_photochem, ip_prod_loss, ip_ozmix, & + ip_temp, ip_overhead_ozone, do3_dt_prd, do3_dt_ozmx, do3_dt_temp, do3_dt_ohoz, & + dtend, errmsg, errflg) ! Inputs integer, intent(in) :: & @@ -49,7 +33,7 @@ subroutine GFS_physics_post_run(nCol, nLev, ntoz, ntracp100, nprocess, nprocess_ nprocess, & ! Number of processes that cause changes in state variables nprocess_summed,& ! Number of causes in dtidx per tracer summed for total physics tendency ip_physics, & ! Index for process in diagnostic tendency output - ip_photochem, & ! + ip_photochem, & ! Index for process in diagnostic tendency output ip_prod_loss, & ! Index for process in diagnostic tendency output ip_ozmix, & ! Index for process in diagnostic tendency output ip_temp, & ! Index for process in diagnostic tendency output diff --git a/physics/GFS_physics_post.meta b/physics/GFS_physics_post.meta index 649ef6491..5701909fd 100644 --- a/physics/GFS_physics_post.meta +++ b/physics/GFS_physics_post.meta @@ -3,26 +3,6 @@ type = scheme dependencies = machine.F -######################################################################## -[ccpp-arg-table] - name = GFS_physics_post_init - type = scheme -[errmsg] - standard_name = ccpp_error_message - long_name = error message for error handling in CCPP - units = none - dimensions = () - type = character - kind = len=* - intent = out -[errflg] - standard_name = ccpp_error_code - long_name = error code for error handling in CCPP - units = 1 - dimensions = () - type = integer - intent = out - ######################################################################## [ccpp-arg-table] name = GFS_physics_post_run From 89af3d8946ab25737628a016fe89356a261155ac Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Thu, 12 Oct 2023 15:45:58 +0000 Subject: [PATCH 22/25] Omission from previous commit --- physics/GFS_physics_post.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/physics/GFS_physics_post.F90 b/physics/GFS_physics_post.F90 index f89b257a8..fe5409353 100644 --- a/physics/GFS_physics_post.F90 +++ b/physics/GFS_physics_post.F90 @@ -10,7 +10,7 @@ module GFS_physics_post use machine, only : kind_phys, kind_dbl_prec, kind_sngl_prec implicit none - public GFS_physics_post_init, GFS_physics_post_run + public GFS_physics_post_run contains ! ########################################################################################### From 2f417bb5f8c1e814ea5f3539615395d9ed096eca Mon Sep 17 00:00:00 2001 From: Helin Wei Date: Tue, 17 Oct 2023 12:32:30 -0400 Subject: [PATCH 23/25] refine surface 2m t/q diagnostic method --- physics/sfc_diag_post.F90 | 24 ++++++++++++++++++------ physics/sfc_diag_post.meta | 7 +++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/physics/sfc_diag_post.F90 b/physics/sfc_diag_post.F90 index c1a43f170..6945e48e9 100644 --- a/physics/sfc_diag_post.F90 +++ b/physics/sfc_diag_post.F90 @@ -14,16 +14,17 @@ module sfc_diag_post !! #endif subroutine sfc_diag_post_run (im, lsm, lsm_noahmp, opt_diag, dry, lssav, dtf, con_eps, con_epsm1, pgr,& - t2mmp,q2mp, t2m, q2m, u10m, v10m, tmpmin, tmpmax, spfhmin, spfhmax, & + vegtype,t2mmp,q2mp, t2m, q2m, u10m, v10m, tmpmin, tmpmax, spfhmin, spfhmax, & wind10mmax, u10mmax, v10mmax, dpt2m, errmsg, errflg) use machine, only: kind_phys, kind_dbl_prec implicit none - integer, intent(in) :: im, lsm, lsm_noahmp,opt_diag - logical, intent(in) :: lssav - real(kind=kind_phys), intent(in) :: dtf, con_eps, con_epsm1 + integer, intent(in) :: im, lsm, lsm_noahmp,opt_diag + integer, dimension(:), intent(in) :: vegtype ! vegetation type (integer index) + logical, intent(in) :: lssav + real(kind=kind_phys), intent(in) :: dtf, con_eps, con_epsm1 logical , dimension(:), intent(in) :: dry real(kind=kind_phys), dimension(:), intent(in) :: pgr, u10m, v10m real(kind=kind_phys), dimension(:), intent(inout) :: t2m, q2m, tmpmin, tmpmax, spfhmin, spfhmax @@ -41,12 +42,23 @@ subroutine sfc_diag_post_run (im, lsm, lsm_noahmp, opt_diag, dry, lssav, dtf, co errflg = 0 if (lsm == lsm_noahmp) then - if (opt_diag == 2 .or. opt_diag == 3)then +! over shrublands use opt_diag=2 + do i=1, im + if(dry(i)) then + if (vegtype(i) == 6 .or. vegtype(i) == 7 & + .or. vegtype(i) == 16) then + t2m(i) = t2mmp(i) + q2m(i) = q2mp(i) + endif + endif + enddo + + if (opt_diag == 2 .or. opt_diag == 3) then do i=1,im if(dry(i)) then t2m(i) = t2mmp(i) q2m(i) = q2mp(i) - endif + endif enddo endif endif diff --git a/physics/sfc_diag_post.meta b/physics/sfc_diag_post.meta index c50d3c4dc..17648753a 100644 --- a/physics/sfc_diag_post.meta +++ b/physics/sfc_diag_post.meta @@ -81,6 +81,13 @@ type = real kind = kind_phys intent = in +[vegtype] + standard_name = vegetation_type_classification + long_name = vegetation type at each grid cell + units = index + dimensions = (horizontal_loop_extent) + type = integer + intent= in [t2mmp] standard_name = temperature_at_2m_from_noahmp long_name = 2 meter temperature from noahmp From 32cf7ba5484db1387e33c7f9d25de87079e9014c Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Fri, 27 Oct 2023 17:01:01 +0000 Subject: [PATCH 24/25] Reverted standard_name change --- physics/GFS_phys_time_vary.fv3.meta | 2 +- physics/GFS_phys_time_vary.scm.meta | 2 +- physics/GFS_suite_stateout_update.meta | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/physics/GFS_phys_time_vary.fv3.meta b/physics/GFS_phys_time_vary.fv3.meta index ad543e146..968f33027 100644 --- a/physics/GFS_phys_time_vary.fv3.meta +++ b/physics/GFS_phys_time_vary.fv3.meta @@ -1205,7 +1205,7 @@ standard_name = ozone_forcing long_name = ozone forcing data units = mixed - dimensions = (horizontal_dimension,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) + dimensions = (horizontal_dimension,vertical_dimension_of_ozone_forcing_data,number_of_coefficients_in_ozone_data) type = real kind = kind_phys intent = inout diff --git a/physics/GFS_phys_time_vary.scm.meta b/physics/GFS_phys_time_vary.scm.meta index cf5ad15ca..d72e27fd5 100644 --- a/physics/GFS_phys_time_vary.scm.meta +++ b/physics/GFS_phys_time_vary.scm.meta @@ -1110,7 +1110,7 @@ standard_name = ozone_forcing long_name = ozone forcing data units = mixed - dimensions = (horizontal_dimension,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) + dimensions = (horizontal_dimension,vertical_dimension_of_ozone_forcing_data,number_of_coefficients_in_ozone_data) type = real kind = kind_phys intent = inout diff --git a/physics/GFS_suite_stateout_update.meta b/physics/GFS_suite_stateout_update.meta index 8cbab9139..fae276d2f 100644 --- a/physics/GFS_suite_stateout_update.meta +++ b/physics/GFS_suite_stateout_update.meta @@ -218,7 +218,7 @@ standard_name = ozone_forcing long_name = ozone forcing data units = mixed - dimensions = (horizontal_loop_extent,number_of_levels_in_ozone_data,number_of_coefficients_in_ozone_data) + dimensions = (horizontal_loop_extent,vertical_dimension_of_ozone_forcing_data,number_of_coefficients_in_ozone_data) type = real kind = kind_phys intent = in From 63ee841b85a0a71eabb9ccb18fb8963032981fe3 Mon Sep 17 00:00:00 2001 From: Grant Firl Date: Sun, 3 Dec 2023 22:18:07 -0500 Subject: [PATCH 25/25] fix bug in GFS_phys_time_vary.scm.F90/meta --- physics/GFS_phys_time_vary.scm.F90 | 4 ++-- physics/GFS_phys_time_vary.scm.meta | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/physics/GFS_phys_time_vary.scm.F90 b/physics/GFS_phys_time_vary.scm.F90 index ff5a50d41..b338f4ad4 100644 --- a/physics/GFS_phys_time_vary.scm.F90 +++ b/physics/GFS_phys_time_vary.scm.F90 @@ -61,7 +61,7 @@ module GFS_phys_time_vary !! @{ subroutine GFS_phys_time_vary_init ( & me, master, ntoz, h2o_phys, iaerclm, iccn, iflip, im, nx, ny, idate, xlat_d, xlon_d, & - jindx1_o3, jindx2_o3, ddy_o3, ozphys, jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & + jindx1_o3, jindx2_o3, ddy_o3, jindx1_h, jindx2_h, ddy_h, h2opl,fhour, & jindx1_aer, jindx2_aer, ddy_aer, iindx1_aer, iindx2_aer, ddx_aer, aer_nm, & jindx1_ci, jindx2_ci, ddy_ci, iindx1_ci, iindx2_ci, ddx_ci, imap, jmap, & do_ugwp_v1, jindx1_tau, jindx2_tau, ddy_j1tau, ddy_j2tau, & @@ -73,7 +73,7 @@ subroutine GFS_phys_time_vary_init ( zwtxy, xlaixy, xsaixy, lfmassxy, stmassxy, rtmassxy, woodxy, stblcpxy, fastcpxy, & smcwtdxy, deeprechxy, rechxy, snowxy, snicexy, snliqxy, tsnoxy , smoiseq, zsnsoxy, & slc, smc, stc, tsfcl, snowd, canopy, tg3, stype, con_t0c, lsm_cold_start, nthrds, & - errmsg, errflg) + ozphys, errmsg, errflg) implicit none diff --git a/physics/GFS_phys_time_vary.scm.meta b/physics/GFS_phys_time_vary.scm.meta index d72e27fd5..6f828648f 100644 --- a/physics/GFS_phys_time_vary.scm.meta +++ b/physics/GFS_phys_time_vary.scm.meta @@ -880,6 +880,13 @@ dimensions = () type = integer intent = in +[ozphys] + standard_name = dataset_for_ozone_physics + long_name = dataset for NRL ozone physics + units = mixed + dimensions = () + type = ty_ozphys + intent = in [errmsg] standard_name = ccpp_error_message long_name = error message for error handling in CCPP