diff --git a/ccpp/config/ccpp_prebuild_config.py b/ccpp/config/ccpp_prebuild_config.py index bbc7da433..8723f89b1 100755 --- a/ccpp/config/ccpp_prebuild_config.py +++ b/ccpp/config/ccpp_prebuild_config.py @@ -187,6 +187,10 @@ 'physics/physics/sfc_sice.f', # HAFS FER_HIRES 'physics/physics/mp_fer_hires.F90', + # SMOKE + 'physics/smoke/rrfs_smoke_wrapper.F90', + 'physics/smoke/rrfs_smoke_postpbl.F90', + 'physics/smoke/rrfs_smoke_lsdep_wrapper.F90', # RRTMGP 'physics/physics/rrtmgp_lw_gas_optics.F90', 'physics/physics/rrtmgp_lw_cloud_optics.F90', diff --git a/ccpp/data/GFS_typedefs.F90 b/ccpp/data/GFS_typedefs.F90 index 84302cac4..a5d7fda42 100644 --- a/ccpp/data/GFS_typedefs.F90 +++ b/ccpp/data/GFS_typedefs.F90 @@ -247,6 +247,9 @@ module GFS_typedefs real (kind=kind_phys), pointer :: snodi (:) => null() !< snow depth over ice real (kind=kind_phys), pointer :: weasdi (:) => null() !< weasd over ice real (kind=kind_phys), pointer :: hprime (:,:) => null() !< orographic metrics + real (kind=kind_phys), pointer :: dust12m_in (:,:,:) => null() !< fengsha dust input + real (kind=kind_phys), pointer :: emi_in (:,:) => null() !< anthropogenic background input + real (kind=kind_phys), pointer :: smoke_GBBEPx(:,:,:) => null() !< GBBEPx fire input real (kind=kind_phys), pointer :: z0base (:) => null() !< background or baseline surface roughness length in m real (kind=kind_phys), pointer :: semisbase(:) => null() !< background surface emissivity real (kind=kind_phys), pointer :: sfalb_lnd (:) => null() !< surface albedo over land for LSM @@ -551,12 +554,42 @@ module GFS_typedefs real (kind=kind_phys), pointer :: nwfa2d (:) => null() !< instantaneous water-friendly sfc aerosol source real (kind=kind_phys), pointer :: nifa2d (:) => null() !< instantaneous ice-friendly sfc aerosol source + !--- aerosol surface emissions for Thompson microphysics & smoke + real (kind=kind_phys), pointer :: emdust (:) => null() !< instantaneous dust emission + real (kind=kind_phys), pointer :: emseas (:) => null() !< instantaneous sea salt emission + real (kind=kind_phys), pointer :: emanoc (:) => null() !< instantaneous anthro. oc emission + + !--- These 3 arrays are hourly, so their dimension is imx24 (output is hourly) + real (kind=kind_phys), pointer :: ebb_smoke_hr(:) => null() !< hourly smoke emission + real (kind=kind_phys), pointer :: frp_hr (:) => null() !< hourly FRP + real (kind=kind_phys), pointer :: frp_std_hr (:) => null() !< hourly std. FRP + + !--- For fire diurnal cycle + real (kind=kind_phys), pointer :: fhist (:) => null() !< instantaneous fire coef_bb + real (kind=kind_phys), pointer :: coef_bb_dc (:) => null() !< instantaneous fire coef_bb + real (kind=kind_phys), pointer :: ebu_smoke (:,:) => null() !< 3D ebu array + + !--- For smoke and dust optical extinction + real (kind=kind_phys), pointer :: smoke_ext (:,:) => null() !< 3D aod array + real (kind=kind_phys), pointer :: dust_ext (:,:) => null() !< 3D aod array + !--- For MYNN PBL transport of smoke and dust + real (kind=kind_phys), pointer :: chem3d (:,:,:) => null() !< 3D aod array + + !--- Fire plume rise diagnostics + real (kind=kind_phys), pointer :: min_fplume (:) => null() !< minimum plume rise level + real (kind=kind_phys), pointer :: max_fplume (:) => null() !< maximum plume rise level + !--- hourly fire potential index + real (kind=kind_phys), pointer :: rrfs_hwp (:) => null() !< hourly fire potential index + !--- instantaneous quantities for chemistry coupling real (kind=kind_phys), pointer :: ushfsfci(:) => null() !< instantaneous upward sensible heat flux (w/m**2) real (kind=kind_phys), pointer :: qci_conv(:,:) => null() !< convective cloud condesate after rainout real (kind=kind_phys), pointer :: pfi_lsan(:,:) => null() !< instantaneous 3D flux of ice nonconvective precipitation (kg m-2 s-1) real (kind=kind_phys), pointer :: pfl_lsan(:,:) => null() !< instantaneous 3D flux of liquid nonconvective precipitation (kg m-2 s-1) + !--- instantaneous total moisture tendency for smoke coupling: + real (kind=kind_phys), pointer :: dqdti (:,:) => null() !< rrfs_smoke=true only; instantaneous total moisture tendency (kg/kg/s) + contains procedure :: create => coupling_create !< allocate array data end type GFS_coupling_type @@ -648,6 +681,7 @@ module GFS_typedefs logical :: cplwav !< default no cplwav collection logical :: cplwav2atm !< default no wav->atm coupling logical :: cplchm !< default no cplchm collection + logical :: rrfs_smoke !< default no rrfs_smoke collection logical :: use_cice_alb !< default .false. - i.e. don't use albedo imported from the ice model logical :: cpl_imp_mrg !< default no merge import with internal forcings logical :: cpl_imp_dbg !< default no write import data to file post merge @@ -1246,6 +1280,10 @@ module GFS_typedefs integer :: nto2 !< tracer index for oxygen integer :: ntwa !< tracer index for water friendly aerosol integer :: ntia !< tracer index for ice friendly aerosol + integer :: ntsmoke !< tracer index for smoke + integer :: ntdust !< tracer index for dust + integer :: nchem !< number of prognostic chemical species (vertically mixied) + integer :: ndvel !< number of prognostic chemical species (which are deposited, usually =nchem) integer :: ntchm !< number of prognostic chemical tracers (advected) integer :: ntchs !< tracer index for first prognostic chemical tracer integer :: ntche !< tracer index for last prognostic chemical tracer @@ -1284,6 +1322,22 @@ module GFS_typedefs integer :: npsdelt !< the index of surface air pressure at the previous timestep for Z-C MP in phy_f2d integer :: ncnvwind !< the index of surface wind enhancement due to convection for MYNN SFC and RAS CNV in phy f2d +!-- chem nml variables for RRFS-Smoke + integer :: seas_opt + integer :: dust_opt + integer :: biomass_burn_opt + integer :: drydep_opt + integer :: wetdep_ls_opt + logical :: do_plumerise + integer :: addsmoke_flag + integer :: plumerisefire_frq + logical :: smoke_forecast + logical :: aero_ind_fdb ! WFA/IFA indirect + logical :: aero_dir_fdb ! smoke/dust direct + logical :: rrfs_smoke_debug + logical :: mix_chem + logical :: fire_turb + !--- debug flags logical :: debug logical :: pre_rad !< flag for testing purpose @@ -2379,6 +2433,9 @@ subroutine sfcprop_create (Sfcprop, IM, Model) allocate (Sfcprop%snodi (IM)) allocate (Sfcprop%weasdi (IM)) allocate (Sfcprop%hprime (IM,Model%nmtvr)) + allocate (Sfcprop%dust12m_in (IM,12,5)) + allocate (Sfcprop%smoke_GBBEPx(IM,24,3)) + allocate (Sfcprop%emi_in (IM,1)) allocate(Sfcprop%albdirvis_lnd (IM)) allocate(Sfcprop%albdirnir_lnd (IM)) allocate(Sfcprop%albdifvis_lnd (IM)) @@ -2409,6 +2466,9 @@ subroutine sfcprop_create (Sfcprop, IM, Model) Sfcprop%snodi = clear_val Sfcprop%weasdi = clear_val Sfcprop%hprime = clear_val + Sfcprop%dust12m_in= clear_val + Sfcprop%emi_in = clear_val + Sfcprop%smoke_GBBEPx = clear_val Sfcprop%albdirvis_lnd = clear_val Sfcprop%albdirnir_lnd = clear_val Sfcprop%albdifvis_lnd = clear_val @@ -2976,7 +3036,7 @@ subroutine coupling_create (Coupling, IM, Model) endif ! -- Aerosols coupling options - if (Model%cplchm) then + if (Model%cplchm .or. Model%rrfs_smoke) then !--- outgoing instantaneous quantities allocate (Coupling%ushfsfci (IM)) !--- accumulated convective rainfall @@ -3039,6 +3099,42 @@ subroutine coupling_create (Coupling, IM, Model) Coupling%nifa2d = clear_val endif + if(Model%rrfs_smoke) then + !--- needed for smoke aerosol option + allocate (Coupling%emdust (IM)) + allocate (Coupling%emseas (IM)) + allocate (Coupling%emanoc (IM)) + allocate (Coupling%ebb_smoke_hr (IM)) + allocate (Coupling%frp_hr (IM)) + allocate (Coupling%frp_std_hr(IM)) + allocate (Coupling%fhist (IM)) + allocate (Coupling%coef_bb_dc(IM)) + allocate (Coupling%ebu_smoke (IM,Model%levs)) + allocate (Coupling%smoke_ext (IM,Model%levs)) + allocate (Coupling%dust_ext (IM,Model%levs)) + allocate (Coupling%chem3d (IM,Model%levs,2)) + allocate (Coupling%min_fplume(IM)) + allocate (Coupling%max_fplume(IM)) + allocate (Coupling%rrfs_hwp (IM)) + allocate (Coupling%dqdti (IM,Model%levs)) + Coupling%emdust = clear_val + Coupling%emseas = clear_val + Coupling%emanoc = clear_val + Coupling%ebb_smoke_hr = clear_val + Coupling%frp_hr = clear_val + Coupling%frp_std_hr = clear_val + Coupling%fhist = 1. + Coupling%coef_bb_dc = clear_val + Coupling%ebu_smoke = clear_val + Coupling%smoke_ext = clear_val + Coupling%dust_ext = clear_val + Coupling%chem3d = clear_val + Coupling%min_fplume = clear_val + Coupling%max_fplume = clear_val + Coupling%rrfs_hwp = clear_val + Coupling%dqdti = clear_val + endif + if (Model%imfdeepcnv == Model%imfdeepcnv_gf) then allocate (Coupling%qci_conv (IM,Model%levs)) Coupling%qci_conv = clear_val @@ -3134,6 +3230,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & logical :: cplwav = .false. !< default no cplwav collection logical :: cplwav2atm = .false. !< default no cplwav2atm coupling logical :: cplchm = .false. !< default no cplchm collection + logical :: rrfs_smoke = .false. !< default no rrfs_smoke collection logical :: use_cice_alb = .false. !< default no cice albedo logical :: cpl_imp_mrg = .false. !< default no merge import with internal forcings logical :: cpl_imp_dbg = .false. !< default no write import data to file post merge @@ -3601,6 +3698,22 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & integer :: spp_gwd = 0 logical :: do_spp = .false. +!-- chem nml variables for RRFS-Smoke + integer :: seas_opt = 2 + integer :: dust_opt = 5 + integer :: biomass_burn_opt = 1 + integer :: drydep_opt = 1 + integer :: wetdep_ls_opt = 1 + logical :: do_plumerise = .false. + integer :: addsmoke_flag = 1 + integer :: plumerisefire_frq = 60 + logical :: smoke_forecast = .false. ! RRFS-smoke diurnal + logical :: aero_ind_fdb = .false. ! RRFS-smoke wfa/ifa emission + logical :: aero_dir_fdb = .false. ! RRFS-smoke smoke/dust radiation feedback + logical :: rrfs_smoke_debug = .false. ! RRFS-smoke plumerise debug + logical :: mix_chem = .false. ! tracer mixing option by MYNN PBL + logical :: fire_turb = .false. ! enh vertmix option by MYNN PBL + !--- aerosol scavenging factors integer, parameter :: max_scav_factors = 25 character(len=40) :: fscav_aero(max_scav_factors) @@ -3617,7 +3730,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & thermodyn_id, sfcpress_id, & !--- coupling parameters cplflx, cplice, cplocn2atm, cplwav, cplwav2atm, cplchm, & - cpl_imp_mrg, cpl_imp_dbg, & + cpl_imp_mrg, cpl_imp_dbg, rrfs_smoke, & use_cice_alb, & #ifdef IDEA_PHYS lsidea, weimer_model, f107_kp_size, f107_kp_interval, & @@ -3731,6 +3844,11 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & phys_version, & !--- aerosol scavenging factors ('name:value' string array) fscav_aero, & + !--- RRFS smoke namelist + seas_opt, dust_opt, biomass_burn_opt, drydep_opt, & + wetdep_ls_opt, smoke_forecast, aero_ind_fdb, aero_dir_fdb, & + rrfs_smoke_debug, do_plumerise, plumerisefire_frq, & + addsmoke_flag, fire_turb, mix_chem, & !--- (DFI) time ranges with radar-prescribed microphysics tendencies ! and (maybe) convection suppression fh_dfi_radar, radar_tten_limits, do_cap_suppress @@ -3933,6 +4051,23 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%cpl_imp_mrg = cpl_imp_mrg Model%cpl_imp_dbg = cpl_imp_dbg +!--- RRFS Smoke + Model%rrfs_smoke = rrfs_smoke + Model%seas_opt = seas_opt + Model%dust_opt = dust_opt + Model%biomass_burn_opt = biomass_burn_opt + Model%drydep_opt = drydep_opt + Model%wetdep_ls_opt = wetdep_ls_opt + Model%do_plumerise = do_plumerise + Model%plumerisefire_frq = plumerisefire_frq + Model%addsmoke_flag = addsmoke_flag + Model%smoke_forecast = smoke_forecast + Model%aero_ind_fdb = aero_ind_fdb + Model%aero_dir_fdb = aero_dir_fdb + Model%rrfs_smoke_debug = rrfs_smoke_debug + Model%mix_chem = mix_chem + Model%fire_turb = fire_turb + !--- integrated dynamics through earth's atmosphere Model%lsidea = lsidea if (Model%lsidea) then @@ -4572,6 +4707,8 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%nqrimef = get_tracer_index(Model%tracer_names, 'q_rimef', Model%me, Model%master, Model%debug) Model%ntwa = get_tracer_index(Model%tracer_names, 'liq_aero', Model%me, Model%master, Model%debug) Model%ntia = get_tracer_index(Model%tracer_names, 'ice_aero', Model%me, Model%master, Model%debug) + Model%ntsmoke = get_tracer_index(Model%tracer_names, 'smoke', Model%me, Model%master, Model%debug) + Model%ntdust = get_tracer_index(Model%tracer_names, 'dust', Model%me, Model%master, Model%debug) !--- initialize parameters for atmospheric chemistry tracers call Model%init_chemistry(tracer_types) @@ -5471,6 +5608,8 @@ subroutine control_chemistry_initialize(Model, tracer_types) integer :: n !--- begin + Model%nchem = 0 + Model%ndvel = 0 Model%ntchm = 0 Model%ntchs = NO_TRACER Model%ntche = NO_TRACER @@ -5478,6 +5617,11 @@ subroutine control_chemistry_initialize(Model, tracer_types) Model%ndchs = NO_TRACER Model%ndche = NO_TRACER + if (Model%rrfs_smoke) then + Model%nchem = 2 + Model%ndvel = 2 + endif + do n = 1, size(tracer_types) select case (tracer_types(n)) case (1) @@ -5608,6 +5752,7 @@ subroutine control_print(Model) print *, ' cplwav : ', Model%cplwav print *, ' cplwav2atm : ', Model%cplwav2atm print *, ' cplchm : ', Model%cplchm + print *, ' rrfs_smoke : ', Model%rrfs_smoke print *, ' use_cice_alb : ', Model%use_cice_alb print *, ' cpl_imp_mrg : ', Model%cpl_imp_mrg print *, ' cpl_imp_dbg : ', Model%cpl_imp_dbg @@ -5976,6 +6121,10 @@ subroutine control_print(Model) print *, ' nto2 : ', Model%nto2 print *, ' ntwa : ', Model%ntwa print *, ' ntia : ', Model%ntia + print *, ' ntsmoke : ', Model%ntsmoke + print *, ' ntdust : ', Model%ntdust + print *, ' nchem : ', Model%nchem + print *, ' ndvel : ', Model%ndvel print *, ' ntchm : ', Model%ntchm print *, ' ntchs : ', Model%ntchs print *, ' ntche : ', Model%ntche diff --git a/ccpp/data/GFS_typedefs.meta b/ccpp/data/GFS_typedefs.meta index 4cec6d322..ec4a18432 100644 --- a/ccpp/data/GFS_typedefs.meta +++ b/ccpp/data/GFS_typedefs.meta @@ -261,6 +261,20 @@ dimensions = (horizontal_loop_extent,vertical_layer_dimension) type = real kind = kind_phys +[qgrs(:,:,index_for_smoke)] + standard_name = smoke_tracer_concentration + long_name = concentration of smoke + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys +[qgrs(:,:,index_for_dust)] + standard_name = dust_tracer_concentration + long_name = concentration of dust + units = kg kg-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys [diss_est] standard_name = dissipation_estimate_of_air_temperature_at_model_layers long_name = dissipation estimate model layer mean temperature @@ -620,6 +634,30 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys +[dust12m_in] + standard_name = fengsha_dust12m_input + long_name = fengsha dust input + units = various + dimensions = (horizontal_dimension,12,5) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[emi_in] + standard_name = anthropogenic_background_input + long_name = anthropogenic background input + units = various + dimensions = (horizontal_dimension,1) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[smoke_GBBEPx] + standard_name = emission_smoke_GBBEPx + long_name = emission fire GBBEPx + units = various + dimensions = (horizontal_dimension,24,3) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) [z0base] standard_name = baseline_surface_roughness_length long_name = baseline surface roughness length for momentum in meter @@ -2292,6 +2330,14 @@ type = real kind = kind_phys active = (control_for_stochastic_land_surface_perturbation /= 0) +[dqdti] + standard_name = instantaneous_water_vapor_specific_humidity_tendency_due_to_convection + long_name = instantaneous moisture tendency due to convection + units = kg kg-1 s-1 + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) [nwfa2d] standard_name = tendency_of_hygroscopic_aerosols_at_surface_adjacent_layer long_name = instantaneous water-friendly sfc aerosol source @@ -2308,6 +2354,126 @@ type = real kind = kind_phys active = (control_for_microphysics_scheme == identifier_for_thompson_microphysics_scheme .and. flag_for_aerosol_physics) +[emdust] + standard_name = emission_of_dust_for_smoke + long_name = emission of dust for smoke + units = ug m-2 s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[emseas] + standard_name = emission_of_seas_for_smoke + long_name = emission of seas for smoke + units = ug m-2 s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[emanoc] + standard_name = emission_of_anoc_for_thompson_mp + long_name = emission of anoc for thompson mp + units = ug m-2 s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[ebb_smoke_hr] + standard_name = surfce_emission_of_smoke + long_name = emission of surface smoke + units = ug m-2 s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[frp_hr] + standard_name = frp_hourly + long_name = hourly frp + units = mw + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[frp_std_hr] + standard_name = frp_std_hourly + long_name = hourly std frp + units = mw + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[fhist] + standard_name = fhist + long_name = fire hist + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[coef_bb_dc] + standard_name = coef_bb_dc + long_name = coef bb dc from plumerise + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[ebu_smoke] + standard_name = ebu_smoke + long_name = smoke buffer of ebu + units = various + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[smoke_ext] + standard_name = smoke_ext + long_name = smoke optical extinction + units = various + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[dust_ext] + standard_name = dust_ext + long_name = dust optical extinction + units = various + dimensions = (horizontal_loop_extent,vertical_layer_dimension) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[chem3d] + standard_name = chem3d_mynn_pbl_transport + long_name = mynn pbl transport of smoke and dust + units = various + dimensions = (horizontal_loop_extent,vertical_layer_dimension,2) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[min_fplume] + standard_name = min_fplume + long_name = miminum plume height + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[max_fplume] + standard_name = max_fplume + long_name = maximum plume height + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) +[rrfs_hwp] + standard_name = rrfs_hwp + long_name = rrfs hourly fire weather potential + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (flag_for_rrfs_smoke_coupling) [ushfsfci] standard_name = surface_upward_sensible_heat_flux_for_chemistry_coupling long_name = instantaneous upward sensible heat flux for chemistry coupling @@ -2657,6 +2823,12 @@ units = flag dimensions = () type = logical +[rrfs_smoke] + standard_name = flag_for_rrfs_smoke_coupling + long_name = flag controlling rrfs_smoke collection (default off) + units = flag + dimensions = () + type = logical [cpl_imp_mrg] standard_name = flag_for_merging_imported_data long_name = flag controlling cpl_imp_mrg for imported data (default off) @@ -5010,6 +5182,30 @@ units = index dimensions = () type = integer +[ntsmoke] + standard_name = index_for_smoke + long_name = tracer index for smoke + units = index + dimensions = () + type = integer +[ntdust] + standard_name = index_for_dust + long_name = tracer index for dust + units = index + dimensions = () + type = integer +[nchem] + standard_name = number_of_chemical_species_vertically_mixed + long_name = number of chemical vertically mixed + units = count + dimensions = () + type = integer +[ndvel] + standard_name = number_of_chemical_species_deposited + long_name = number of chemical pbl deposited + units = count + dimensions = () + type = integer [ntchm] standard_name = number_of_chemical_tracers long_name = number of chemical tracers @@ -5107,6 +5303,104 @@ units = index dimensions = () type = integer +[mix_chem] + standard_name = rrfs_smoke_mynn_tracer_mixing + long_name = flag for rrfs smoke mynn tracer mixing + units = flag + dimensions = () + type = logical + active = (flag_for_rrfs_smoke_coupling) +[fire_turb] + standard_name = rrfs_smoke_mynn_enh_vermix + long_name = flag for rrfs smoke mynn enh vermix + units = flag + dimensions = () + type = logical + active = (flag_for_rrfs_smoke_coupling) +[seas_opt] + standard_name = rrfs_smoke_sea_salt_opt + long_name = rrfs smoke sea salt emission option + units = index + dimensions = () + type = integer + active = (flag_for_rrfs_smoke_coupling) +[dust_opt] + standard_name = rrfs_smoke_dust_opt + long_name = rrfs smoke dust chem option + units = index + dimensions = () + type = integer + active = (flag_for_rrfs_smoke_coupling) +[biomass_burn_opt] + standard_name = rrfs_smoke_biomass_burn_opt + long_name = rrfs smoke biomass burning option + units = index + dimensions = () + type = integer + active = (flag_for_rrfs_smoke_coupling) +[drydep_opt] + standard_name = rrfs_smoke_drydep_opt + long_name = rrfs smoke dry deposition option + units = index + dimensions = () + type = integer + active = (flag_for_rrfs_smoke_coupling) +[wetdep_ls_opt] + standard_name = rrfs_smoke_wetdep_ls_opt + long_name = rrfs smoke large scale wet deposition option + units = index + dimensions = () + type = integer + active = (flag_for_rrfs_smoke_coupling) +[do_plumerise] + standard_name = rrfs_smoke_plumerise_flag + long_name = rrfs smoke plumerise option + units = index + dimensions = () + type = logical + active = (flag_for_rrfs_smoke_coupling) +[plumerisefire_frq] + standard_name = rrfs_smoke_plumerisefire_frq + long_name = rrfs smoke add smoke option + units = index + dimensions = () + type = integer + active = (flag_for_rrfs_smoke_coupling) +[addsmoke_flag] + standard_name = rrfs_smoke_addsmoke_flag + long_name = rrfs smoke add smoke option + units = index + dimensions = () + type = integer + active = (flag_for_rrfs_smoke_coupling) +[smoke_forecast] + standard_name = rrfs_smoke_smoke_forecast_opt + long_name = flag for rrfs smoke forecast + units = flag + dimensions = () + type = logical + active = (flag_for_rrfs_smoke_coupling) +[aero_ind_fdb] + standard_name = rrfs_smoke_aero_ind_fdb_opt + long_name = flag for rrfs wfa ifa emission + units = flag + dimensions = () + type = logical + active = (flag_for_rrfs_smoke_coupling) +[aero_dir_fdb] + standard_name = rrfs_smoke_dust_rad_fdb_opt + long_name = flag for rrfs smoke dust rad feedback + units = flag + dimensions = () + type = logical + active = (flag_for_rrfs_smoke_coupling) +[rrfs_smoke_debug] + standard_name = rrfs_smoke_plumerise_debug + long_name = flag for rrfs smoke plumerise debug + units = flag + dimensions = () + type = logical + active = (flag_for_rrfs_smoke_coupling) [ncnvcld3d] standard_name = number_of_convective_cloud_variables_in_xyz_dimensioned_restart_array long_name = number of convective 3d clouds fields diff --git a/ccpp/driver/GFS_diagnostics.F90 b/ccpp/driver/GFS_diagnostics.F90 index 6e4b62337..8b4954e60 100644 --- a/ccpp/driver/GFS_diagnostics.F90 +++ b/ccpp/driver/GFS_diagnostics.F90 @@ -1764,6 +1764,20 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop ! if(mpp_pe()==mpp_root_pe())print *,'in gfdl_diag_register,af totgrp,idx=',idx +!--- RRFS Smoke --- + if (Model%rrfs_smoke) then + idx = idx + 1 + ExtDiag(idx)%axes = 3 + ExtDiag(idx)%name = 'dqdti' + ExtDiag(idx)%desc = 'dqdti' + ExtDiag(idx)%unit = 'kg kg-1 s-1' + ExtDiag(idx)%mod_name = 'gfs_phys' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var3 => Coupling(nb)%dqdti(:,:) + enddo + endif + !--- physics instantaneous diagnostics --- idx = idx + 1 ExtDiag(idx)%axes = 2 @@ -3541,6 +3555,152 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop enddo end if thompson_extended_diagnostics + if (Model%rrfs_smoke .and. Model%ntsmoke>0) then + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'emdust' + ExtDiag(idx)%desc = 'emission of dust for smoke' + ExtDiag(idx)%unit = 'ug m-2 s-1' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%emdust + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'emseas' + ExtDiag(idx)%desc = 'emission of seas for smoke' + ExtDiag(idx)%unit = 'ug m-2 s-1' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%emseas + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'emanoc' + ExtDiag(idx)%desc = 'emission of anoc for thompson mp' + ExtDiag(idx)%unit = 'ug m-2 s-1' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%emanoc + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'coef_bb_dc' + ExtDiag(idx)%desc = 'coeff bb for smoke' + ExtDiag(idx)%unit = '' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%coef_bb_dc + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'min_fplume' + ExtDiag(idx)%desc = 'minimum smoke plume height' + ExtDiag(idx)%unit = '' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%min_fplume + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'max_fplume' + ExtDiag(idx)%desc = 'maximum smoke plume height' + ExtDiag(idx)%unit = '' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%max_fplume + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'HWP' + ExtDiag(idx)%desc = 'hourly fire weather potential' + ExtDiag(idx)%unit = ' ' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%rrfs_hwp + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'ebb_smoke_hr' + ExtDiag(idx)%desc = 'hourly smoke emission' + ExtDiag(idx)%unit = 'ug m-2 s-1' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%ebb_smoke_hr + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'frp_hr' + ExtDiag(idx)%desc = 'hourly frp' + ExtDiag(idx)%unit = 'mw' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%frp_hr + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 2 + ExtDiag(idx)%name = 'frp_std_hr' + ExtDiag(idx)%desc = 'hourly std frp' + ExtDiag(idx)%unit = 'mw' + ExtDiag(idx)%mod_name = 'gfs_sfc' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var2 => Coupling(nb)%frp_std_hr + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 3 + ExtDiag(idx)%name = 'ebu_smoke' + ExtDiag(idx)%desc = 'smoke emission' + ExtDiag(idx)%unit = 'ug/m2/s' + ExtDiag(idx)%mod_name = 'gfs_phys' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var3 => Coupling(nb)%ebu_smoke(:,:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 3 + ExtDiag(idx)%name = 'smoke_ext' + ExtDiag(idx)%desc = 'smoke extinction at 550nm' + ExtDiag(idx)%unit = ' ' + ExtDiag(idx)%mod_name = 'gfs_phys' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var3 => Coupling(nb)%smoke_ext(:,:) + enddo + + idx = idx + 1 + ExtDiag(idx)%axes = 3 + ExtDiag(idx)%name = 'dust_ext' + ExtDiag(idx)%desc = 'dust extinction at 550nm' + ExtDiag(idx)%unit = ' ' + ExtDiag(idx)%mod_name = 'gfs_phys' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var3 => Coupling(nb)%dust_ext(:,:) + enddo + + endif + do i=1,Model%num_dfi_radar idx = idx + 1 ExtDiag(idx)%axes = 3 diff --git a/ccpp/suites/suite_FV3_HRRR_smoke.xml b/ccpp/suites/suite_FV3_HRRR_smoke.xml new file mode 100644 index 000000000..450007623 --- /dev/null +++ b/ccpp/suites/suite_FV3_HRRR_smoke.xml @@ -0,0 +1,83 @@ + + + + + + + GFS_time_vary_pre + GFS_rrtmg_setup + GFS_rad_time_vary + GFS_phys_time_vary + + + + + GFS_suite_interstitial_rad_reset + sgscloud_radpre + GFS_rrtmg_pre + GFS_radiation_surface + rrtmg_sw_pre + rrtmg_sw + rrtmg_sw_post + rrtmg_lw_pre + rrtmg_lw + sgscloud_radpost + rrtmg_lw_post + GFS_rrtmg_post + + + + + GFS_suite_interstitial_phys_reset + GFS_suite_stateout_reset + get_prs_fv3 + GFS_suite_interstitial_1 + GFS_surface_generic_pre + GFS_surface_composites_pre + dcyc2t3 + GFS_surface_composites_inter + GFS_suite_interstitial_2 + + + + mynnsfc_wrapper + GFS_surface_loop_control_part1 + lsm_ruc + flake_driver + GFS_surface_loop_control_part2 + + + + GFS_surface_composites_post + sfc_diag + sfc_diag_post + GFS_surface_generic_post + rrfs_smoke_wrapper + mynnedmf_wrapper + rrfs_smoke_postpbl + GFS_GWD_generic_pre + drag_suite + GFS_GWD_generic_post + GFS_suite_stateout_update + ozphys_2015 + h2ophys + get_phi_fv3 + GFS_suite_interstitial_3 + GFS_suite_interstitial_4 + GFS_MP_generic_pre + mp_thompson_pre + mp_thompson + mp_thompson_post + GFS_MP_generic_post + maximum_hourly_diagnostics + rrfs_smoke_lsdep_wrapper + phys_tend + + + + + GFS_stochastics + + + + diff --git a/io/FV3GFS_io.F90 b/io/FV3GFS_io.F90 index 041a2d46b..ef7cbf008 100644 --- a/io/FV3GFS_io.F90 +++ b/io/FV3GFS_io.F90 @@ -60,9 +60,12 @@ module FV3GFS_io_mod character(len=32) :: fn_oro_ss = 'oro_data_ss.nc' character(len=32) :: fn_srf = 'sfc_data.nc' character(len=32) :: fn_phy = 'phy_data.nc' + character(len=32) :: fn_dust12m= 'dust12m_data.nc' + character(len=32) :: fn_emi = 'emi_data.nc' + character(len=32) :: fn_gbbepx = 'SMOKE_GBBEPx_data.nc' !--- GFDL FMS netcdf restart data types defined in fms2_io - type(FmsNetcdfDomainFile_t) :: Oro_restart, Sfc_restart, Phy_restart + type(FmsNetcdfDomainFile_t) :: Oro_restart, Sfc_restart, Phy_restart, dust12m_restart, emi_restart, gbbepx_restart type(FmsNetcdfDomainFile_t) :: Oro_ls_restart, Oro_ss_restart !--- GFDL FMS restart containers @@ -71,6 +74,10 @@ module FV3GFS_io_mod character(len=32), allocatable, dimension(:) :: oro_ls_ss_name real(kind=kind_phys), allocatable, target, dimension(:,:,:) :: oro_ls_var, oro_ss_var real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: sfc_var3, phy_var3 + character(len=32), allocatable, dimension(:) :: dust12m_name, emi_name, gbbepx_name + real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: gbbepx_var + real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: dust12m_var + real(kind=kind_phys), allocatable, target, dimension(:,:,:) :: emi_var !--- Noah MP restart containers real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: sfc_var3sn,sfc_var3eq,sfc_var3zn @@ -515,6 +522,7 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta integer :: nvar_o2, nvar_s2m, nvar_s2o, nvar_s3 integer :: nvar_oro_ls_ss integer :: nvar_s2r, nvar_s2mp, nvar_s3mp, isnow + integer :: nvar_emi, nvar_dust12m, nvar_gbbepx real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p1 => NULL() @@ -534,6 +542,15 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta nvar_o2 = 19 nvar_oro_ls_ss = 10 nvar_s2o = 18 + if(Model%rrfs_smoke) then + nvar_dust12m = 5 + nvar_gbbepx = 3 + nvar_emi = 1 + else + nvar_dust12m = 0 + nvar_gbbepx = 0 + nvar_emi = 0 + endif if (Model%lsm == Model%lsm_ruc .and. warm_start) then if(Model%rdlai) then @@ -675,6 +692,150 @@ subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_sta !--- deallocate containers and free restart container deallocate(oro_name2, oro_var2) + if_smoke: if(Model%rrfs_smoke) then ! for RRFS-Smoke + + !--- Dust input FILE + !--- open file + infile=trim(indir)//'/'//trim(fn_dust12m) + amiopen=open_file(dust12m_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file'//trim(infile) ) + + if (.not. allocated(dust12m_name)) then + !--- allocate the various containers needed for fengsha dust12m data + allocate(dust12m_name(nvar_dust12m)) + allocate(dust12m_var(nx,ny,12,nvar_dust12m)) + + dust12m_name(1) = 'clay' + dust12m_name(2) = 'rdrag' + dust12m_name(3) = 'sand' + dust12m_name(4) = 'ssm' + dust12m_name(5) = 'uthr' + + !--- register axis + call register_axis(dust12m_restart, 'lon', 'X') + call register_axis(dust12m_restart, 'lat', 'Y') + call register_axis(dust12m_restart, 'time', 12) + !--- register the 3D fields + do num = 1,nvar_dust12m + var3_p2 => dust12m_var(:,:,:,num) + call register_restart_field(dust12m_restart, dust12m_name(num), var3_p2, dimensions=(/'time', 'lat ', 'lon '/),& + &is_optional=.not.mand) + enddo + nullify(var3_p2) + endif + + !--- read new GSL created dust12m restart/data + call mpp_error(NOTE,'reading dust12m information from INPUT/dust12m_data.tile*.nc') + call read_restart(dust12m_restart) + call close_file(dust12m_restart) + + do nb = 1, Atm_block%nblks + !--- 3D variables + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - isc + 1 + j = Atm_block%index(nb)%jj(ix) - jsc + 1 + do k = 1, 12 + Sfcprop(nb)%dust12m_in(ix,k,1) = dust12m_var(i,j,k,1) + Sfcprop(nb)%dust12m_in(ix,k,2) = dust12m_var(i,j,k,2) + Sfcprop(nb)%dust12m_in(ix,k,3) = dust12m_var(i,j,k,3) + Sfcprop(nb)%dust12m_in(ix,k,4) = dust12m_var(i,j,k,4) + Sfcprop(nb)%dust12m_in(ix,k,5) = dust12m_var(i,j,k,5) + enddo + enddo + enddo + + deallocate(dust12m_name,dust12m_var) + + !--- open anthropogenic emission file + infile=trim(indir)//'/'//trim(fn_emi) + amiopen=open_file(emi_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file'//trim(infile) ) + + if (.not. allocated(emi_name)) then + !--- allocate the various containers needed for anthropogenic emission data + allocate(emi_name(nvar_emi)) + allocate(emi_var(nx,ny,nvar_emi)) + + emi_name(1) = 'e_oc' + !--- register axis + call register_axis( emi_restart, "grid_xt", 'X' ) + call register_axis( emi_restart, "grid_yt", 'Y' ) + !--- register the 2D fields + do num = 1,nvar_emi + var2_p => emi_var(:,:,num) + call register_restart_field(emi_restart, emi_name(num), var2_p, dimensions=(/'grid_yt','grid_xt'/)) + enddo + nullify(var2_p) + endif + + !--- read new GSL created emi restart/data + call mpp_error(NOTE,'reading emi information from INPUT/emi_data.tile*.nc') + call read_restart(emi_restart) + call close_file(emi_restart) + + do nb = 1, Atm_block%nblks + !--- 2D variables + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - isc + 1 + j = Atm_block%index(nb)%jj(ix) - jsc + 1 + Sfcprop(nb)%emi_in(ix,1) = emi_var(i,j,1) + enddo + enddo + + !--- deallocate containers and free restart container + deallocate(emi_name, emi_var) + + !--- Dust input FILE + !--- open file + infile=trim(indir)//'/'//trim(fn_gbbepx) + amiopen=open_file(gbbepx_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file'//trim(infile) ) + + if (.not. allocated(gbbepx_name)) then + !--- allocate the various containers needed for gbbepx fire data + allocate(gbbepx_name(nvar_gbbepx)) + allocate(gbbepx_var(nx,ny,24,nvar_gbbepx)) + + gbbepx_name(1) = 'ebb_smoke_hr' + gbbepx_name(2) = 'frp_avg_hr' + gbbepx_name(3) = 'frp_std_hr' + + !--- register axis + call register_axis(gbbepx_restart, 'lon', 'X') + call register_axis(gbbepx_restart, 'lat', 'Y') + call register_axis(gbbepx_restart, 't', 24) + !--- register the 3D fields + mand = .false. + do num = 1,nvar_gbbepx + var3_p2 => gbbepx_var(:,:,:,num) + call register_restart_field(gbbepx_restart, gbbepx_name(num), var3_p2, dimensions=(/'t ', 'lat', 'lon'/),& + &is_optional=.not.mand) + enddo + nullify(var3_p2) + endif + + !--- read new GSL created gbbepx restart/data + call mpp_error(NOTE,'reading gbbepx information from INPUT/SMOKE_GBBEPx_data.nc') + call read_restart(gbbepx_restart) + call close_file(gbbepx_restart) + + do nb = 1, Atm_block%nblks + !--- 3D variables + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - isc + 1 + j = Atm_block%index(nb)%jj(ix) - jsc + 1 + !--- assign hprime(1:10) and hprime(15:24) with new oro stat data + do k = 1, 24 + Sfcprop(nb)%smoke_GBBEPx(ix,k,1) = gbbepx_var(i,j,k,1) + Sfcprop(nb)%smoke_GBBEPx(ix,k,2) = gbbepx_var(i,j,k,2) + Sfcprop(nb)%smoke_GBBEPx(ix,k,3) = gbbepx_var(i,j,k,3) + enddo + enddo + enddo + + deallocate(gbbepx_name, gbbepx_var) + endif if_smoke ! RRFS_Smoke + !--- Modify/read-in additional orographic static fields for GSL drag suite if (Model%gwd_opt==3 .or. Model%gwd_opt==33 .or. & Model%gwd_opt==2 .or. Model%gwd_opt==22 ) then