diff --git a/.gitmodules b/.gitmodules index 22c723ac1..75152781f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,8 +8,8 @@ branch = main [submodule "ccpp/physics"] path = ccpp/physics - url = https://github.com/ufs-community/ccpp-physics - branch = ufs/dev + url = https://github.com/esmf-org/ccpp-physics + branch = feature/ufs_fire_cpl [submodule "upp"] path = upp url = https://github.com/NOAA-EMC/UPP diff --git a/atmos_model.F90 b/atmos_model.F90 index 92fa59742..083095f47 100644 --- a/atmos_model.F90 +++ b/atmos_model.F90 @@ -3091,6 +3091,51 @@ subroutine assign_importdata(jdat, rc) endif endif + fldname = 'hflx_fire' + if (trim(impfield_name) == trim(fldname)) then + findex = queryImportFields(fldname) + if (importFieldsValid(findex)) then +!$omp parallel do default(shared) private(i,j,nb,ix) + do j=jsc,jec + do i=isc,iec + nb = Atm_block%blkno(i,j) + ix = Atm_block%ixp(i,j) + GFS_data(nb)%Sfcprop%hflx_fire(ix) = datar82d(i-isc+1,j-jsc+1) + enddo + enddo + endif + endif + + fldname = 'evap_fire' + if (trim(impfield_name) == trim(fldname)) then + findex = queryImportFields(fldname) + if (importFieldsValid(findex)) then +!$omp parallel do default(shared) private(i,j,nb,ix) + do j=jsc,jec + do i=isc,iec + nb = Atm_block%blkno(i,j) + ix = Atm_block%ixp(i,j) + GFS_data(nb)%Sfcprop%evap_fire(ix) = datar82d(i-isc+1,j-jsc+1) + enddo + enddo + endif + endif + + fldname = 'smoke_fire' + if (trim(impfield_name) == trim(fldname)) then + findex = queryImportFields(fldname) + if (importFieldsValid(findex)) then +!$omp parallel do default(shared) private(i,j,nb,ix) + do j=jsc,jec + do i=isc,iec + nb = Atm_block%blkno(i,j) + ix = Atm_block%ixp(i,j) + GFS_data(nb)%Sfcprop%smoke_fire(ix) = datar82d(i-isc+1,j-jsc+1) + enddo + enddo + endif + endif + ! write post merge import data to NetCDF file. if (GFS_control%cpl_imp_dbg) then call ESMF_FieldGet(importFields(n), grid=grid, rc=rc) @@ -3280,6 +3325,21 @@ subroutine setup_exportdata(rc) do nb = 1, Atm_block%nblks select case (trim(fieldname)) !--- Instantaneous quantities + ! Instantaneous mean layer pressure (Pa) + case ('inst_pres_levels') + call block_data_copy_or_fill(datar83d, GFS_data(nb)%Statein%prsl, zeror8, Atm_block, nb, rc=localrc) + ! Instantaneous geopotential at model layer centers (m2 s-2) + case ('inst_geop_levels') + call block_data_copy_or_fill(datar83d, GFS_data(nb)%Statein%phil, zeror8, Atm_block, nb, rc=localrc) + ! Instantaneous zonal wind (m s-1) + case ('inst_zonal_wind_levels') + call block_data_copy_or_fill(datar83d, GFS_data(nb)%Statein%ugrs, zeror8, Atm_block, nb, rc=localrc) + ! Instantaneous meridional wind (m s-1) + case ('inst_merid_wind_levels') + call block_data_copy_or_fill(datar83d, GFS_data(nb)%Statein%vgrs, zeror8, Atm_block, nb, rc=localrc) + ! Instantaneous surface roughness length (cm) + case ('inst_surface_roughness') + call block_data_copy(datar82d, GFS_data(nb)%sfcprop%zorl, Atm_block, nb, rc=localrc) ! Instantaneous u wind (m/s) 10 m above ground case ('inst_zonal_wind_height10m') call block_data_copy(datar82d, GFS_data(nb)%coupling%u10mi_cpl, Atm_block, nb, rc=localrc) @@ -3364,6 +3424,9 @@ subroutine setup_exportdata(rc) ! Land/Sea mask (sea:0,land:1) case ('inst_land_sea_mask', 'slmsk') call block_data_copy(datar82d, GFS_data(nb)%sfcprop%slmsk, Atm_block, nb, rc=localrc) + ! Total precipitation amount in each time step + case ('inst_rainfall_amount') + call block_data_copy(datar82d, GFS_data(nb)%sfcprop%tprcp, Atm_block, nb, rc=localrc) !--- Mean quantities ! MEAN Zonal compt of momentum flux (N/m**2) case ('mean_zonal_moment_flx_atm') @@ -3416,6 +3479,15 @@ subroutine setup_exportdata(rc) ! MEAN NET sfc uv+vis diffused flux (W/m**2) case ('mean_net_sw_vis_dif_flx') call block_data_copy(datar82d, GFS_data(nb)%coupling%nvisdf_cpl, Atm_block, nb, rtime, spval, rc=localrc) + ! MEAN precipitation rate (kg/m2/s) + case ('mean_prec_rate') + call block_data_copy(datar82d, GFS_data(nb)%sfcprop%tprcp, Atm_block, nb, rtimek, spval, rc=localrc) + ! MEAN convective precipitation rate (kg/m2/s) + case ('mean_prec_rate_conv') + call block_data_copy(datar82d, GFS_Data(nb)%Coupling%rainc_cpl, Atm_block, nb, rtimek, spval, rc=localrc) + ! MEAN snow precipitation rate (kg/m2/s) + case ('mean_fprec_rate') + call block_data_copy(datar82d, GFS_data(nb)%coupling%snow_cpl, Atm_block, nb, rtimek, spval, rc=localrc) ! oceanfrac used by atm to calculate fluxes case ('openwater_frac_in_atm') call block_data_combine_fractions(datar82d, GFS_data(nb)%sfcprop%oceanfrac, GFS_Data(nb)%sfcprop%fice, Atm_block, nb, rc=localrc) diff --git a/ccpp/data/GFS_typedefs.F90 b/ccpp/data/GFS_typedefs.F90 index 40c33cfc5..96c963121 100644 --- a/ccpp/data/GFS_typedefs.F90 +++ b/ccpp/data/GFS_typedefs.F90 @@ -298,6 +298,11 @@ module GFS_typedefs real (kind=kind_phys), pointer :: hflx (:) => null() !< real (kind=kind_phys), pointer :: qss (:) => null() !< +!--- fire_behavior + real (kind=kind_phys), pointer :: hflx_fire (:) => null() !< kinematic surface upward sensible heat flux of fire + real (kind=kind_phys), pointer :: evap_fire (:) => null() !< kinematic surface upward latent heat flux of fire + real (kind=kind_phys), pointer :: smoke_fire (:) => null() !< smoke emission of fire + !-- In/Out real (kind=kind_phys), pointer :: maxupmf(:) => null() !< maximum up draft mass flux for Grell-Freitas real (kind=kind_phys), pointer :: conv_act(:) => null() !< convective activity counter for Grell-Freitas @@ -763,6 +768,7 @@ module GFS_typedefs logical :: cpllnd !< default no cpllnd collection logical :: cpllnd2atm !< default no lnd->atm coupling logical :: rrfs_sd !< default no rrfs_sd collection + logical :: cpl_fire !< default no fire_behavior 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 @@ -1478,6 +1484,7 @@ 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 :: ntfsmoke !< tracer index for fire smoke integer :: ntsmoke !< tracer index for smoke integer :: ntdust !< tracer index for dust integer :: ntcoarsepm !< tracer index for coarse PM @@ -2863,6 +2870,16 @@ subroutine sfcprop_create (Sfcprop, IM, Model) Sfcprop%lu_qfire = clear_val endif + !--- if fire_behavior is on + if(Model%cpl_fire) then + allocate (Sfcprop%hflx_fire (IM)) + allocate (Sfcprop%evap_fire (IM)) + allocate (Sfcprop%smoke_fire (IM)) + Sfcprop%hflx_fire = zero + Sfcprop%evap_fire = zero + Sfcprop%smoke_fire = zero + endif + end subroutine sfcprop_create @@ -2920,7 +2937,7 @@ subroutine coupling_create (Coupling, IM, Model) Coupling%tsfc_radtime = clear_val endif - if (Model%cplflx .or. Model%do_sppt .or. Model%cplchm .or. Model%ca_global .or. Model%cpllnd) then + if (Model%cplflx .or. Model%do_sppt .or. Model%cplchm .or. Model%ca_global .or. Model%cpllnd .or. Model%cpl_fire) then allocate (Coupling%rain_cpl (IM)) allocate (Coupling%snow_cpl (IM)) Coupling%rain_cpl = clear_val @@ -2949,7 +2966,7 @@ subroutine coupling_create (Coupling, IM, Model) ! Coupling%zorlwav_cpl = clear_val ! endif - if (Model%cplflx .or. Model%cpllnd) then + if (Model%cplflx .or. Model%cpllnd .or. Model%cpl_fire) then allocate (Coupling%dlwsfci_cpl (IM)) allocate (Coupling%dswsfci_cpl (IM)) allocate (Coupling%dlwsfc_cpl (IM)) @@ -2983,7 +3000,7 @@ subroutine coupling_create (Coupling, IM, Model) Coupling%nvisdf_cpl = clear_val end if - if (Model%cplflx) then + if (Model%cplflx .or. Model%cpl_fire) then !--- incoming quantities allocate (Coupling%slimskin_cpl (IM)) allocate (Coupling%dusfcin_cpl (IM)) @@ -3148,7 +3165,7 @@ subroutine coupling_create (Coupling, IM, Model) Coupling%pfl_lsan = clear_val endif - if (Model%cplchm .or. Model%cplflx .or. Model%cpllnd) then + if (Model%cplchm .or. Model%cplflx .or. Model%cpllnd .or. Model%cpl_fire) then !--- accumulated convective rainfall allocate (Coupling%rainc_cpl (IM)) Coupling%rainc_cpl = clear_val @@ -3356,6 +3373,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & logical :: cpllnd = .false. !< default no cpllnd collection logical :: cpllnd2atm = .false. !< default no cpllnd2atm coupling logical :: rrfs_sd = .false. !< default no rrfs_sd collection + logical :: cpl_fire = .false. !< default no fire behavior colleciton 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 @@ -3993,7 +4011,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !--- coupling parameters cplflx, cplice, cplocn2atm, cplwav, cplwav2atm, cplaqm, & cplchm, cpllnd, cpllnd2atm, cpl_imp_mrg, cpl_imp_dbg, & - rrfs_sd, use_cice_alb, & + cpl_fire, rrfs_sd, use_cice_alb, & #ifdef IDEA_PHYS lsidea, weimer_model, f107_kp_size, f107_kp_interval, & f107_kp_skip_size, f107_kp_data_size, f107_kp_read_in_start, & @@ -4351,6 +4369,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !--- RRFS-SD Model%rrfs_sd = rrfs_sd + Model%cpl_fire = cpl_fire Model%dust_drylimit_factor = dust_drylimit_factor Model%dust_moist_correction = dust_moist_correction Model%dust_moist_opt = dust_moist_opt @@ -5171,12 +5190,14 @@ 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) + if (Model%cpl_fire) then + Model%ntfsmoke = get_tracer_index(Model%tracer_names, 'fsmoke', Model%me, Model%master, Model%debug) + endif if (Model%rrfs_sd) then 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) Model%ntcoarsepm = get_tracer_index(Model%tracer_names, 'coarsepm', Model%me, Model%master, Model%debug) endif - !--- initialize parameters for atmospheric chemistry tracers call Model%init_chemistry(tracer_types) @@ -6471,6 +6492,7 @@ subroutine control_print(Model) print *, ' cpllnd : ', Model%cpllnd print *, ' cpllnd2atm : ', Model%cpllnd2atm print *, ' rrfs_sd : ', Model%rrfs_sd + print *, ' cpl_fire : ', Model%cpl_fire print *, ' use_cice_alb : ', Model%use_cice_alb print *, ' cpl_imp_mrg : ', Model%cpl_imp_mrg print *, ' cpl_imp_dbg : ', Model%cpl_imp_dbg @@ -6939,6 +6961,7 @@ subroutine control_print(Model) print *, ' nto2 : ', Model%nto2 print *, ' ntwa : ', Model%ntwa print *, ' ntia : ', Model%ntia + print *, ' ntfsmoke : ', Model%ntfsmoke print *, ' ntsmoke : ', Model%ntsmoke print *, ' ntdust : ', Model%ntdust print *, ' ntcoarsepm : ', Model%ntcoarsepm diff --git a/ccpp/data/GFS_typedefs.meta b/ccpp/data/GFS_typedefs.meta index 5ac00e403..38ff8d7be 100644 --- a/ccpp/data/GFS_typedefs.meta +++ b/ccpp/data/GFS_typedefs.meta @@ -2362,6 +2362,30 @@ type = real kind = kind_phys active = (do_smoke_coupling) +[hflx_fire] + standard_name = kinematic_surface_upward_sensible_heat_flux_of_fire + long_name = kinematic surface upward sensible heat flux of fire + units = K m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (do_fire_coupling) +[evap_fire] + standard_name = surface_upward_specific_humidity_flux_of_fire + long_name = kinematic surface upward latent heat flux of fire + units = kg kg-1 m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (do_fire_coupling) +[smoke_fire] + standard_name = smoke_emission_of_fire + long_name = smoke emission of fire + units = kg m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + active = (do_fire_coupling) ######################################################################## [ccpp-table-properties] @@ -2471,7 +2495,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (flag_for_surface_flux_coupling .or. flag_for_chemistry_coupling .or. flag_for_land_coupling) + active = (flag_for_surface_flux_coupling .or. flag_for_chemistry_coupling .or. flag_for_land_coupling .or. do_fire_coupling) [snow_cpl] standard_name = cumulative_lwe_thickness_of_snow_amount_for_coupling long_name = total snow precipitation @@ -2479,7 +2503,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (flag_for_surface_flux_coupling .or. flag_for_stochastic_physics_perturbations .or. flag_for_chemistry_coupling .or. flag_for_global_cellular_automata .or. flag_for_land_coupling) + active = (flag_for_surface_flux_coupling .or. flag_for_stochastic_physics_perturbations .or. flag_for_chemistry_coupling .or. flag_for_global_cellular_automata .or. flag_for_land_coupling .or. do_fire_coupling) [dusfc_cpl] standard_name = cumulative_surface_x_momentum_flux_for_coupling_multiplied_by_timestep long_name = cumulative sfc x momentum flux multiplied by timestep @@ -2743,7 +2767,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (flag_for_surface_flux_coupling .or. flag_for_air_quality_coupling) + active = (flag_for_surface_flux_coupling .or. flag_for_air_quality_coupling .or. do_fire_coupling) [q2mi_cpl] standard_name = specific_humidity_at_2m_for_coupling long_name = instantaneous Q2m @@ -2751,7 +2775,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (flag_for_surface_flux_coupling .or. flag_for_air_quality_coupling) + active = (flag_for_surface_flux_coupling .or. flag_for_air_quality_coupling .or. do_fire_coupling) [u10mi_cpl] standard_name = x_wind_at_10m_for_coupling long_name = instantaneous U10m @@ -2783,7 +2807,7 @@ dimensions = (horizontal_loop_extent) type = real kind = kind_phys - active = (flag_for_surface_flux_coupling .or. flag_for_air_quality_coupling .or. flag_for_land_coupling) + active = (flag_for_surface_flux_coupling .or. flag_for_air_quality_coupling .or. flag_for_land_coupling .or. do_fire_coupling) [ulwsfcin_cpl] standard_name = surface_upwelling_longwave_flux_from_coupled_process long_name = surface upwelling LW flux for coupling @@ -3603,6 +3627,12 @@ units = flag dimensions = () type = logical +[cpl_fire] + standard_name = do_fire_coupling + long_name = flag controlling fire_behavior 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) @@ -6499,6 +6529,12 @@ units = index dimensions = () type = integer +[ntfsmoke] + standard_name = index_for_fire_smoke_in_tracer_concentration_array + long_name = tracer index for fire smoke + units = index + dimensions = () + type = integer [ntdust] standard_name = index_for_dust_in_tracer_concentration_array long_name = tracer index for dust diff --git a/ccpp/driver/GFS_diagnostics.F90 b/ccpp/driver/GFS_diagnostics.F90 index 68f89ae89..874bf6feb 100644 --- a/ccpp/driver/GFS_diagnostics.F90 +++ b/ccpp/driver/GFS_diagnostics.F90 @@ -4654,6 +4654,19 @@ subroutine GFS_externaldiag_populate (ExtDiag, Model, Statein, Stateout, Sfcprop enddo end if thompson_extended_diagnostics + if (Model%cpl_fire .and. Model%ntfsmoke>0) then + idx = idx + 1 + ExtDiag(idx)%axes = 3 + ExtDiag(idx)%name = 'fsmoke' + ExtDiag(idx)%desc = 'smoke concentration' + ExtDiag(idx)%unit = 'kg kg-1' + ExtDiag(idx)%mod_name = 'gfs_phys' + allocate (ExtDiag(idx)%data(nblks)) + do nb = 1,nblks + ExtDiag(idx)%data(nb)%var3 => Statein(nb)%qgrs(:,:,Model%ntfsmoke) + enddo + endif + if (Model%rrfs_sd .and. Model%ntsmoke>0) then idx = idx + 1 diff --git a/ccpp/physics b/ccpp/physics index 16a1d8817..fad3fa436 160000 --- a/ccpp/physics +++ b/ccpp/physics @@ -1 +1 @@ -Subproject commit 16a1d881774d795f46db16017aeed7fc351d661a +Subproject commit fad3fa4363befa88242a0fa5dffa8042aff69723 diff --git a/cpl/module_cplfields.F90 b/cpl/module_cplfields.F90 index 524db0208..5266807a5 100644 --- a/cpl/module_cplfields.F90 +++ b/cpl/module_cplfields.F90 @@ -26,7 +26,7 @@ module module_cplfields ! l : model levels (3D) ! s : surface (2D) ! t : tracers (4D) - integer, public, parameter :: NexportFields = 120 + integer, public, parameter :: NexportFields = 121 type(ESMF_Field), target, public :: exportFields(NexportFields) type(FieldInfo), dimension(NexportFields), public, parameter :: exportFieldsInfo = [ & @@ -64,6 +64,7 @@ module module_cplfields FieldInfo("mean_evap_rate ", "s"), & FieldInfo("mean_down_lw_flx ", "s"), & FieldInfo("mean_down_sw_flx ", "s"), & + FieldInfo("mean_prec_rate ", "s"), & FieldInfo("inst_prec_rate ", "s"), & FieldInfo("inst_zonal_moment_flx ", "s"), & FieldInfo("inst_merid_moment_flx ", "s"), & @@ -157,7 +158,7 @@ module module_cplfields FieldInfo("cpl_scalars ", "s")] ! Import Fields ---------------------------------------- - integer, public, parameter :: NimportFields = 64 + integer, public, parameter :: NimportFields = 67 logical, public :: importFieldsValid(NimportFields) type(ESMF_Field), target, public :: importFields(NimportFields) @@ -233,7 +234,12 @@ module module_cplfields FieldInfo("snwdph ", "s"), & FieldInfo("f10m ", "s"), & FieldInfo("zorl ", "s"), & - FieldInfo("t2m ", "s") ] + FieldInfo("t2m ", "s"), & + + ! For FIRE + FieldInfo("hflx_fire ", "s"), & + FieldInfo("evap_fire ", "s"), & + FieldInfo("smoke_fire ", "s") ] ! Fields exported exclusively for coupling with chemistry character(*), public, parameter :: chemistryFieldNames(*) = [ &