diff --git a/ccpp/data/GFS_typedefs.F90 b/ccpp/data/GFS_typedefs.F90 index 9e1b6b728..0d12073cb 100644 --- a/ccpp/data/GFS_typedefs.F90 +++ b/ccpp/data/GFS_typedefs.F90 @@ -337,6 +337,9 @@ module GFS_typedefs ! -- In/Out for Noah MP real (kind=kind_phys), pointer :: snowxy (:) => null() !< + real (kind=kind_phys), pointer :: dzsno (:) => null() !< + real (kind=kind_phys), pointer :: dzsnso (:) => null() !< + real (kind=kind_phys), pointer :: tvxy (:) => null() !< veg temp real (kind=kind_phys), pointer :: tgxy (:) => null() !< ground temp real (kind=kind_phys), pointer :: canicexy(:) => null() !< @@ -2671,6 +2674,10 @@ subroutine sfcprop_create (Sfcprop, Model) if (Model%lsm == Model%lsm_noahmp ) then allocate (Sfcprop%snowxy (IM)) + + allocate (Sfcprop%dzsno (Model%lsnow_lsm_lbound:Model%lsnow_lsm_ubound)) + allocate (Sfcprop%dzsnso (Model%lsnow_lsm_lbound:Model%lsoil_lsm)) + allocate (Sfcprop%tvxy (IM)) allocate (Sfcprop%tgxy (IM)) allocate (Sfcprop%canicexy (IM)) @@ -2704,7 +2711,12 @@ subroutine sfcprop_create (Sfcprop, Model) allocate (Sfcprop%smoiseq (IM, Model%lsoil_lsm)) allocate (Sfcprop%zsnsoxy (IM, Model%lsnow_lsm_lbound:Model%lsoil_lsm)) + Sfcprop%snowxy = clear_val + + Sfcprop%dzsno = clear_val + Sfcprop%dzsnso = clear_val + Sfcprop%tvxy = clear_val Sfcprop%tgxy = clear_val Sfcprop%canicexy = clear_val diff --git a/ccpp/data/GFS_typedefs.meta b/ccpp/data/GFS_typedefs.meta index 7140c187d..162aeaa4a 100644 --- a/ccpp/data/GFS_typedefs.meta +++ b/ccpp/data/GFS_typedefs.meta @@ -1511,6 +1511,14 @@ type = real kind = kind_phys active = (control_for_land_surface_scheme == identifier_for_noahmp_land_surface_scheme) +[dzsno] + standard_name = thickness_of_snow_layers + long_name = thickness of snow layers + units = m + dimensions = (lower_bound_of_vertical_dimension_of_surface_snow:0) + type = real + kind = kind_phys + active = (control_for_land_surface_scheme == identifier_for_noahmp_land_surface_scheme) [tvxy] standard_name = canopy_temperature long_name = vegetation temperature @@ -1655,6 +1663,14 @@ type = real kind = kind_phys active = (control_for_land_surface_scheme == identifier_for_noahmp_land_surface_scheme) +[dzsnso] + standard_name = thickness_snow_soil_layers + long_name = thickness of snow and soil layers + units = m + dimensions = (lower_bound_of_vertical_dimension_of_surface_snow:vertical_dimension_of_soil_internal_to_land_surface_scheme) + type = real + kind = kind_phys + active = (control_for_land_surface_scheme == identifier_for_noahmp_land_surface_scheme) [snicexy] standard_name = lwe_thickness_of_ice_in_surface_snow long_name = snow layer ice diff --git a/fv3/moving_nest/fv_moving_nest_physics.F90 b/fv3/moving_nest/fv_moving_nest_physics.F90 index e90ee5bc0..b773edbe5 100644 --- a/fv3/moving_nest/fv_moving_nest_physics.F90 +++ b/fv3/moving_nest/fv_moving_nest_physics.F90 @@ -529,11 +529,22 @@ subroutine mn_phys_apply_temp_variables(Atm, Atm_block, GFS_control, GFS_sfcprop integer :: is, ie, js, je integer :: this_pe integer :: nb, blen, i, j ,k, ix, nv, im + integer :: isnow + + real(kind=kind_phys) :: dzs(1:4) + real(kind=kind_phys) :: porosity(1:19) + + type(fv_moving_nest_physics_type), pointer :: mn_phys this_pe = mpp_pe() mn_phys => Moving_nest(n)%mn_phys + dzs = (/0.1,0.3,0.6,1.0/) ! 4 layer soil thickness + porosity = (/0.339,0.421,0.434,0.476,0.484,0.439,0.404,0.464, & + 0.465,0.406,0.468,0.468,0.439,1.000,0.200,0.421, & + 0.468,0.200,0.339/) + ! Needed to fill the local grids for parent and nest PEs in order to transmit/interpolate data from parent to nest ! But only the nest PE's have changed the values with nest motion, so they are the only ones that need to update the original arrays if (is_fine_pe) then @@ -705,8 +716,7 @@ subroutine mn_phys_apply_temp_variables(Atm, Atm_block, GFS_control, GFS_sfcprop if (GFS_control%lsm == GFS_control%lsm_noahmp) then - GFS_sfcprop%scolor(im) = mn_phys%soilcolor(i,j) - GFS_sfcprop%snowxy(im) = mn_phys%snowxy(i,j) + GFS_sfcprop%scolor(im) = mn_phys%soilcolor(i,j) GFS_sfcprop%tvxy(im) = mn_phys%tvxy(i,j) GFS_sfcprop%tgxy(im) = mn_phys%tgxy(i,j) GFS_sfcprop%canicexy(im) = mn_phys%canicexy(i,j) @@ -735,26 +745,115 @@ subroutine mn_phys_apply_temp_variables(Atm, Atm_block, GFS_control, GFS_sfcprop GFS_sfcprop%smcwtdxy(im) = mn_phys%smcwtdxy(i,j) GFS_sfcprop%deeprechxy(im) = mn_phys%deeprechxy(i,j) GFS_sfcprop%rechxy(im) = mn_phys%rechxy(i,j) + GFS_sfcprop%snowxy(im) = mn_phys%snowxy(i,j) do k = 1, GFS_control%lsoil GFS_sfcprop%smoiseq(im,k) = mn_phys%smoiseq(i,j,k) enddo + isnow = nint(GFS_sfcprop%snowxy(im)) + 1 - do k = GFS_control%lsnow_lsm_lbound, GFS_control%lsnow_lsm_ubound - GFS_sfcprop%snicexy(im,k) = mn_phys%snicexy(i,j,k) - GFS_sfcprop%snliqxy(im,k) = mn_phys%snliqxy(i,j,k) - GFS_sfcprop%tsnoxy(im,k) = mn_phys%tsnoxy(i,j,k) + do k = isnow, 0 + GFS_sfcprop%tsnoxy(im,k) = mn_phys%tsnoxy(i,j,k) + GFS_sfcprop%snicexy(im,k) = mn_phys%snicexy(i,j,k) + GFS_sfcprop%snliqxy(im,k) = mn_phys%snliqxy(i,j,k) enddo - GFS_sfcprop%snowd(im) = mn_phys%snowd(i,j) - GFS_sfcprop%weasd(im) = mn_phys%weasd(i,j) + do k = isnow, GFS_control%lsoil + GFS_sfcprop%zsnsoxy(im,k) = mn_phys%zsnsoxy(i,j,k) + enddo + + + ! soil moisture check against uplimit porosity when Noah MP LSM is used - do k = GFS_control%lsnow_lsm_lbound, GFS_control%lsoil - GFS_sfcprop%zsnsoxy(im,k) = mn_phys%zsnsoxy(i,j,k) + do k = 1, GFS_control%lsoil + GFS_sfcprop%smc(im,k) = min(GFS_sfcprop%smc(im,k),porosity(GFS_sfcprop%stype(im))-0.01) + GFS_sfcprop%slc(im,k) = min(GFS_sfcprop%slc(im,k),porosity(GFS_sfcprop%stype(im))-0.01) enddo + ! use snowd and weasd to set snow related variables, and set soil related quantities over land ice + ! (snowd is set to 2 meters and weasd is 600 mm), snow layers may be different around a new land point. + ! can't do average, the nearest point method is not spported yet. + ! check to see if smoiseq needs to be set. + + GFS_sfcprop%snowd(im) = mn_phys%snowd(i,j) + GFS_sfcprop%weasd(im) = mn_phys%weasd(i,j) + + if (int(GFS_sfcprop%vtype(im)) == 15) then ! set stc,smc,slc over glaceir ice + do k = 1,GFS_control%lsoil + GFS_sfcprop%stc(im,k) = min(mn_phys%stc(i,j,k),min(GFS_Sfcprop%tg3(im),263.15)) + GFS_sfcprop%smc(im,k) = 1.0 + GFS_sfcprop%slc(im,k) = 0.0 + enddo + GFS_sfcprop%weasd(im) = 600.0 ! 600mm SWE for glacier + GFS_sfcprop%snowd(im) = 2000.0 ! 2m snow depth for glacier, snowd/snwdph is in mm + endif + + if (GFS_sfcprop%snowd(im) == 0.0 .and. GFS_sfcprop%weasd(im) /= 0.0 ) then ! use weasd to set snowd, in case + GFS_sfcprop%snowd(im) = GFS_sfcprop%weasd(im)/10.0 !snowd is snwdph in mm. divide by 10. + endif + + if (mn_phys%leading_edge(i,j)) then ! reset Noah MP snow fields on new land points only + + if (GFS_sfcprop%snowd(im)/1000.0 < 0.025) then + GFS_sfcprop%snowxy(im) = 0 + GFS_sfcprop%dzsno(-2:0) = 0.0 + elseif (GFS_sfcprop%snowd(im)/1000.0 >= 0.025 .and. GFS_sfcprop%snowd(im)/1000.0 <= 0.05 ) then + GFS_sfcprop%snowxy(im) = -1.0 + GFS_sfcprop%dzsno(0) = GFS_sfcprop%snowd(im)/1000.0 + elseif (GFS_sfcprop%snowd(im)/1000.0 > 0.05 .and. GFS_sfcprop%snowd(im)/1000.0 <= 0.10 ) then + GFS_sfcprop%snowxy(im) = -2.0 + GFS_sfcprop%dzsno(-1) = 0.5*GFS_sfcprop%snowd(im)/1000.0 + GFS_sfcprop%dzsno(0) = 0.5*GFS_sfcprop%snowd(im)/1000.0 + elseif (GFS_sfcprop%snowd(im) /1000.0> 0.10 .and. GFS_sfcprop%snowd(im) /1000.0<= 0.25 ) then + GFS_sfcprop%snowxy(im) = -2.0 + GFS_sfcprop%dzsno(-1) = 0.05 + GFS_sfcprop%dzsno(0) = GFS_sfcprop%snowd(im)/1000.0- 0.05 + elseif (GFS_sfcprop%snowd(im)/1000.0 > 0.25 .and. GFS_sfcprop%snowd(im)/1000.0 <= 0.45 ) then + GFS_sfcprop%snowxy(im) = -3.0 + GFS_sfcprop%dzsno(-2) = 0.05 + GFS_sfcprop%dzsno(-1) = 0.5*(GFS_sfcprop%snowd(im)/1000.0-0.05) + GFS_sfcprop%dzsno(0) = 0.5*(GFS_sfcprop%snowd(im)/1000.0-0.05) + elseif (GFS_sfcprop%snowd(im)/1000.0 > 0.45) then + GFS_sfcprop%snowxy(im) = -3.0 + GFS_sfcprop%dzsno(-2) = 0.05 + GFS_sfcprop%dzsno(-1) = 0.20 + GFS_sfcprop%dzsno(0) = GFS_sfcprop%snowd(im)/1000.0 - 0.05 - 0.20 + else + write(*,*) 'Error in fv_moving_nest_physics.F90 Problem with the logic assigning snow layers ' + stop + + endif + + isnow = nint(GFS_sfcprop%snowxy(im)) + 1 ! new snow layers at new land points + + do k = isnow, 0 + + GFS_sfcprop%tsnoxy(im,k) = GFS_sfcprop%tgxy(im) + (( sum(GFS_sfcprop%dzsno(isnow:k)) - \ + 0.5*GFS_sfcprop%dzsno(k) )/ GFS_sfcprop%snowd(im)/1000.0)*( GFS_sfcprop%stc(im,1)- GFS_sfcprop%tgxy(im)) + + GFS_sfcprop%snliqxy(im,k) = 0.0 + GFS_sfcprop%snicexy(im,k) = 1.0 * GFS_sfcprop%dzsno(k) * GFS_sfcprop%weasd(im)/GFS_sfcprop%snowd(im) + + enddo + + + do k = isnow, 0 + GFS_sfcprop%dzsnso(k) = -GFS_sfcprop%dzsno(k) + enddo + + do k = 1, 4 + GFS_sfcprop%dzsnso(k) = -dzs(k) + enddo + + GFS_sfcprop%zsnsoxy(im,isnow) = GFS_sfcprop%dzsnso(isnow) + + do k = isnow + 1, GFS_control%lsoil + GFS_sfcprop%zsnsoxy(im, k) = GFS_sfcprop%zsnsoxy(im,k-1) + GFS_sfcprop%dzsnso(k) + enddo + endif + endif ! Check if stype and vtype are properly set for land points. Set to reasonable values if they have fill values. if ( (int(GFS_sfcprop%slmsk(im)) .eq. 1) ) then @@ -775,8 +874,10 @@ subroutine mn_phys_apply_temp_variables(Atm, Atm_block, GFS_control, GFS_sfcprop endif endif + enddo enddo + endif end subroutine mn_phys_apply_temp_variables @@ -1643,8 +1744,6 @@ subroutine mn_phys_shift_data(Atm, GFS_control, n, child_grid_num, wt_h, wt_u, w delta_i_c, delta_j_c, x_refine, y_refine, is_fine_pe, nest_domain, position) call mn_var_shift_data(mn_phys%smoiseq, interp_type, wt_h, Atm(child_grid_num)%neststruct%ind_h, & delta_i_c, delta_j_c, x_refine, y_refine, is_fine_pe, nest_domain, position, GFS_control%lsoil) - - call mn_var_shift_data(mn_phys%snicexy, interp_type, wt_h, Atm(child_grid_num)%neststruct%ind_h, & delta_i_c, delta_j_c, x_refine, y_refine, is_fine_pe, nest_domain, position, GFS_control%lsnow_lsm_lbound, GFS_control%lsnow_lsm_ubound) call mn_var_shift_data(mn_phys%snliqxy, interp_type, wt_h, Atm(child_grid_num)%neststruct%ind_h, & diff --git a/fv3/moving_nest/fv_moving_nest_types.F90 b/fv3/moving_nest/fv_moving_nest_types.F90 index 9e33aff13..035d11472 100644 --- a/fv3/moving_nest/fv_moving_nest_types.F90 +++ b/fv3/moving_nest/fv_moving_nest_types.F90 @@ -235,6 +235,10 @@ module fv_moving_nest_types_mod ! NOAH MP LSM Variables real (kind=kind_phys), _ALLOCATABLE :: soilcolor (:,:) _NULL !< soil color real (kind=kind_phys), _ALLOCATABLE :: snowxy (:,:) _NULL !< number of snow layers + + real (kind=kind_phys), _ALLOCATABLE :: dzsno (:) _NULL !< number of snow layers + real (kind=kind_phys), _ALLOCATABLE :: dzsnso (:) _NULL !< number of snow layers + real (kind=kind_phys), _ALLOCATABLE :: tvxy (:,:) _NULL !< canopy temperature real (kind=kind_phys), _ALLOCATABLE :: tgxy (:,:) _NULL !< ground temperature real (kind=kind_phys), _ALLOCATABLE :: canicexy (:,:) _NULL !< canopy intercepted ice mass @@ -715,6 +719,10 @@ subroutine allocate_fv_moving_nest_physics_type(isd, ied, jsd, jed, npz, move_p if (move_noahmp) then allocate ( mn_phys%soilcolor(isd:ied, jsd:jed) ) allocate ( mn_phys%snowxy(isd:ied, jsd:jed) ) + + allocate ( mn_phys%dzsno(lsnow_lbound:lsnow_ubound) ) + allocate ( mn_phys%dzsnso(lsnow_lbound:lsoil) ) + allocate ( mn_phys%tvxy(isd:ied, jsd:jed) ) allocate ( mn_phys%tgxy(isd:ied, jsd:jed) ) allocate ( mn_phys%canicexy(isd:ied, jsd:jed) ) @@ -848,6 +856,10 @@ subroutine allocate_fv_moving_nest_physics_type(isd, ied, jsd, jed, npz, move_p if (move_noahmp) then mn_phys%soilcolor = +99999.9 mn_phys%snowxy = +99999.9 + + mn_phys%dzsno = +99999.9 + mn_phys%dzsnso = +99999.9 + mn_phys%tvxy = +99999.9 mn_phys%tgxy = +99999.9 mn_phys%canicexy = +99999.9 @@ -993,6 +1005,10 @@ subroutine deallocate_fv_moving_nest_physics_type(mn_phys) if (allocated(mn_phys%snowxy)) then deallocate ( mn_phys%soilcolor ) deallocate ( mn_phys%snowxy ) + + deallocate ( mn_phys%dzsno ) + deallocate ( mn_phys%dzsnso ) + deallocate ( mn_phys%tvxy ) deallocate ( mn_phys%tgxy ) deallocate ( mn_phys%canicexy )