diff --git a/CMakeLists.txt b/CMakeLists.txt index 5df81955e23cc0dd653e531e852d5aee9a188ce1..a6c7d111531d8ed72ac61a73a9da762846a22b88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,10 +31,11 @@ endif(BUILD_DOC) set(lib_files src/parkinds.f90 src/pbl_grid.f90 - src/phys_fluid.f90 + src/phys_fluid.f90 src/state_utils.f90 src/scm_state_data.f90 src/pbl_turb_data.f90 + src/pbl_solver.f90 src/diag_pbl.f90) add_library(abl_lib ${lib_files}) diff --git a/src/pbl_fo_turb.f90 b/src/pbl_fo_turb.f90 new file mode 100644 index 0000000000000000000000000000000000000000..fe140e683046c6692f05c15e51f2641a0f4e8e3d --- /dev/null +++ b/src/pbl_fo_turb.f90 @@ -0,0 +1,11 @@ +! Created by Andrey Debolskiy on 29.11.2024. + +module pbl_fo_turb + implicit none + + public get_fo_coeffs + public get_turb_length + public + contains + +end module pbl_fo_turb \ No newline at end of file diff --git a/src/pbl_solver.f90 b/src/pbl_solver.f90 new file mode 100644 index 0000000000000000000000000000000000000000..ce9530e9d99e166bf1a043ef63ba98b9de508187 --- /dev/null +++ b/src/pbl_solver.f90 @@ -0,0 +1,109 @@ +! Created by Andrey Debolskiy on 29.11.2024. + +module pbl_solver + use parkinds, only: rf=>kind_rf, im=>kind_im + use scm_state_data + use pbl_turb_data + implicit none + + public factorize_tridiag + public solve_tridiag + public fill_tridiag + public solve_diffusion + contains + subroutine factorize_tridiag(ktvd, kl, aa, bb, cc, prgna, prgnz) + implicit none + integer, intent(in) :: ktvd, kl + real, intent(in), dimension(kl) :: aa, bb, cc + real, intent(out), dimension(kl) :: prgna, prgnz + + integer :: k + + prgna(ktvd) = cc(ktvd) / bb(ktvd) + do k = ktvd+1, kl + prgnz(k) = 1.0e0 / (bb(k) - aa(k) * prgna(k-1)) + prgna(k) = cc(k) * prgnz(k) + end do + end subroutine factorize_tridiag + + !> reduce tridiagonal system to bidiagonal after matrix factorization + !! - bb(k) y(k) + cc(k) y(k+1) = -f(k), k = ktvd + !! aa(k) y(k-1) - bb(k) y(k) + cc(k) y(k+1) = -f(k), k = ktvd+1..kl-1 + !! aa(k) y(k-1) - bb(k) y(k) = -f(k), k = kl + !! assuming cc(kl) = 0.0 + !! reduced system is + !! y(k) - prgna(k) y(k+1) = prgnb(k), k = ktvd..kl-1 + !! y(k) = prgnb(k), k = kl + !! then solve via backward substitution + subroutine solve_tridiag(ktvd, kl, aa, bb, cc, ff, prgna, prgnz, y) + implicit none + integer, intent(in) :: ktvd, kl + real, intent(in), dimension(kl) :: aa, bb, cc, ff + real, intent(in), dimension(kl) :: prgna, prgnz + real, intent(out), dimension(kl) :: y + + integer :: k + real :: prgnb(kl) + + prgnb(ktvd) = ff(ktvd) / bb(ktvd) + do k = ktvd+1, kl + prgnb(k) = prgnz(k) * (ff(k) + aa(k) * prgnb(k-1)) + end do + y(kl) = prgnb(kl) + do k = kl-1, ktvd, -1 + y(k) = prgna(k) * y(k+1) + prgnb(k) + end do + end subroutine solve_tridiag + + subroutine fill_tridiag(aa, bb, cc, rho, kdiff, kbltop, grid, dt) + use pbl_grid, only: pblgridDataType + implicit none + real, dimension(*), intent(in):: rho, kdiff + real, intent(in):: dt + integer, intent(in):: kbltop + type(pblgridDataType),intent(in):: grid + + real, dimension(*), intent(out):: aa, bb, cc + + real:: dtdz + integer:: k + + !nulify before top boundary + aa(1:kbltop) = 0.0 + bb(1:kbltop) = 0.0 + cc(1:kbltop) = 0.0 + !top boundary condition: flux = 0 + k = kbltop + dtdz = dt / (grid%dzc(k)) + aa(k) = 0 + cc(k) = (kdiff(k)/rho(k)) * dtdz / grid%dze(k) + + do k = kbltop + 1, grid%kmax -1 + dtdz = dt / (grid%dzc(k)) + aa(k) = (kdiff(k - 1)/rho(k)) * dtdz / grid%dze(k-1) + cc(k) = (kdiff(k)/rho(k)) * dtdz / grid%dze(k) + bb(k) = 1.0 + aa(k) + cc(k) + end do + + !bottom boundary + k = grid%kmax + dtdz = dt / (grid%dzc(k)) + aa(k) = (kdiff(k-1)/rho(k)) * dtdz / grid%dze(k-1) + bb(k) = 1.0 + aa(k) + cc(k) = 0.0 + end subroutine fill_tridiag + + subroutine solve_diffusion(bl, bl_old, turb, fluid, grid) + use scm_state_data, only : stateBLDataType + use pbl_turb_data, only : turbBLDataType + use phys_fluid, only: fluidParamsDataType + use pbl_grid, only : pblgridDataType + implicit none + type(stateBLDataType), intent(out):: bl + type(stateBLDataType), intent(in):: bl_old + type(turbBLDataType), intent(in):: turb + type(fluidParamsDataType), intent(in) :: fluid + type(pblgridDataType), intent(in) :: grid + + end subroutine solve_diffusion +end module pbl_solver \ No newline at end of file diff --git a/src/state_utils.f90 b/src/state_utils.f90 index 311241cc30eb23d4c4cba32bcc00c3605cba2f2b..2d0eebcfe5e874660856f6a1d28e3b6fc7abf9c4 100644 --- a/src/state_utils.f90 +++ b/src/state_utils.f90 @@ -2,7 +2,11 @@ module state_utils - + public geo + public theta2ta + public ta2theta + public dqsdt_sc, qmax_sc, qmax + public DQSDT2, DQSDT, CLDT contains SUBROUTINE GEO(T,FS,F,SIG, R, LL) @@ -31,23 +35,6 @@ module state_utils - - SUBROUTINE NANOLOVKA(X,INAN) - implicit none - real, intent(in):: x - integer, intent(out):: inan - inan=1 - - IF(X.LE.0.0) THEN - INAN=0 - END IF - - IF(X.GE.0.0) THEN - INAN=0 - END IF - - END SUBROUTINE NANOLOVKA - subroutine theta2ta(ta, theta, p0, sig, appa, kl) implicit none real, dimension(kl), intent(in):: theta @@ -77,4 +64,76 @@ module state_utils theta(k) = ta(k) * (p0 * sig(k))**(-appa) end do end subroutine ta2theta + + real function qmax_sc(t, p, aa) + implicit none + + real, intent(in) :: t, p, aa + real :: pb2, pb + + pb2 = t - 273.2e0 + if ((aa.gt.1.0e0.and.pb2.ge.0.0e0).or.(aa.lt.1.0e0.and.pb2.ge.-12.0e0)) then + pb=17.55e0/(t-31.1e0) + else + pb=21.85e0/(t-7.65e0) + end if + qmax_sc=3.80042e-3*exp(pb*pb2)/p + end function qmax_sc + real function qmax(T,P, AA ) + IMPLICIT NONE + real, intent(in):: t, p, aa + !local + real pb2, pb + PB2=T-273.2E0 + IF((AA.GT.1.0E0.AND.PB2.GE.0.0E0).OR. & + (AA.LT.1.0E0.AND.PB2.GE.-12.0E0))THEN + PB=17.55E0/(T-31.1E0 ) + ELSE + PB=21.85E0/(T-7.65E0) + ENDIF + QMAX=3.80042E-3*EXP(PB*PB2)/P + RETURN + end function qmax + + + real function dqsdt_sc(a, b, h) + real, intent(in) :: a, b, h + + dqsdt_sc=4248.855e0*h*qmax_sc(a,b, 0.0e0)/(a-31.10e0)**2 + end function dqsdt_sc + + REAL FUNCTION CLDT(Q,T,P,C) + ! + IMPLICIT NONE + REAL, INTENT(IN) :: Q,T,P,C + ! REAL DQSDT + !REAL :: QMAX + + CLDT=(Q-C*QMAX(T,P, 0.0E0))/(1.0E0+2488.851E0*DQSDT(T,P,C)) + RETURN + END FUNCTION CLDT + + REAL FUNCTION DQSDT(A,B,H) + ! + IMPLICIT NONE + REAL, INTENT(IN) :: A, B, H + !REAL :: QMAX + + DQSDT=4248.855E0*H*QMAX(A,B, 0.0E0)/(A-31.10E0)**2 + RETURN + END FUNCTION DQSDT + + REAL FUNCTION DQSDT2(A,B,H) + + IMPLICIT NONE + + REAL, INTENT(IN) :: A, B, H + ! REAL DQSDT + !REAL :: QMAX + + DQSDT2=4248.855E0*H*(DQSDT(A,B, H )/(A-31.10E0)**2 - & + 2.0E0*QMAX (A,B, 0.0E0)/(A-31.10E0)**3) + RETURN + END FUNCTION DQSDT2 + end module state_utils \ No newline at end of file diff --git a/src/tests/gabls1.f90 b/src/tests/gabls1.f90 index 91478bce2a6c83b0676d29679f4967e6d81c7c8a..8bd572b69dec5a21ddfd4604cd6ffa9ae1cc4319 100644 --- a/src/tests/gabls1.f90 +++ b/src/tests/gabls1.f90 @@ -10,6 +10,7 @@ program gabls1 use scm_sfx_data, only: taux, tauy, umst, hflx, qflx, cu use scm_state_data use pbl_turb_data + use pbl_solver use state_utils, only : geo, theta2ta, ta2theta use diag_pbl use pbl_grid @@ -38,6 +39,7 @@ program gabls1 type(pblgridDataType) grid type(stateBLDataType):: bl, bl_old; + type(turbBLDataType):: turb type(meteoDataType) :: meteo_cell type(sfxDataType) :: sfx_cell @@ -191,6 +193,8 @@ program gabls1 END DO call theta2ta(bl_old%temp, bl_old%theta, fluid_params%pref / 1000.0, grid%sigma, 287.5 / 1003.5, bl_old%kmax) + + !io setup nt = floor((time_end - time_begin)/output_dt) allocate(ttime(nt)) @@ -217,7 +221,8 @@ program gabls1 hflx = sfx_cell%Cm * sfx_cell%Ct * meteo_cell%U * meteo_cell%dT umst = sfx_cell%Cm * meteo_cell%U - !call vdiff_scm() + call get_fo_diff(turb, bl, grid) + call solv_diffusion(bl, bl_old, turb, fluid_params, grid) call add_coriolis(bl, ug, vg, f_cor, dt, grid) time_current = time_current + dt