From 51d7265586f18ab6f5a64cb1abf4325dc4a6ed84 Mon Sep 17 00:00:00 2001 From: "Samuel Trahan (NOAA contractor)" <39415369+SamuelTrahanNOAA@users.noreply.github.com> Date: Mon, 12 Apr 2021 17:50:01 -0400 Subject: [PATCH] More 3D diagnostic tendencies (#76) Add diagnostic tendencies for all tracers. Move all d*3dt variables into a 4D sparse array stored as `dtend(i,k,dtidx(tracer,process))` to reduce memory usage. --- atmos_model.F90 | 48 ++- ccpp/data/GFS_typedefs.F90 | 547 +++++++++++++++++++++++-- ccpp/data/GFS_typedefs.meta | 483 ++++++++-------------- ccpp/driver/GFS_diagnostics.F90 | 566 ++++---------------------- ccpp/physics | 2 +- ccpp/suites/suite_FV3_RRFS_v1beta.xml | 1 + io/FV3GFS_io.F90 | 32 -- 7 files changed, 790 insertions(+), 889 deletions(-) diff --git a/atmos_model.F90 b/atmos_model.F90 index 506fcee00..18f99484f 100644 --- a/atmos_model.F90 +++ b/atmos_model.F90 @@ -229,6 +229,7 @@ subroutine update_atmos_radiation_physics (Atmos) implicit none type (atmos_data_type), intent(in) :: Atmos !--- local variables--- + integer :: idtend, itrac integer :: nb, jdat(8), rc, ierr if (mpp_pe() == mpp_root_pe() .and. debug) write(6,*) "statein driver" @@ -283,21 +284,40 @@ subroutine update_atmos_radiation_physics (Atmos) ! Calculate total non-physics tendencies by substracting old IPD Stateout ! variables from new/updated IPD Statein variables (gives the tendencies ! due to anything else than physics) - if (GFS_control%ldiag3d) then - do nb = 1,Atm_block%nblks - GFS_data(nb)%Intdiag%du3dt(:,:,8) = GFS_data(nb)%Intdiag%du3dt(:,:,8) & - + (GFS_data(nb)%Statein%ugrs - GFS_data(nb)%Stateout%gu0) - GFS_data(nb)%Intdiag%dv3dt(:,:,8) = GFS_data(nb)%Intdiag%dv3dt(:,:,8) & - + (GFS_data(nb)%Statein%vgrs - GFS_data(nb)%Stateout%gv0) - GFS_data(nb)%Intdiag%dt3dt(:,:,11) = GFS_data(nb)%Intdiag%dt3dt(:,:,11) & - + (GFS_data(nb)%Statein%tgrs - GFS_data(nb)%Stateout%gt0) - enddo - if (GFS_control%qdiag3d) then + if (GFS_Control%ldiag3d) then + idtend = GFS_Control%dtidx(GFS_Control%index_of_x_wind,GFS_Control%index_of_process_non_physics) + if(idtend>=1) then + do nb = 1,Atm_block%nblks + GFS_data(nb)%Intdiag%dtend(:,:,idtend) = GFS_data(nb)%Intdiag%dtend(:,:,idtend) & + + (GFS_data(nb)%Statein%ugrs - GFS_data(nb)%Stateout%gu0) + enddo + endif + + idtend = GFS_Control%dtidx(GFS_Control%index_of_y_wind,GFS_Control%index_of_process_non_physics) + if(idtend>=1) then + do nb = 1,Atm_block%nblks + GFS_data(nb)%Intdiag%dtend(:,:,idtend) = GFS_data(nb)%Intdiag%dtend(:,:,idtend) & + + (GFS_data(nb)%Statein%vgrs - GFS_data(nb)%Stateout%gv0) + enddo + endif + + idtend = GFS_Control%dtidx(GFS_Control%index_of_temperature,GFS_Control%index_of_process_non_physics) + if(idtend>=1) then do nb = 1,Atm_block%nblks - GFS_data(nb)%Intdiag%dq3dt(:,:,12) = GFS_data(nb)%Intdiag%dq3dt(:,:,12) & - + (GFS_data(nb)%Statein%qgrs(:,:,GFS_control%ntqv) - GFS_data(nb)%Stateout%gq0(:,:,GFS_control%ntqv)) - GFS_data(nb)%Intdiag%dq3dt(:,:,13) = GFS_data(nb)%Intdiag%dq3dt(:,:,13) & - + (GFS_data(nb)%Statein%qgrs(:,:,GFS_control%ntoz) - GFS_data(nb)%Stateout%gq0(:,:,GFS_control%ntoz)) + GFS_data(nb)%Intdiag%dtend(:,:,idtend) = GFS_data(nb)%Intdiag%dtend(:,:,idtend) & + + (GFS_data(nb)%Statein%tgrs - GFS_data(nb)%Stateout%gt0) + enddo + endif + + if (GFS_Control%qdiag3d) then + do itrac=1,GFS_Control%ntrac + idtend = GFS_Control%dtidx(itrac+100,GFS_Control%index_of_process_non_physics) + if(idtend>=1) then + do nb = 1,Atm_block%nblks + GFS_data(nb)%Intdiag%dtend(:,:,idtend) = GFS_data(nb)%Intdiag%dtend(:,:,idtend) & + + (GFS_data(nb)%Statein%qgrs(:,:,itrac) - GFS_data(nb)%Stateout%gq0(:,:,itrac)) + enddo + endif enddo endif endif diff --git a/ccpp/data/GFS_typedefs.F90 b/ccpp/data/GFS_typedefs.F90 index 96a7aaa36..29c8cf5a5 100644 --- a/ccpp/data/GFS_typedefs.F90 +++ b/ccpp/data/GFS_typedefs.F90 @@ -521,11 +521,30 @@ module GFS_typedefs real (kind=kind_phys), pointer :: dkt (:,:) => null() !< instantaneous dkt diffusion coefficient for temperature (m**2/s) real (kind=kind_phys), pointer :: qci_conv(:,:) => null() !< convective cloud condesate after rainout - contains procedure :: create => coupling_create !< allocate array data end type GFS_coupling_type +!---------------------------------------------------------------- +! dtend_var_label +! Information about first dimension of dtidx +!---------------------------------------------------------------- + type dtend_var_label + character(len=20) :: name + character(len=44) :: desc + character(len=32) :: unit + end type dtend_var_label + +!---------------------------------------------------------------- +! dtend_process_label +! Information about second dimension of dtidx +!---------------------------------------------------------------- + type dtend_process_label + character(len=20) :: name + character(len=44) :: desc + logical :: time_avg + character(len=20) :: mod_name + end type dtend_process_label !---------------------------------------------------------------------------------- ! GFS_control_type @@ -1093,7 +1112,41 @@ module GFS_typedefs character(len=32), pointer :: tracer_names(:) !< array of initialized tracers from dynamic core integer :: ntrac !< number of tracers integer :: ntracp1 !< number of tracers plus one + integer :: ntracp100 !< number of tracers plus one hundred integer :: nqrimef !< tracer index for mass weighted rime factor + + integer, pointer :: dtidx(:,:) => null() !< index in outermost dimension of dtend + integer :: ndtend !< size of outermost dimension of dtend + type(dtend_var_label), pointer :: dtend_var_labels(:) => null() !< information about first dim of dtidx + type(dtend_process_label), pointer :: dtend_process_labels(:) => null() !< information about second dim of dtidx + + ! Indices within inner dimension of dtidx for things that are not tracers: + integer :: index_of_temperature !< temperature in dtidx + integer :: index_of_x_wind !< x wind in dtidx + integer :: index_of_y_wind !< y wind in dtidx + + ! Indices within outer dimension of dtidx: + integer :: nprocess !< maximum value of the below index_for_process_ variables + integer :: nprocess_summed !< number of causes in dtend(:,:,dtidx(...)) to sum to make the physics tendency + integer :: index_of_process_pbl !< tracer changes caused by PBL scheme + integer :: index_of_process_dcnv !< tracer changes caused by deep convection scheme + integer :: index_of_process_scnv !< tracer changes caused by shallow convection scheme + integer :: index_of_process_mp !< tracer changes caused by microphysics scheme + integer :: index_of_process_prod_loss !< tracer changes caused by ozone production and loss + integer :: index_of_process_ozmix !< tracer changes caused by ozone mixing ratio + integer :: index_of_process_temp !< tracer changes caused by temperature + integer :: index_of_process_longwave !< tracer changes caused by long wave radiation + integer :: index_of_process_shortwave !< tracer changes caused by short wave radiation + integer :: index_of_process_orographic_gwd !< tracer changes caused by orographic gravity wave drag + integer :: index_of_process_rayleigh_damping !< tracer changes caused by Rayleigh damping + integer :: index_of_process_nonorographic_gwd !< tracer changes caused by convective gravity wave drag + integer :: index_of_process_overhead_ozone !< tracer changes caused by overhead ozone column + integer :: index_of_process_conv_trans !< tracer changes caused by convective transport + integer :: index_of_process_physics !< tracer changes caused by physics schemes + integer :: index_of_process_non_physics !< tracer changes caused by everything except physics schemes + integer :: index_of_process_photochem !< all changes to ozone + logical, pointer :: is_photochem(:) => null()!< flags for which processes should be summed as photochemical + integer :: ntqv !< tracer index for water vapor (specific humidity) integer :: ntoz !< tracer index for ozone mixing ratio integer :: ntcw !< tracer index for cloud condensate (or liquid water) @@ -1410,6 +1463,7 @@ module GFS_typedefs procedure :: create => radtend_create !< allocate array data end type GFS_radtend_type + !---------------------------------------------------------------- ! GFS_diag_type ! internal diagnostic type used as arguments to gbphys and grrad @@ -1544,10 +1598,12 @@ module GFS_typedefs real (kind=kind_phys), pointer :: shum_wts(:,:) => null() !< real (kind=kind_phys), pointer :: sfc_wts(:,:) => null() !< real (kind=kind_phys), pointer :: zmtnblck(:) => null() ! null() !< u momentum change due to physics - real (kind=kind_phys), pointer :: dv3dt (:,:,:) => null() !< v momentum change due to physics - real (kind=kind_phys), pointer :: dt3dt (:,:,:) => null() !< temperature change due to physics - real (kind=kind_phys), pointer :: dq3dt (:,:,:) => null() !< moisture change due to physics + + ! dtend/dtidxt: Multitudenous 3d tendencies in a 4D array: (i,k,0:ntrac,nprocess) + ! Sparse in outermost two dimensions. dtidx(1:100+ntrac,nprocess) maps to dtend + ! outer dimension index. + real (kind=kind_phys), pointer :: dtend (:,:,:) => null() !< tracer changes due to physics + real (kind=kind_phys), pointer :: refdmax (:) => null() !< max hourly 1-km agl reflectivity real (kind=kind_phys), pointer :: refdmax263k(:) => null() !< max hourly -10C reflectivity real (kind=kind_phys), pointer :: t02max (:) => null() !< max hourly 2m T @@ -2126,6 +2182,8 @@ module GFS_typedefs real (kind=kind_phys), pointer :: f_rimef (:,:) => null() !< real (kind=kind_phys), pointer :: cwm (:,:) => null() !< + !-- 3D diagnostics + integer :: rtg_ozone_index contains procedure :: create => interstitial_create !< allocate array data @@ -2959,6 +3017,8 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & logical :: ldiag3d = .false. !< flag for 3d diagnostic fields logical :: qdiag3d = .false. !< flag for 3d tracer diagnostic fields logical :: lssav = .false. !< logical flag for storing diagnostics + integer, parameter :: pat_len = 60, pat_count=100 !< dimensions of dtend_select + character(len=pat_len) :: dtend_select(pat_count) !< fglob_list() patterns to decide which 3d diagnostic fields to enable integer :: naux2d = 0 !< number of auxiliary 2d arrays to output (for debugging) integer :: naux3d = 0 !< number of auxiliary 3d arrays to output (for debugging) logical :: aux2d_time_avg(1:naux2dmax) = .false. !< flags for time averaging of auxiliary 2d arrays @@ -3411,8 +3471,8 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & NAMELIST /gfs_physics_nml/ & !--- general parameters - fhzero, ldiag3d, qdiag3d, lssav, naux2d, naux3d, & - aux2d_time_avg, aux3d_time_avg, fhcyc, & + fhzero, ldiag3d, qdiag3d, lssav, naux2d, dtend_select, & + naux3d, aux2d_time_avg, aux3d_time_avg, fhcyc, & thermodyn_id, sfcpress_id, & !--- coupling parameters cplflx, cplwav, cplwav2atm, cplchm, lsidea, & @@ -3527,6 +3587,16 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !--- convective clouds integer :: ncnvcld3d = 0 !< number of convective 3d clouds fields + integer :: itrac, ipat, ichem + logical :: have_pbl, have_dcnv, have_scnv, have_mp, have_oz_phys, have_samf, have_pbl_edmf + character(len=20) :: namestr + character(len=44) :: descstr + + ! dtend selection: default is to match all variables: + dtend_select(1)='*' + do ipat=2,pat_count + dtend_select(ipat)=' ' + enddo !--- read in the namelist #ifdef INTERNAL_FILE_NML @@ -3567,7 +3637,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%fhzero = fhzero Model%ldiag3d = ldiag3d Model%qdiag3d = qdiag3d - if (Model%qdiag3d .and. .not. Model%ldiag3d) then + if (qdiag3d .and. .not. ldiag3d) then write(0,*) 'Logic error in GFS_typedefs.F90: qdiag3d requires ldiag3d' stop endif @@ -3608,9 +3678,6 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & if(me==master) & write(0,*) 'FLAG: imfshalcnv_gf so scnv not generic' Model%flag_for_scnv_generic_tend=.false. - ! else if(imfshalcnv == Model%imfshalcnv_samf) then - ! write(0,*) 'FLAG: imfshalcnv_samf so scnv not generic' - ! Model%flag_for_scnv_generic_tend=.false. elseif(me==master) then write(0,*) 'NO FLAG: scnv is generic' endif @@ -3619,9 +3686,6 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & if(me==master) & write(0,*) 'FLAG: imfdeepcnv_gf so dcnv not generic' Model%flag_for_dcnv_generic_tend=.false. - ! else if(imfdeepcnv == Model%imfdeepcnv_samf) then - ! write(0,*) 'FLAG: imfdeepcnv_samf so dcnv not generic' - ! Model%flag_for_dcnv_generic_tend=.false. elseif(me==master) then write(0,*) 'NO FLAG: dcnv is generic' endif @@ -4209,6 +4273,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !--- tracer handling Model%ntrac = size(tracer_names) Model%ntracp1 = Model%ntrac + 1 + Model%ntracp100 = Model%ntrac + 100 allocate (Model%tracer_names(Model%ntrac)) Model%tracer_names(:) = tracer_names(:) Model%ntqv = 1 @@ -4288,6 +4353,228 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & enddo endif + ! Tracer diagnostics indices and dimension size, which must be in + ! Model to be forwarded to the right places. + + ! Individual processes: + Model%index_of_process_pbl = 1 + Model%index_of_process_dcnv = 2 + Model%index_of_process_scnv = 3 + Model%index_of_process_mp = 4 + Model%index_of_process_prod_loss = 5 + Model%index_of_process_ozmix = 6 + Model%index_of_process_temp = 7 + Model%index_of_process_overhead_ozone = 8 + Model%index_of_process_longwave = 9 + Model%index_of_process_shortwave = 10 + Model%index_of_process_orographic_gwd = 11 + Model%index_of_process_rayleigh_damping = 12 + Model%index_of_process_nonorographic_gwd = 13 + Model%index_of_process_conv_trans = 14 + + ! Number of processes to sum (last index of prior set) + Model%nprocess_summed = 14 + + ! Sums of other processes, which must be after nprocess_summed: + Model%index_of_process_physics = 15 + Model%index_of_process_non_physics = 16 + Model%index_of_process_photochem = 17 + + ! Total number of processes (last index of prior set) + Model%nprocess = 17 + + ! List which processes should be summed as photochemical: + allocate(Model%is_photochem(Model%nprocess)) + Model%is_photochem = .false. + Model%is_photochem(Model%index_of_process_prod_loss) = .true. + Model%is_photochem(Model%index_of_process_ozmix) = .true. + Model%is_photochem(Model%index_of_process_temp) = .true. + Model%is_photochem(Model%index_of_process_overhead_ozone) = .true. + + ! Non-tracers that appear in first dimension of dtidx: + Model%index_of_temperature = 10 + Model%index_of_x_wind = 11 + Model%index_of_y_wind = 12 + + ! Last index of outermost dimension of dtend + Model%ndtend = 0 + allocate(Model%dtidx(Model%ntracp100,Model%nprocess)) + Model%dtidx = -99 + + if(ldiag3d) then + ! Flags used to turn on or off tracer "causes" + have_pbl_edmf = Model%hybedmf .or. Model%satmedmf .or. do_mynnedmf + have_samf = Model%satmedmf .or. Model%trans_trac .or. Model%ras .or. Model%do_shoc + have_pbl = .true. + have_dcnv = Model%imfdeepcnv>=0 !Model%ras .or. Model%cscnv .or. Model%do_deep .or. Model%hwrf_samfdeep + have_scnv = Model%imfshalcnv>=0 !Model%shal_cnv + have_mp = Model%imp_physics>0 + have_oz_phys = Model%oz_phys .or. Model%oz_phys_2015 + + ! Increment idtend and fill dtidx: + allocate(Model%dtend_var_labels(Model%ntracp100)) + allocate(Model%dtend_process_labels(Model%nprocess)) + + call allocate_dtend_labels_and_causes(Model) + + ! Default names of tracers just in case later code does not initialize them: + do itrac=1,Model%ntrac + write(namestr,'("tracer",I0)') itrac + write(descstr,'("tracer ",I0," of ",I0)') itrac, Model%ntrac + call label_dtend_tracer(Model,100+itrac,trim(namestr),trim(descstr)) + enddo + + if(Model%ntchs>0) then + if(Model%ntchm>0) then + ! Chemical tracers are first so more specific tracer names + ! replace them. There is no straightforward way of getting + ! chemical tracer short names or descriptions, so we use + ! indices instead. + do ichem=Model%ntchs,Model%ntchs+Model%ntchm-1 + write(namestr,'("chem",I0)') ichem + write(descstr,'("chemical tracer ",I0," of ",I0)') ichem, Model%ntchm + call label_dtend_tracer(Model,100+ichem,trim(namestr),trim(descstr)) + enddo + endif + + ! More specific chemical tracer names: + call label_dtend_tracer(Model,100+Model%ntchs,'so2','sulfur dioxide concentration') + if(Model%ntchm>0) then + ! Need better descriptions of these. + call label_dtend_tracer(Model,100+Model%ntchm+Model%ntchs-1,'pp10','pp10 concentration') + + itrac=get_tracer_index(Model%tracer_names, 'DMS', Model%me, Model%master, Model%debug) + if(itrac>0) then + call label_dtend_tracer(Model,100+itrac,'DMS','DMS concentration') + endif + itrac=get_tracer_index(Model%tracer_names, 'msa', Model%me, Model%master, Model%debug) + if(itrac>0) then + call label_dtend_tracer(Model,100+itrac,'msa','msa concentration') + endif + endif + endif + + call label_dtend_tracer(Model,Model%index_of_temperature,'temp','temperature','K s-1') + call label_dtend_tracer(Model,Model%index_of_x_wind,'u','x wind','m s-2') + call label_dtend_tracer(Model,Model%index_of_y_wind,'v','y wind','m s-2') + + ! Other tracer names. These were taken from GFS_typedefs.F90 with descriptions from GFS_typedefs.meta + call label_dtend_tracer(Model,100+Model%ntqv,'qv','water vapor specific humidity') + call label_dtend_tracer(Model,100+Model%ntoz,'o3','ozone concentration') + call label_dtend_tracer(Model,100+Model%ntcw,'liq_wat','cloud condensate (or liquid water)') + call label_dtend_tracer(Model,100+Model%ntiw,'ice_wat','ice water') + call label_dtend_tracer(Model,100+Model%ntrw,'rainwat','rain water') + call label_dtend_tracer(Model,100+Model%ntsw,'snowwat','snow water') + call label_dtend_tracer(Model,100+Model%ntgl,'graupel','graupel') + call label_dtend_tracer(Model,100+Model%ntclamt,'cld_amt','cloud amount integer') + call label_dtend_tracer(Model,100+Model%ntlnc,'water_nc','liquid number concentration') + call label_dtend_tracer(Model,100+Model%ntinc,'ice_nc','ice number concentration') + call label_dtend_tracer(Model,100+Model%ntrnc,'rain_nc','rain number concentration') + call label_dtend_tracer(Model,100+Model%ntsnc,'snow_nc','snow number concentration') + call label_dtend_tracer(Model,100+Model%ntgnc,'graupel_nc','graupel number concentration') + call label_dtend_tracer(Model,100+Model%ntke,'sgs_tke','turbulent kinetic energy') + call label_dtend_tracer(Model,100+Model%nqrimef,'q_rimef','mass weighted rime factor') + call label_dtend_tracer(Model,100+Model%ntwa,'liq_aero','number concentration of water-friendly aerosols') + call label_dtend_tracer(Model,100+Model%ntia,'ice_aero','number concentration of ice-friendly aerosols') + call label_dtend_tracer(Model,100+Model%nto,'o_ion','oxygen ion concentration') + call label_dtend_tracer(Model,100+Model%nto2,'o2','oxygen concentration') + + call label_dtend_cause(Model,Model%index_of_process_pbl,'pbl','tendency due to PBL') + call label_dtend_cause(Model,Model%index_of_process_dcnv,'deepcnv','tendency due to deep convection') + call label_dtend_cause(Model,Model%index_of_process_scnv,'shalcnv','tendency due to shallow convection') + call label_dtend_cause(Model,Model%index_of_process_mp,'mp','tendency due to microphysics') + call label_dtend_cause(Model,Model%index_of_process_prod_loss,'prodloss','tendency due to production and loss rate') + call label_dtend_cause(Model,Model%index_of_process_ozmix,'o3mix','tendency due to ozone mixing ratio') + call label_dtend_cause(Model,Model%index_of_process_temp,'temp','tendency due to temperature') + call label_dtend_cause(Model,Model%index_of_process_overhead_ozone,'o3column','tendency due to overhead ozone column') + call label_dtend_cause(Model,Model%index_of_process_photochem,'photochem','tendency due to photochemical processes') + call label_dtend_cause(Model,Model%index_of_process_physics,'phys','tendency due to physics') + call label_dtend_cause(Model,Model%index_of_process_non_physics,'nophys','tendency due to non-physics processes', & + mod_name='gfs_dyn') + call label_dtend_cause(Model,Model%index_of_process_conv_trans,'cnvtrans','tendency due to convective transport') + call label_dtend_cause(Model,Model%index_of_process_longwave,'lw','tendency due to long wave radiation') + call label_dtend_cause(Model,Model%index_of_process_shortwave,'sw','tendency due to short wave radiation') + call label_dtend_cause(Model,Model%index_of_process_orographic_gwd,'orogwd','tendency due to orographic gravity wave drag') + call label_dtend_cause(Model,Model%index_of_process_rayleigh_damping,'rdamp','tendency due to Rayleigh damping') + call label_dtend_cause(Model,Model%index_of_process_nonorographic_gwd,'cnvgwd','tendency due to convective gravity wave drag') + + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_longwave) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_shortwave) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_pbl,have_pbl) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_dcnv,have_dcnv) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_scnv,have_scnv) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_mp,have_mp) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_orographic_gwd) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_rayleigh_damping) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_nonorographic_gwd) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_physics) + call fill_dtidx(Model,dtend_select,Model%index_of_temperature,Model%index_of_process_non_physics) + + call fill_dtidx(Model,dtend_select,Model%index_of_x_wind,Model%index_of_process_pbl,have_pbl) + call fill_dtidx(Model,dtend_select,Model%index_of_y_wind,Model%index_of_process_pbl,have_pbl) + call fill_dtidx(Model,dtend_select,Model%index_of_x_wind,Model%index_of_process_orographic_gwd) + call fill_dtidx(Model,dtend_select,Model%index_of_y_wind,Model%index_of_process_orographic_gwd) + call fill_dtidx(Model,dtend_select,Model%index_of_x_wind,Model%index_of_process_dcnv,have_dcnv) + call fill_dtidx(Model,dtend_select,Model%index_of_y_wind,Model%index_of_process_dcnv,have_dcnv) + call fill_dtidx(Model,dtend_select,Model%index_of_x_wind,Model%index_of_process_nonorographic_gwd) + call fill_dtidx(Model,dtend_select,Model%index_of_y_wind,Model%index_of_process_nonorographic_gwd) + call fill_dtidx(Model,dtend_select,Model%index_of_x_wind,Model%index_of_process_rayleigh_damping) + call fill_dtidx(Model,dtend_select,Model%index_of_y_wind,Model%index_of_process_rayleigh_damping) + call fill_dtidx(Model,dtend_select,Model%index_of_x_wind,Model%index_of_process_scnv,have_scnv) + call fill_dtidx(Model,dtend_select,Model%index_of_y_wind,Model%index_of_process_scnv,have_scnv) + call fill_dtidx(Model,dtend_select,Model%index_of_x_wind,Model%index_of_process_physics) + call fill_dtidx(Model,dtend_select,Model%index_of_y_wind,Model%index_of_process_physics) + call fill_dtidx(Model,dtend_select,Model%index_of_x_wind,Model%index_of_process_non_physics) + call fill_dtidx(Model,dtend_select,Model%index_of_y_wind,Model%index_of_process_non_physics) + + if(qdiag3d) then + if(have_samf) then + do itrac=1,Model%ntrac + if(itrac==Model%ntchs) exit ! remaining tracers are chemical + if(itrac==Model%ntke) cycle ! TKE is handled by convective transport (see below) + call fill_dtidx(Model,dtend_select,100+itrac,Model%index_of_process_dcnv,have_dcnv) + call fill_dtidx(Model,dtend_select,100+itrac,Model%index_of_process_scnv,have_scnv) + enddo + else + call fill_dtidx(Model,dtend_select,100+Model%ntqv,Model%index_of_process_dcnv,have_dcnv) + call fill_dtidx(Model,dtend_select,100+Model%ntqv,Model%index_of_process_scnv,have_scnv) + call fill_dtidx(Model,dtend_select,100+Model%ntcw,Model%index_of_process_dcnv,have_dcnv) + call fill_dtidx(Model,dtend_select,100+Model%ntcw,Model%index_of_process_scnv,have_scnv) + call fill_dtidx(Model,dtend_select,100+Model%ntiw,Model%index_of_process_dcnv,have_dcnv) + call fill_dtidx(Model,dtend_select,100+Model%ntiw,Model%index_of_process_scnv,have_scnv) + endif + call fill_dtidx(Model,dtend_select,100+Model%ntke,Model%index_of_process_conv_trans,have_scnv.or.have_dcnv) + call fill_dtidx(Model,dtend_select,100+Model%ntclamt,Model%index_of_process_conv_trans,have_scnv.or.have_dcnv) + + call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_pbl,have_pbl .and. have_oz_phys) + call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_prod_loss,have_oz_phys) + call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_ozmix,have_oz_phys) + call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_temp,have_oz_phys) + call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_overhead_ozone,have_oz_phys) + call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_photochem,have_oz_phys) + call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_physics,.true.) + call fill_dtidx(Model,dtend_select,100+Model%ntoz,Model%index_of_process_non_physics,.true.) + + if(.not.Model%do_mynnedmf .and. .not. Model%satmedmf) then + call fill_dtidx(Model,dtend_select,100+Model%ntqv,Model%index_of_process_pbl,have_pbl) + call fill_dtidx(Model,dtend_select,100+Model%ntcw,Model%index_of_process_pbl,have_pbl) + call fill_dtidx(Model,dtend_select,100+Model%ntiw,Model%index_of_process_pbl,have_pbl) + call fill_dtidx(Model,dtend_select,100+Model%ntke,Model%index_of_process_pbl,have_pbl) + endif + + do itrac=1,Model%ntrac + if(itrac==Model%ntchs) exit ! remaining tracers are chemical + if(itrac==Model%ntoz) cycle ! already took care of ozone + call fill_dtidx(Model,dtend_select,100+itrac,Model%index_of_process_mp,have_mp) + if(have_pbl_edmf) then + call fill_dtidx(Model,dtend_select,100+itrac,Model%index_of_process_pbl,have_pbl) + endif + call fill_dtidx(Model,dtend_select,100+itrac,Model%index_of_process_physics,.true.) + call fill_dtidx(Model,dtend_select,100+itrac,Model%index_of_process_non_physics,.true.) + enddo + endif + end if + ! To ensure that these values match what's in the physics, ! array sizes are compared during model init in GFS_phys_time_vary_init() ! @@ -5602,17 +5889,231 @@ subroutine radtend_create (Radtend, IM, Model) end subroutine radtend_create + subroutine fill_dtidx(Model,dtend_select,itrac,icause,flag) + implicit none + class(GFS_control_type), intent(inout) :: Model + character(len=*), intent(in) :: dtend_select(:) + integer, intent(in) :: itrac + integer, intent(in) :: icause + logical, intent(in), optional :: flag + + character(len=100) :: name + logical :: flag2 + + flag2=.true. + if(present(flag)) flag2=flag + + if(icause>0 .and. flag2 .and. itrac>0) then + name = 'dtend_'//trim(Model%dtend_var_labels(itrac)%name)//'_'//trim(Model%dtend_process_labels(icause)%name) + if(fglob_list(dtend_select,trim(name))) then + Model%ndtend = Model%ndtend+1 + Model%dtidx(itrac,icause) = Model%ndtend + elseif(Model%me==Model%master) then + print '(A,A,A)','Skipping ',trim(name),' due to mismatch with dtend_select.' + endif + endif + end subroutine fill_dtidx + + recursive function fglob(pattern,string) result(match) + ! Matches UNIX-style globs. A '*' matches 0 or more characters, + ! and a '?' matches one character. Other characters must match + ! exactly. The entire string must match, so if you want to match + ! a substring in the middle, put '*' at the ends. + ! + ! Spaces ARE significant, so make sure you trim() the inputs. + ! + ! Examples: + ! + ! fglob('dtend*_mp','dtend_temp_mp') => .true. + ! fglob('dtend*_mp','dtend_cow_mp_dog') => .false. ! entire string must match + ! fglob('c?w','cow') => .true. + ! fglob('c?w','coow') => .false. ! "?" matches one char, not two + ! fglob('c?w ','cow ') => .false. ! You forgot to trim() the inputs. + implicit none + logical :: match + character(len=*), intent(in) :: pattern,string + integer :: npat, nstr, ipat, istr, min_match, num_match + logical :: match_infinity + + npat=len(pattern) + nstr=len(string) + ipat=1 ! Next pattern character to process + istr=1 ! First string character not yet matched + outer: do while(ipat<=npat) + if_glob: if(pattern(ipat:ipat)=='*' .or. pattern(ipat:ipat)=='?') then + ! Collect sequences of * and ? to avoid pathalogical cases. + min_match=0 ! Number of "?" which is minimum number of chars to match + match_infinity=.false. ! Do we see a "*"? + glob_collect: do while(ipat<=npat) + if(pattern(ipat:ipat)=='*') then + match_infinity=.true. + else if(pattern(ipat:ipat)=='?') then + min_match=min_match+1 + else + exit + endif + ipat=ipat+1 + end do glob_collect + + num_match=0 + glob_match: do while(istr<=len(string)) + if(num_match>=min_match) then + if(match_infinity) then + if(fglob(pattern(ipat:npat),string(istr:nstr))) then + ! Remaining pattern matches remaining string. + match=.true. + return + else + ! Remaining pattern does NOT match, so we have + ! to consume another char. + endif + else + ! This is a sequence of "?" and we matched them all. + cycle outer + endif + else + ! Haven't consumed enough chars for all the "?" yet. + endif + istr=istr+1 + num_match=num_match+1 + enddo glob_match + ! We get here if we hit the end of the string. + if(num_matchnstr) then + ! Not enough string left to match the pattern + match=.false. + return + elseif(string(istr:istr)/=pattern(ipat:ipat)) then + ! Exact character mismatch + match=.false. + return + endif if_glob + ! Exact character match + istr=istr+1 + ipat=ipat+1 + end do outer + ! We get here if we ran out of pattern. We must also hit the end of the string. + match = istr>nstr + end function fglob + + logical function fglob_list(patterns,string) + ! Wrapper around fglob that returns .true. if ANY pattern + ! matches. Unlike fglob(), patterns and strings ARE automatically + ! trim()ed. Patterns are processed in order until one matches, one + ! is empty, or one is '*'. + implicit none + character(len=*), intent(in) :: patterns(:) + character(len=*), intent(in) :: string + integer :: i,n,s + fglob_list=.false. + s=len_trim(string) + do i=1,len(patterns) + n=len_trim(patterns(i)) + if(n<1) then + return ! end of pattern list + elseif(n==1 .and. patterns(i)(1:1)=='*') then + fglob_list=.true. ! A single "*" matches anything + return + else if(fglob(patterns(i)(1:n),string(1:s))) then + fglob_list=.true. + return + else + endif + enddo + end function fglob_list + + subroutine allocate_dtend_labels_and_causes(Model) + implicit none + type(GFS_control_type), intent(inout) :: Model + integer :: i + + allocate(Model%dtend_var_labels(Model%ntracp100)) + allocate(Model%dtend_process_labels(Model%nprocess)) + + Model%dtend_var_labels(1)%name = 'unallocated' + Model%dtend_var_labels(1)%desc = 'unallocated tracer' + Model%dtend_var_labels(1)%unit = 'kg kg-1 s-1' + + do i=2,Model%ntracp100 + Model%dtend_var_labels(i)%name = 'unknown' + Model%dtend_var_labels(i)%desc = 'unspecified tracer' + Model%dtend_var_labels(i)%unit = 'kg kg-1 s-1' + enddo + do i=1,Model%nprocess + Model%dtend_process_labels(i)%name = 'unknown' + Model%dtend_process_labels(i)%desc = 'unspecified tendency' + Model%dtend_process_labels(i)%time_avg = .true. + Model%dtend_process_labels(i)%mod_name = 'gfs_phys' + enddo + end subroutine allocate_dtend_labels_and_causes + + subroutine label_dtend_tracer(Model,itrac,name,desc,unit) + implicit none + type(GFS_control_type), intent(inout) :: Model + integer, intent(in) :: itrac + character(len=*), intent(in) :: name, desc + character(len=*), optional, intent(in) :: unit + + if(itrac<2) then + ! Special index 1 is for unallocated tracers + return + endif + + Model%dtend_var_labels(itrac)%name = name + Model%dtend_var_labels(itrac)%desc = desc + if(present(unit)) then + Model%dtend_var_labels(itrac)%unit=unit + else + Model%dtend_var_labels(itrac)%unit='kg kg-1 s-1' + endif + end subroutine label_dtend_tracer + + subroutine label_dtend_cause(Model,icause,name,desc,mod_name,time_avg) + implicit none + type(GFS_control_type), intent(inout) :: Model + integer, intent(in) :: icause + character(len=*), intent(in) :: name, desc + character(len=*), optional, intent(in) :: mod_name + logical, optional, intent(in) :: time_avg + + Model%dtend_process_labels(icause)%name=name + Model%dtend_process_labels(icause)%desc=desc + if(present(mod_name)) then + Model%dtend_process_labels(icause)%mod_name = mod_name + else + Model%dtend_process_labels(icause)%mod_name = "gfs_phys" + endif + if(present(time_avg)) then + Model%dtend_process_labels(icause)%time_avg = time_avg + else + Model%dtend_process_labels(icause)%time_avg = .true. + endif + end subroutine label_dtend_cause !---------------- ! GFS_diag%create !---------------- subroutine diag_create (Diag, IM, Model) + use parse_tracers, only: get_tracer_index class(GFS_diag_type) :: Diag integer, intent(in) :: IM type(GFS_control_type), intent(in) :: Model ! logical, save :: linit + logical :: have_pbl, have_dcnv, have_scnv, have_mp, have_oz_phys if(Model%print_diff_pgr) then allocate(Diag%old_pgr(IM)) @@ -5729,22 +6230,13 @@ subroutine diag_create (Diag, IM, Model) !--- 3D diagnostics if (Model%ldiag3d) then - allocate (Diag%du3dt (IM,Model%levs,8)) - allocate (Diag%dv3dt (IM,Model%levs,8)) - allocate (Diag%dt3dt (IM,Model%levs,11)) + allocate(Diag%dtend(IM,Model%levs,Model%ndtend)) + Diag%dtend = clear_val if (Model%qdiag3d) then - allocate (Diag%dq3dt (IM,Model%levs,13)) allocate (Diag%upd_mf (IM,Model%levs)) allocate (Diag%dwn_mf (IM,Model%levs)) allocate (Diag%det_mf (IM,Model%levs)) - else - allocate (Diag%dq3dt (1,1,13)) endif - else - allocate (Diag%du3dt (1,1,8)) - allocate (Diag%dv3dt (1,1,8)) - allocate (Diag%dt3dt (1,1,11)) - allocate (Diag%dq3dt (1,1,13)) endif ! UGWP @@ -6030,11 +6522,8 @@ subroutine diag_phys_zero (Diag, Model, linit, iauwindow_center) ! if(Model%me == Model%master) print *,'in diag_phys_zero, totprcpb set to 0,kdt=',Model%kdt if (Model%ldiag3d) then - Diag%du3dt = zero - Diag%dv3dt = zero - Diag%dt3dt = zero + Diag%dtend = zero if (Model%qdiag3d) then - Diag%dq3dt = zero Diag%upd_mf = zero Diag%dwn_mf = zero Diag%det_mf = zero diff --git a/ccpp/data/GFS_typedefs.meta b/ccpp/data/GFS_typedefs.meta index 4247f9395..7d0fb0182 100644 --- a/ccpp/data/GFS_typedefs.meta +++ b/ccpp/data/GFS_typedefs.meta @@ -4354,6 +4354,162 @@ units = count dimensions = () type = integer +[ntracp100] + standard_name = number_of_tracers_plus_one_hundred + long_name = number of tracers plus one hundred + units = count + dimensions = () + type = integer +[nprocess] + standard_name = number_of_cumulative_change_processes + long_name = number of processes that cause changes in state variables + units = count + dimensions = () + type = integer +[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 +[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 +[ndtend] + standard_name = cumulative_change_of_state_variables_outer_index_max + long_name = last dimension of array of diagnostic tendencies for state variables + units = count + dimensions = () + type = integer +[index_of_process_pbl] + standard_name = index_of_subgrid_scale_vertical_mixing_process_in_cumulative_change_index + long_name = index of subgrid scale vertical mixing process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_process_dcnv] + standard_name = index_of_deep_convection_process_process_in_cumulative_change_index + long_name = index of deep convection process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_process_scnv] + standard_name = index_of_shallow_convection_process_process_in_cumulative_change_index + long_name = index of shallow convection process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_process_mp] + standard_name = index_of_microphysics_process_process_in_cumulative_change_index + long_name = index of microphysics transport process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[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 +[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 +[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 +[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 +[index_of_process_longwave] + standard_name = index_of_longwave_heating_process_in_cumulative_change_index + long_name = index of longwave heating process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_process_shortwave] + standard_name = index_of_shortwave_heating_process_in_cumulative_change_index + long_name = index of shortwave heating process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_process_orographic_gwd] + standard_name = index_of_orographic_gravity_wave_drag_process_in_cumulative_change_index + long_name = index of orographic gravity wave drag process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_process_rayleigh_damping] + standard_name = index_of_rayleigh_damping_process_in_cumulative_change_index + long_name = index of rayleigh damping process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_process_nonorographic_gwd] + standard_name = index_of_nonorographic_gravity_wave_drag_process_in_cumulative_change_index + long_name = index of nonorographic gravity wave drag process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_process_conv_trans] + standard_name = index_of_convective_transport_process_in_cumulative_change_index + long_name = index of convective transport process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[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 +[index_of_process_non_physics] + standard_name = index_of_non_physics_process_in_cumulative_change_index + long_name = index of non-physics transport process in second dimension of array cumulative change index + units = index + dimensions = () + type = integer +[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 +[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 +[index_of_temperature] + standard_name = index_of_temperature_in_cumulative_change_index + long_name = index of temperature in first dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_x_wind] + standard_name = index_of_x_wind_in_cumulative_change_index + long_name = index of x-wind in first dimension of array cumulative change index + units = index + dimensions = () + type = integer +[index_of_y_wind] + standard_name = index_of_y_wind_in_cumulative_change_index + long_name = index of x-wind in first dimension of array cumulative change index + units = index + dimensions = () + type = integer [ntqv] standard_name = index_for_water_vapor long_name = tracer index for water vapor (specific humidity) @@ -6555,325 +6711,14 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys -[du3dt(:,:,1)] - standard_name = cumulative_change_in_x_wind_due_to_PBL - long_name = cumulative change in x wind due to PBL - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[du3dt(:,:,2)] - standard_name = cumulative_change_in_x_wind_due_to_orographic_gravity_wave_drag - long_name = cumulative change in x wind due to orographic gravity wave drag - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[du3dt(:,:,3)] - standard_name = cumulative_change_in_x_wind_due_to_deep_convection - long_name = cumulative change in x wind due to deep convection - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[du3dt(:,:,4)] - standard_name = cumulative_change_in_x_wind_due_to_convective_gravity_wave_drag - long_name = cumulative change in x wind due to convective gravity wave drag - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[du3dt(:,:,5)] - standard_name = cumulative_change_in_x_wind_due_to_rayleigh_damping - long_name = cumulative change in x wind due to Rayleigh damping - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[du3dt(:,:,6)] - standard_name = cumulative_change_in_x_wind_due_to_shallow_convection - long_name = cumulative change in x wind due to shallow convection - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[du3dt(:,:,7)] - standard_name = cumulative_change_in_x_wind_due_to_physics - long_name = cumulative change in x wind due to physics - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[du3dt(:,:,8)] - standard_name = cumulative_change_in_x_wind_due_to_non_physics_processes - long_name = cumulative change in x wind due to non-physics processes - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dv3dt(:,:,1)] - standard_name = cumulative_change_in_y_wind_due_to_PBL - long_name = cumulative change in y wind due to PBL - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dv3dt(:,:,2)] - standard_name = cumulative_change_in_y_wind_due_to_orographic_gravity_wave_drag - long_name = cumulative change in y wind due to orographic gravity wave drag - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dv3dt(:,:,3)] - standard_name = cumulative_change_in_y_wind_due_to_deep_convection - long_name = cumulative change in y wind due to deep convection - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dv3dt(:,:,4)] - standard_name = cumulative_change_in_y_wind_due_to_convective_gravity_wave_drag - long_name = cumulative change in y wind due to convective gravity wave drag - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys -[dv3dt(:,:,5)] - standard_name = cumulative_change_in_y_wind_due_to_rayleigh_damping - long_name = cumulative change in y wind due to Rayleigh damping - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dv3dt(:,:,6)] - standard_name = cumulative_change_in_y_wind_due_to_shallow_convection - long_name = cumulative change in y wind due to shallow convection - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dv3dt(:,:,7)] - standard_name = cumulative_change_in_y_wind_due_to_physics - long_name = cumulative change in y wind due to physics - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dv3dt(:,:,8)] - standard_name = cumulative_change_in_y_wind_due_to_non_physics_processes - long_name = cumulative change in y wind due to non-physics processes - units = m s-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,1)] - standard_name = cumulative_change_in_temperature_due_to_longwave_radiation - long_name = cumulative change in temperature due to longwave radiation - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,2)] - standard_name = cumulative_change_in_temperature_due_to_shortwave_radiation - long_name = cumulative change in temperature due to shortwave radiation - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,3)] - standard_name = cumulative_change_in_temperature_due_to_PBL - long_name = cumulative change in temperature due to PBL - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,4)] - standard_name = cumulative_change_in_temperature_due_to_deep_convection - long_name = cumulative change in temperature due to deep convection - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,5)] - standard_name = cumulative_change_in_temperature_due_to_shallow_convection - long_name = cumulative change in temperature due to shallow convection - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,6)] - standard_name = cumulative_change_in_temperature_due_to_microphysics - long_name = cumulative change in temperature due to microphysics - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,7)] - standard_name = cumulative_change_in_temperature_due_to_orographic_gravity_wave_drag - long_name = cumulative change in temperature due to orographic gravity wave drag - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,8)] - standard_name = cumulative_change_in_temperature_due_to_rayleigh_damping - long_name = cumulative change in temperature due to Rayleigh damping - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,9)] - standard_name = cumulative_change_in_temperature_due_to_convective_gravity_wave_drag - long_name = cumulative change in temperature due to convective gravity wave drag - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,10)] - standard_name = cumulative_change_in_temperature_due_to_physics - long_name = cumulative change in temperature due to physics - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D) -[dt3dt(:,:,11)] - standard_name = cumulative_change_in_temperature_due_to_non_physics_processes - long_name = cumulative change in temperature due to non-physics processed - units = K - dimensions = (horizontal_loop_extent,vertical_dimension) +[dtend] + standard_name = cumulative_change_of_state_variables + long_name = diagnostic tendencies for state variables + units = various + dimensions = (horizontal_loop_extent,vertical_dimension,number_of_cumulative_change_processes) type = real kind = kind_phys active = (flag_diagnostics_3D) -[dq3dt(:,:,1)] - standard_name = cumulative_change_in_water_vapor_specific_humidity_due_to_PBL - long_name = cumulative change in water vapor specific humidity due to PBL - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,2)] - standard_name = cumulative_change_in_water_vapor_specific_humidity_due_to_deep_convection - long_name = cumulative change in water vapor specific humidity due to deep convection - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,3)] - standard_name = cumulative_change_in_water_vapor_specific_humidity_due_to_shallow_convection - long_name = cumulative change in water vapor specific humidity due to shallow convection - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,4)] - standard_name = cumulative_change_in_water_vapor_specific_humidity_due_to_microphysics - long_name = cumulative change in water vapor specific humidity due to microphysics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,5)] - standard_name = cumulative_change_in_ozone_mixing_ratio_due_to_PBL - long_name = cumulative change in ozone mixing ratio due to PBL - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,6)] - standard_name = cumulative_change_in_ozone_concentration_due_to_production_and_loss_rate - long_name = cumulative change in ozone concentration due to production and loss rate - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,7)] - standard_name = cumulative_change_in_ozone_concentration_due_to_ozone_mixing_ratio - long_name = cumulative change in ozone concentration due to ozone mixing ratio - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,8)] - standard_name = cumulative_change_in_ozone_concentration_due_to_temperature - long_name = cumulative change in ozone concentration due to temperature - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,9)] - standard_name = cumulative_change_in_ozone_concentration_due_to_overhead_ozone_column - long_name = cumulative change in ozone concentration due to overhead ozone column - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,10)] - standard_name = cumulative_change_in_water_vapor_specific_humidity_due_to_physics - long_name = cumulative change in water vapor specific humidity due to physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,11)] - standard_name = cumulative_change_in_ozone_concentration_due_to_physics - long_name = cumulative change in ozone concentration due to physics - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,12)] - standard_name = cumulative_change_in_water_vapor_specific_humidity_due_to_non_physics_processes - long_name = cumulative change in water vapor specific humidity due to non-physics processes - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) -[dq3dt(:,:,13)] - standard_name = cumulative_change_in_ozone_concentration_due_to_non_physics_processes - long_name = cumulative change in ozone_concentration due to non-physics processes - units = kg kg-1 - dimensions = (horizontal_loop_extent,vertical_dimension) - type = real - kind = kind_phys - active = (flag_diagnostics_3D .and. flag_tracer_diagnostics_3D) [refdmax] standard_name = maximum_reflectivity_at_1km_agl_over_maximum_hourly_time_interval long_name = maximum reflectivity at 1km agl over maximum hourly time interval @@ -10611,6 +10456,12 @@ type = character kind = len=128 active = (flag_for_rrtmgp_radiation_scheme) +[rtg_ozone_index] + standard_name = vertically_diffused_tracer_index_of_ozone + long_name = number of tracers + units = count + dimensions = () + type = integer ######################################################################## [ccpp-table-properties] diff --git a/ccpp/driver/GFS_diagnostics.F90 b/ccpp/driver/GFS_diagnostics.F90 index fea122446..f3d8faf9b 100644 --- a/ccpp/driver/GFS_diagnostics.F90 +++ b/ccpp/driver/GFS_diagnostics.F90 @@ -46,11 +46,52 @@ module GFS_diagnostics !--- public interfaces --- public GFS_externaldiag_populate - + CONTAINS !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - + + ! Helper function for GFS_externaldiag_populate to handle the massive dtend(:,:,dtidx(:,:)) array + subroutine add_dtend(Model,ExtDiag,IntDiag,idx,nblks,itrac,iprocess,desc,unit) + implicit none + type(GFS_control_type), intent(in) :: Model + type(GFS_externaldiag_type), intent(inout) :: ExtDiag(:) + type(GFS_diag_type), intent(in) :: IntDiag(:) + integer, intent(in) :: nblks, itrac, iprocess + integer, intent(inout) :: idx + real(kind=kind_phys), pointer :: dtend(:,:,:) ! Assumption: dtend is null iff all(dtidx <= 1) + character(len=*), intent(in), optional :: desc, unit + + integer :: idtend, nb + + idtend = Model%dtidx(itrac,iprocess) + if(idtend>=1) then + idx = idx + 1 + ExtDiag(idx)%axes = 3 + ExtDiag(idx)%name = 'dtend_'//trim(Model%dtend_var_labels(itrac)%name)//'_'//trim(Model%dtend_process_labels(iprocess)%name) + ExtDiag(idx)%mod_name = Model%dtend_process_labels(iprocess)%mod_name + ExtDiag(idx)%time_avg = Model%dtend_process_labels(iprocess)%time_avg + if(present(desc)) then + ExtDiag(idx)%desc = desc + else + ExtDiag(idx)%desc = trim(Model%dtend_var_labels(itrac)%desc)//' '//trim(Model%dtend_process_labels(iprocess)%desc) + endif + if(present(unit)) then + ExtDiag(idx)%unit = trim(unit) + else + ExtDiag(idx)%unit = trim(Model%dtend_var_labels(itrac)%unit) + endif + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dtend(:,:,idtend) + enddo + if(Model%me==Model%master .and. Model%ldiag3d) then +307 format('ExtDiag(',I4,') = dtend(:,:,',I4,') = ',A,' (',A,': ',A,')') + print 307,idx,idtend,trim(ExtDiag(idx)%name),trim(ExtDiag(idx)%mod_name),trim(ExtDiag(idx)%desc) + endif + endif + end subroutine add_dtend + !------------------------------------------------------------------------- !--- GFS_externaldiag_populate --- !------------------------------------------------------------------------- @@ -81,7 +122,8 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop ! ExtDiag%data(nb)%var3(:,:) [real*8 ] pointer to 3D data [=> null() for a 2D field] ! !---------------------------------------------------------------------------------------------! - implicit none + use parse_tracers, only: get_tracer_index + implicit none ! ! --- interface variables type(GFS_externaldiag_type), intent(inout) :: ExtDiag(:) @@ -98,12 +140,13 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop type(GFS_init_type), intent(in) :: Init_parm !--- local variables - integer :: idt, idx, num, nb, nblks, NFXR + integer :: idt, idx, num, nb, nblks, NFXR, idtend, ichem, itrac, iprocess character(len=2) :: xtra real(kind=kind_phys), parameter :: cn_one = 1._kind_phys real(kind=kind_phys), parameter :: cn_100 = 100._kind_phys real(kind=kind_phys), parameter :: cn_th = 1000._kind_phys real(kind=kind_phys), parameter :: cn_hr = 3600._kind_phys + character(len=30) :: namestr, descstr NFXR = Model%NFXR nblks = size(Statein) @@ -2336,526 +2379,55 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop ! if(mpp_pe()==mpp_root_pe())print *,'in gfdl_diag_register,af shum_wts,idx=',idx -!--- three-dimensional variables that need to be handled special when writing +!--- Three-dimensional diagnostic tendencies stored in a 4D sparse +!--- array need special handling: if_ldiag3d: if(Model%ldiag3d) then - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_lw' - ExtDiag(idx)%desc = 'temperature tendency due to long wave radiation' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,1) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_sw' - ExtDiag(idx)%desc = 'temperature tendency due to short wave radiation' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,2) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_pbl' - ExtDiag(idx)%desc = 'temperature tendency due to PBL' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,3) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_deepcnv' - ExtDiag(idx)%desc = 'temperature tendency due to deep convection' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,4) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_shalcnv' - ExtDiag(idx)%desc = 'temperature tendency due to shallow convection' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,5) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_mp' - ExtDiag(idx)%desc = 'temperature tendency due to microphysics' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,6) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_orogwd' - ExtDiag(idx)%desc = 'temperature tendency due to orographic gravity wave drag' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,7) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_rdamp' - ExtDiag(idx)%desc = 'temperature tendency due to Rayleigh damping' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,8) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_cnvgwd' - ExtDiag(idx)%desc = 'temperature tendency due to convective gravity wave drag' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,9) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_phys' - ExtDiag(idx)%desc = 'temperature tendency due to physics' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,10) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dt3dt_nophys' - ExtDiag(idx)%desc = 'temperature tendency due to non-physics processes' - ExtDiag(idx)%unit = 'K s-1' - ExtDiag(idx)%mod_name = 'gfs_dyn' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dt3dt(:,:,11) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'du3dt_pbl' - ExtDiag(idx)%desc = 'u momentum tendency due to PBL' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%du3dt(:,:,1) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dv3dt_pbl' - ExtDiag(idx)%desc = 'v momentum tendency due to PBL' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dv3dt(:,:,1) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'du3dt_orogwd' - ExtDiag(idx)%desc = 'u momentum tendency due to orographic gravity wave drag' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%du3dt(:,:,2) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dv3dt_orogwd' - ExtDiag(idx)%desc = 'v momentum tendency due to orographic gravity wave drag' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dv3dt(:,:,2) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'du3dt_deepcnv' - ExtDiag(idx)%desc = 'u momentum tendency due to deep convection' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%du3dt(:,:,3) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dv3dt_deepcnv' - ExtDiag(idx)%desc = 'v momentum tendency due to deep convection' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dv3dt(:,:,3) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'du3dt_cnvgwd' - ExtDiag(idx)%desc = 'u momentum tendency due to convective gravity wave drag' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%du3dt(:,:,4) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dv3dt_cnvgwd' - ExtDiag(idx)%desc = 'v momentum tendency due to convective gravity wave drag' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dv3dt(:,:,4) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'du3dt_rdamp' - ExtDiag(idx)%desc = 'u momentum tendency due to Rayleigh damping' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%du3dt(:,:,5) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dv3dt_damp' - ExtDiag(idx)%desc = 'v momentum tendency due to Rayleigh damping' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dv3dt(:,:,5) - enddo - - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'du3dt_shalcnv' - ExtDiag(idx)%desc = 'u momentum tendency due to shallow convection' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%du3dt(:,:,6) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dv3dt_shalcnv' - ExtDiag(idx)%desc = 'v momentum tendency due to shallow convection' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dv3dt(:,:,6) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'du3dt_phys' - ExtDiag(idx)%desc = 'u momentum tendency due to physics' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%du3dt(:,:,7) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dv3dt_phys' - ExtDiag(idx)%desc = 'v momentum tendency due to physics' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dv3dt(:,:,7) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'du3dt_nophys' - ExtDiag(idx)%desc = 'u momentum tendency due to non-physics processes' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_dyn' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%du3dt(:,:,8) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dv3dt_nophys' - ExtDiag(idx)%desc = 'v momentum tendency due to non-physics processes' - ExtDiag(idx)%unit = 'm s-2' - ExtDiag(idx)%mod_name = 'gfs_dyn' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dv3dt(:,:,8) + do iprocess=1,Model%nprocess + do itrac=1,Model%ntracp100 + if(Model%dtidx(itrac,iprocess)>=1) then + call add_dtend(Model,ExtDiag,IntDiag,idx,nblks,itrac,iprocess) + endif + enddo enddo - + if_qdiag3d: if(Model%qdiag3d) then - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_pbl' - ExtDiag(idx)%desc = 'water vapor specific humidity tendency due to PBL' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,1) - enddo idx = idx + 1 ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_deepcnv' - ExtDiag(idx)%desc = 'water vapor specific humidity tendency due to deep convection' - ExtDiag(idx)%unit = 'kg kg-1 s-1' + ExtDiag(idx)%name = 'upd_mf' + ExtDiag(idx)%desc = 'updraft convective mass flux' + ExtDiag(idx)%unit = 'kg m-1 s-3' ExtDiag(idx)%mod_name = 'gfs_phys' ExtDiag(idx)%time_avg = .TRUE. allocate (ExtDiag(idx)%data(nblks)) do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,2) + ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%upd_mf(:,:) enddo idx = idx + 1 ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_shalcnv' - ExtDiag(idx)%desc = 'water vapor specific humidity tendency due to shallow convection' - ExtDiag(idx)%unit = 'kg kg-1 s-1' + ExtDiag(idx)%name = 'dwn_mf' + ExtDiag(idx)%desc = 'downdraft convective mass flux' + ExtDiag(idx)%unit = 'kg m-1 s-3' ExtDiag(idx)%mod_name = 'gfs_phys' ExtDiag(idx)%time_avg = .TRUE. allocate (ExtDiag(idx)%data(nblks)) do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,3) + ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dwn_mf(:,:) enddo idx = idx + 1 ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_mp' - ExtDiag(idx)%desc = 'water vapor specific humidity tendency due to microphysics' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,4) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_o3pbl' - ExtDiag(idx)%desc = 'ozone mixing ratio tendency due to PBL' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,5) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_o3prodloss' - ExtDiag(idx)%desc = 'ozone concentration tendency due to production and loss rate' - ExtDiag(idx)%unit = 'kg kg-1 s-1' + ExtDiag(idx)%name = 'det_mf' + ExtDiag(idx)%desc = 'detrainment convective mass flux' + ExtDiag(idx)%unit = 'kg m-1 s-3' ExtDiag(idx)%mod_name = 'gfs_phys' ExtDiag(idx)%time_avg = .TRUE. allocate (ExtDiag(idx)%data(nblks)) do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,6) + ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%det_mf(:,:) enddo - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_o3mix' - ExtDiag(idx)%desc = 'ozone concentration tendency due to ozone mixing ratio' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,7) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_o3temp' - ExtDiag(idx)%desc = 'ozone concentration tendency due to temperature' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,8) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_o3column' - ExtDiag(idx)%desc = 'ozone concentration tendency due to overhead ozone column' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,9) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_phys' - ExtDiag(idx)%desc = 'water vapor specific humidity tendency due to physics' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,10) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_o3phys' - ExtDiag(idx)%desc = 'ozone concentration tendency due to physics' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,11) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_nophys' - ExtDiag(idx)%desc = 'water vapor specific humidity tendency due to non-physics processes' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_dyn' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,12) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dq3dt_o3nophys' - ExtDiag(idx)%desc = 'ozone concentration tendency due to non-physics processes' - ExtDiag(idx)%unit = 'kg kg-1 s-1' - ExtDiag(idx)%mod_name = 'gfs_dyn' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dq3dt(:,:,13) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'upd_mf' - ExtDiag(idx)%desc = 'updraft convective mass flux' - ExtDiag(idx)%unit = 'kg m-1 s-3' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%upd_mf(:,:) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'dwn_mf' - ExtDiag(idx)%desc = 'downdraft convective mass flux' - ExtDiag(idx)%unit = 'kg m-1 s-3' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%dwn_mf(:,:) - enddo - - idx = idx + 1 - ExtDiag(idx)%axes = 3 - ExtDiag(idx)%name = 'det_mf' - ExtDiag(idx)%desc = 'detrainment convective mass flux' - ExtDiag(idx)%unit = 'kg m-1 s-3' - ExtDiag(idx)%mod_name = 'gfs_phys' - ExtDiag(idx)%time_avg = .TRUE. - allocate (ExtDiag(idx)%data(nblks)) - do nb = 1,nblks - ExtDiag(idx)%data(nb)%var3 => IntDiag(nb)%det_mf(:,:) - enddo - end if if_qdiag3d end if if_ldiag3d @@ -2865,7 +2437,7 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop !rab write (xtra,'(I1)') num !rab idx = idx + 1 !rab ExtDiag(idx)%axes = 3 -!rab ExtDiag(idx)%name = 'dq3dt_'//trim(xtra) +!rab ExtDiag(idx)%name = 'dtend_'//trim(xtra) !rab ExtDiag(idx)%desc = 'moisture change due to physics '//trim(xtra)//'' !rab ExtDiag(idx)%unit = 'XXX' !rab ExtDiag(idx)%mod_name = 'gfs_phys' diff --git a/ccpp/physics b/ccpp/physics index 21df4016f..417ec2d0c 160000 --- a/ccpp/physics +++ b/ccpp/physics @@ -1 +1 @@ -Subproject commit 21df4016f4d435ed531b773e80b462d57e1f4213 +Subproject commit 417ec2d0cdb9c89fd745104ee3fcd316168f0977 diff --git a/ccpp/suites/suite_FV3_RRFS_v1beta.xml b/ccpp/suites/suite_FV3_RRFS_v1beta.xml index 2691dedd4..74baa3a98 100644 --- a/ccpp/suites/suite_FV3_RRFS_v1beta.xml +++ b/ccpp/suites/suite_FV3_RRFS_v1beta.xml @@ -77,6 +77,7 @@ GFS_stochastics + phys_tend diff --git a/io/FV3GFS_io.F90 b/io/FV3GFS_io.F90 index 5fa2e13c2..6fe8673a8 100644 --- a/io/FV3GFS_io.F90 +++ b/io/FV3GFS_io.F90 @@ -2288,38 +2288,6 @@ subroutine fv3gfs_diag_output(time, diag, atm_block, nx, ny, levs, ntcw, ntoz, & call store_data3D(Diag(idx)%id, var3, Time, idx, Diag(idx)%intpl_method, Diag(idx)%name) #ifdef JUNK else - !--- dt3dt variables - do num = 1,6 - write(xtra,'(i1)') num - if (trim(Diag(idx)%name) == 'dt3dt_'//trim(xtra)) then - var3(1:nx,1:ny,1:levs) = RESHAPE(Gfs_diag%dt3dt(1:ngptc,levs:1:-1,num:num), (/nx,ny,levs/)) - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif - enddo - !--- dq3dt variables - do num = 1,5+Mdl_parms%pl_coeff - write(xtra,'(i1)') num - if (trim(Diag(idx)%name) == 'dq3dt_'//trim(xtra)) then - var3(1:nx,1:ny,1:levs) = RESHAPE(Gfs_diag%dq3dt(1:ngptc,levs:1-1,num:num), (/nx,ny,levs/)) - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif - enddo - !--- du3dt and dv3dt variables - do num = 1,4 - write(xtra,'(i1)') num - if (trim(Diag(idx)%name) == 'du3dt_'//trim(xtra)) then - var3(1:nx,1:ny,1:levs) = RESHAPE(Gfs_diag%du3dt(1:ngptc,levs:1:-1,num:num), (/nx,ny,levs/)) - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif - if (trim(Diag(idx)%name) == 'dv3dt_'//trim(xtra)) then - var3(1:nx,1:ny,1:levs) = RESHAPE(Gfs_diag%dv3dt(1:ngptc,levs:1:-1,num:num), (/nx,ny,levs/)) - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif - enddo - if (trim(Diag(idx)%name) == 'dqdt_v') then - var3(1:nx,1:ny,1:levs) = RESHAPE(Gfs_diag%dqdt_v(1:ngptc,levs:1:-1), (/nx,ny,levs/)) - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif !--- temperature tendency if (trim(Diag(idx)%name) == 'dtemp_dt') then var3(1:nx,1:ny,1:levs) = RESHAPE(Statein%tgrs(1:ngptc,levs:1:-1), (/nx,ny,levs/))