From c56c4781f83501b0c6bf047d5f7dd8ddf691b072 Mon Sep 17 00:00:00 2001 From: julietbravo Date: Thu, 2 Jul 2020 12:13:05 +0200 Subject: [PATCH] Working tiled surface layer solver --- src/modlsm.f90 | 96 ++++++++++++++++++++++++++++++++++++++++++--- src/modstartup.f90 | 4 ++ src/modtimestat.f90 | 87 +++++++++++++++++++++++++++++++--------- 3 files changed, 162 insertions(+), 25 deletions(-) diff --git a/src/modlsm.f90 b/src/modlsm.f90 index 917a09c8..265262f2 100644 --- a/src/modlsm.f90 +++ b/src/modlsm.f90 @@ -40,10 +40,15 @@ module modlsm ! Precipitation interception et al. real, allocatable :: throughfall(:,:) + ! Random + real, allocatable :: du_tot(:,:), thv_1(:,:) + ! Data structure for sub-grid tiles type lsm_tile ! Static properties: real, allocatable :: z0m(:,:), z0h(:,:) + ! Base tile fraction (i.e. without liquid water) + real, allocatable :: base_frac(:,:) ! Dynamic tile fraction: real, allocatable :: frac(:,:) ! Monin-obukhov / surface layer: @@ -81,8 +86,8 @@ subroutine lsm implicit none ! tmp... - thlflux(:,:) = 0. - qtflux(:,:) = 0. + thlflux(:,:) = 0.1 + qtflux(:,:) = 0.1e-3 G0(:,:) = 0. phiw_source(:,:,:) = 0. throughfall(:,:) = 0. @@ -95,8 +100,6 @@ subroutine lsm call stability - - ! ! 2. Calculate soil tendencies ! @@ -116,13 +119,71 @@ subroutine lsm end subroutine lsm ! -! Calculate Obukhov length, ustar, .. for all tiles +! Calculate Obukhov length, ustar, and aerodynamic resistance, for all tiles ! subroutine stability + use modglobal, only : i1, j1, cu, cv, rv, rd + use modfields, only : u0, v0, thl0, qt0 implicit none + real :: du, dv + integer :: i, j + real, parameter :: du_min = 0.1 + + ! Calculate properties shared by all tiles: + ! Absolute wind speed difference, and virtual potential temperature atmosphere + do j=2,j1 + do i=2,i1 + du = 0.5*(u0(i,j,1) + u0(i+1,j,1)) + cu + dv = 0.5*(v0(i,j,1) + v0(i,j+1,1)) + cv + du_tot(i,j) = sqrt(du**2 + dv**2) + + thv_1(i,j) = thl0(i,j,1) * (1.+(rv/rd-1.)*qt0(i,j,1)) + end do + end do + + call calc_obuk_ustar_ra(tile_lv) + call calc_obuk_ustar_ra(tile_hv) + call calc_obuk_ustar_ra(tile_bs) + call calc_obuk_ustar_ra(tile_ws) + end subroutine stability +! +! Calculate Obukhov length and ustar, for single tile +! +subroutine calc_obuk_ustar_ra(tile) + use modglobal, only : i1, j1, rd, rv, grav, zf + implicit none + + type(lsm_tile), intent(inout) :: tile + integer :: i, j + real :: thvs, db + + do j=2,j1 + do i=2,i1 + ! Buoyancy difference surface - atmosphere + thvs = tile%thlskin(i,j) * (1.+(rv/rd-1.)*tile%qtskin(i,j)) + db = grav/thvs * (thvs - thv_1(i,j)) + + ! Iteratively find Obukhov length + tile%obuk(i,j) = calc_obuk_dirichlet( & + tile%obuk(i,j), du_tot(i,j), db, zf(1), tile%z0m(i,j), tile%z0h(i,j)) + end do + end do + + do j=2,j1 + do i=2,i1 + ! Calculate friction velocity and aerodynamic resistance + tile%ustar(i,j) = du_tot(i,j) * fm(zf(1), tile%z0m(i,j), tile%obuk(i,j)) + tile%ra(i,j) = 1./tile%ustar(i,j) * fh(zf(1), tile%z0h(i,j), tile%obuk(i,j)) + end do + end do + +end subroutine calc_obuk_ustar_ra + + + ! @@ -463,6 +524,9 @@ subroutine allocate_fields allocate(throughfall(i2, j2)) + allocate(du_tot(i2, j2)) + allocate(thv_1(i2, j2)) + ! NOTE: names differ from what is described in modsurfdata! ! Diffusivity temperature: allocate(lambda (i2, j2, kmax_soil )) @@ -502,7 +566,8 @@ subroutine allocate_tile(tile) allocate(tile % z0m(i2, j2)) allocate(tile % z0h(i2, j2)) - ! Dynamic tile fraction: + ! Base and dynamic tile fraction: + allocate(tile % base_frac(i2, j2)) allocate(tile % frac(i2, j2)) ! Monin-obukhov / surface layer: @@ -568,6 +633,7 @@ subroutine init_homogeneous implicit none integer :: ierr, k + real :: c_low, c_high, c_bare real :: z0m_low, z0m_high, z0m_bare real :: z0h_low, z0h_high, z0h_bare real :: lambda_s_low, lambda_s_high, lambda_s_bare @@ -580,6 +646,7 @@ subroutine init_homogeneous ! Read namelist namelist /NAMLSM_HOMOGENEOUS/ & + c_low, c_high, & z0m_low, z0m_high, z0m_bare, & z0h_low, z0h_high, z0h_bare, & lambda_s_low, lambda_s_high, lambda_s_bare, & @@ -600,6 +667,9 @@ subroutine init_homogeneous end if ! Broadcast to all MPI tasks + call MPI_BCAST(c_low, 1, my_real, 0, comm3d, mpierr) + call MPI_BCAST(c_high, 1, my_real, 0, comm3d, mpierr) + call MPI_BCAST(z0m_low, 1, my_real, 0, comm3d, mpierr) call MPI_BCAST(z0m_high, 1, my_real, 0, comm3d, mpierr) call MPI_BCAST(z0m_bare, 1, my_real, 0, comm3d, mpierr) @@ -627,6 +697,12 @@ subroutine init_homogeneous call MPI_BCAST(soil_index_p, kmax_soil, mpi_integer, 0, comm3d, mpierr) ! Set values + c_bare = 1.-c_low-c_high + tile_lv % base_frac(:,:) = c_low + tile_hv % base_frac(:,:) = c_high + tile_bs % base_frac(:,:) = c_bare + tile_ws % base_frac(:,:) = 0. + tile_lv % z0m(:,:) = z0m_low tile_hv % z0m(:,:) = z0m_high tile_bs % z0m(:,:) = z0m_bare @@ -658,6 +734,13 @@ subroutine init_homogeneous tsoilm(:,:,:) = tsoil(:,:,:) phiwm (:,:,:) = phiw (:,:,:) + ! Set properties wet skin tile + tile_ws % z0m(:,:) = c_low*z0m_low + c_high*z0m_high + c_bare*z0m_bare + tile_ws % z0h(:,:) = c_low*z0h_low + c_high*z0h_high + c_bare*z0h_bare + + tile_ws % lambda_stable(:,:) = c_low*lambda_s_low + c_high*lambda_s_high + c_bare*lambda_s_bare + tile_ws % lambda_unstable(:,:) = c_low*lambda_us_low + c_high*lambda_us_high + c_bare*lambda_us_bare + ! Cleanup! deallocate(t_soil_p, theta_soil_p) @@ -840,6 +923,7 @@ function calc_obuk_dirichlet(L_in, du, db_in, zsl, z0m, z0h) result(res) if (m > 1) then print*,'WARNING: convergence has not been reached in Obukhov length iteration' + print*,'Input: ', L_in, du, db_in, zsl, z0m, z0h res = 1e-9 return end if diff --git a/src/modstartup.f90 b/src/modstartup.f90 index 4e64d693..e5b91eb5 100644 --- a/src/modstartup.f90 +++ b/src/modstartup.f90 @@ -595,6 +595,10 @@ subroutine readinitfiles tskin = thls qskin = qts case(11) + thls = thlprof(1) + qts = qtprof(1) + tskin = thls + qskin = qts call init_lsm_tiles case(10) call initsurf_user diff --git a/src/modtimestat.f90 b/src/modtimestat.f90 index f93a6bcb..b3b717a1 100644 --- a/src/modtimestat.f90 +++ b/src/modtimestat.f90 @@ -63,7 +63,7 @@ module modtimestat real :: qlint logical:: store_zi = .false. - !Variables for heterogeneity + ! Variables for heterogeneity real, allocatable :: u0av_patch (:,:) ! patch averaged um at full level real, allocatable :: v0av_patch (:,:) ! patch averaged vm at full level real, allocatable :: w0av_patch (:,:) ! patch averaged wm at full level @@ -72,11 +72,13 @@ module modtimestat real,allocatable, dimension(:,:) :: cc_patch, qlint_patch, qlintmax_patch, qlintmax_patchl, tke_tot_patch real,allocatable, dimension(:,:) :: wmax_patch, wmax_patchl, qlmax_patch, qlmax_patchl, ztopmax_patch, ztopmax_patchl real,allocatable, dimension(:,:) :: ust_patch, qst_patch, tst_patch, wthls_patch, wqls_patch, wthvs_patch - !In combination with isurf = 1 + + ! In combination with isurf = 1 real,allocatable, dimension(:,:) :: Qnet_patch, H_patch, LE_patch, G0_patch, tendskin_patch,rs_patch,ra_patch real,allocatable, dimension(:,:) :: cliq_patch, wl_patch, rsveg_patch, rssoil_patch, tskin_patch, obl_patch real,allocatable, dimension(:,:) :: zi_patch,ziold_patch,we_patch, zi_field + contains !> Initializing Timestat. Read out the namelist, initializing the variables subroutine inittimestat @@ -185,7 +187,7 @@ subroutine inittimestat ' [m/s] ' close(ifoutput) end if - + if(lhetero) then do i=1,xpatches do j=1,ypatches @@ -197,7 +199,7 @@ subroutine inittimestat '# time cc z_cbase z_ctop_avg z_ctop_max zi we', & ' <> <>_max w_max tke ql_max' close(ifoutput) - + name = 'tmsurfpatchiiixjjj.'//cexpnr write (name(12:14),'(i3.3)') i write (name(16:18),'(i3.3)') j @@ -206,7 +208,7 @@ subroutine inittimestat '# time ust tst qst obukh', & ' thls z0 wthls wthvs wqls ' close(ifoutput) - + if(isurf == 1) then name = 'tmlsmpatchiiixjjj.'//cexpnr write (name(11:13),'(i3.3)') i @@ -231,7 +233,7 @@ subroutine inittimestat if (isurf == 1) then nvar = 32 else if (isurf == 11) then - nvar = 25 + nvar = 34 else nvar = 21 end if @@ -273,11 +275,24 @@ subroutine inittimestat call ncinfo(ncname(30,:),'Wl','Liquid water reservoir','m','time') call ncinfo(ncname(31,:),'rssoil','Soil evaporation resistance','s/m','time') call ncinfo(ncname(32,:),'rsveg','Vegitation resistance','s/m','time') + else if (isurf==11) then call ncinfo(ncname(22,:),'Qnet','Net radiation','W/m^2','time') call ncinfo(ncname(23,:),'H','Sensible heat flux','W/m^2','time') call ncinfo(ncname(24,:),'LE','Latent heat flux','W/m^2','time') call ncinfo(ncname(25,:),'G','Ground heat flux','W/m^2','time') + + call ncinfo(ncname(26,:),'obuk_lv','Obukhov length low veg','m','time') + call ncinfo(ncname(27,:),'obuk_hv','Obukhov length high veg','m','time') + call ncinfo(ncname(28,:),'obuk_bs','Obukhov length bare soil','m','time') + + call ncinfo(ncname(29,:),'ustar_lv','Friction velocity low veg','m s-1','time') + call ncinfo(ncname(30,:),'ustar_hv','Friction velocity high veg','m s-1','time') + call ncinfo(ncname(31,:),'ustar_bs','Friction velocity bare soil','m s-1','time') + + call ncinfo(ncname(32,:),'ra_lv','Aerodynamic resistance low veg','s m-1','time') + call ncinfo(ncname(33,:),'ra_hv','Aerodynamic resistance high veg','s m-1','time') + call ncinfo(ncname(34,:),'ra_bs','Aerodynamic resistance bare soil','s m-1','time') end if call open_nc(fname, ncid,nrec) @@ -355,9 +370,10 @@ subroutine timestat lhetero, xpatches, ypatches, qts_patch, wt_patch, wq_patch, & thls_patch,obl,z0mav_patch, wco2av, Anav, Respav,gcco2av use modsurface, only : patchxnr,patchynr + use modlsm, only : tile_lv, tile_hv, tile_bs, tile_ws use mpi use modmpi, only : my_real,mpi_sum,mpi_max,mpi_min,comm3d,mpierr,myid - use modstat_nc, only : lnetcdf, writestat_nc,nc_fillvalue + use modstat_nc, only : lnetcdf, writestat_nc,nc_fillvalue implicit none real :: zbaseavl, ztopavl, ztopmaxl, ztop,zbaseminl @@ -372,6 +388,12 @@ subroutine timestat ! lsm variables real :: Qnetavl, Havl, LEavl, G0avl, tendskinavl, rsavl, raavl, tskinavl,Wlavl,cliqavl,rsvegavl,rssoilavl real :: Qnetav, Hav, LEav, G0av, tendskinav, rsav, raav, tskinav,Wlav,cliqav,rsvegav,rssoilav + + ! LSM tiled variables + real :: obuk_lv_av, obuk_hv_av, obuk_bs_av + real :: ustar_lv_av, ustar_hv_av, ustar_bs_av + real :: ra_lv_av, ra_hv_av, ra_bs_av + integer:: i, j, k ! heterogeneity variables @@ -768,20 +790,25 @@ subroutine timestat endif else if(isurf == 11) then - Qnetavl = sum(Qnet(2:i1,2:j1)) - Havl = sum(H(2:i1,2:j1)) - LEavl = sum(LE(2:i1,2:j1)) - G0avl = sum(G0(2:i1,2:j1)) - call MPI_ALLREDUCE(Qnetavl, Qnetav, 1, MY_REAL,MPI_SUM, comm3d,mpierr) - call MPI_ALLREDUCE(Havl, Hav, 1, MY_REAL,MPI_SUM, comm3d,mpierr) - call MPI_ALLREDUCE(LEavl, LEav, 1, MY_REAL,MPI_SUM, comm3d,mpierr) - call MPI_ALLREDUCE(G0avl, G0av, 1, MY_REAL,MPI_SUM, comm3d,mpierr) + Qnetav = mean_2d(Qnet) + Hav = mean_2d(H) + LEav = mean_2d(LE) + G0av = mean_2d(G0) + + ! Tiled variables + obuk_lv_av = mean_2d(tile_lv%obuk) + obuk_hv_av = mean_2d(tile_hv%obuk) + obuk_bs_av = mean_2d(tile_bs%obuk) + + ustar_lv_av = mean_2d(tile_lv%ustar) + ustar_hv_av = mean_2d(tile_hv%ustar) + ustar_bs_av = mean_2d(tile_bs%ustar) + + ra_lv_av = mean_2d(tile_lv%ra) + ra_hv_av = mean_2d(tile_hv%ra) + ra_bs_av = mean_2d(tile_bs%ra) - Qnetav = Qnetav / ijtot - Hav = Hav / ijtot - LEav = LEav / ijtot - G0av = G0av / ijtot end if ! 9.8 write the results to output file @@ -887,6 +914,15 @@ subroutine timestat vars(23) = Hav vars(24) = LEav vars(25) = G0av + vars(26) = obuk_lv_av + vars(27) = obuk_hv_av + vars(28) = obuk_bs_av + vars(29) = ustar_lv_av + vars(30) = ustar_hv_av + vars(31) = ustar_bs_av + vars(32) = ra_lv_av + vars(33) = ra_hv_av + vars(34) = ra_bs_av end if call writestat_nc(ncid,nvar,ncname,vars,nrec,.true.) @@ -960,6 +996,19 @@ subroutine timestat end subroutine timestat + function mean_2d(var_2d) result(res) + use modglobal, only : i1, j1, ijtot + use modmpi, only : my_real, mpi_sum, comm3d, mpierr + implicit none + real, intent(in) :: var_2d(:,:) + real :: res, var_sum_l, var_sum + + var_sum_l = sum(var_2d(2:i1,2:j1)) + call mpi_allreduce(var_sum_l, var_sum, 1, my_real, mpi_sum, comm3d, mpierr) + res = var_sum / ijtot + + end function mean_2d + !>Calculate the boundary layer height !! !! There are 3 available ways to calculate the boundary layer height: