module_vdiff.F90 Source File


This file depends on

sourcefile~~module_vdiff.f90~~EfferentGraph sourcefile~module_vdiff.f90 module_vdiff.F90 sourcefile~module_tool.f90 module_tool.F90 sourcefile~module_vdiff.f90->sourcefile~module_tool.f90

Files dependent on this one

sourcefile~~module_vdiff.f90~~AfferentGraph sourcefile~module_vdiff.f90 module_vdiff.F90 sourcefile~diffusion.f90 diffusion.F90 sourcefile~diffusion.f90->sourcefile~module_vdiff.f90 sourcefile~main.f90 main.f90 sourcefile~main.f90->sourcefile~diffusion.f90

Source Code

module mod_vdiff
   !! 垂直扩散
   use mod_tool, only: fp, eps

   implicit none

   private
   public vdiff_by_k_theory, thomas_solver

   contains

   subroutine vdiff_by_k_theory(dt, dz, kz, rho, conc)
      !! 采用后向欧拉法求解垂直方向的网格湍流扩散(K-theory)。
      !! 用 Thomas 算法求解后向时间差分格式的垂直扩散方程。
      !! 假设底层和顶层边界通量均为 0。
      real(fp), intent(in) :: dt    !! 积分时间: s
      real(fp), intent(in) :: dz(:) !! 网格垂直层宽度: m
      real(fp), intent(in) :: kz(:) !! 垂直扩散系数:m^2/s

      real(fp), intent(in) :: rho(:) !! 空气密度: kg/m^3
      real(fp), intent(inout) :: conc(:) !! 浓度: ug/m^3

      real(fp) :: aa(size(conc)) !! 下对角线
      real(fp) :: bb(size(conc)) !! 主对角线
      real(fp) :: cc(size(conc)) !! 上对角线
      real(fp) :: kz_rho(size(conc)) !! 辅助变量
      integer :: k, nz

      nz = size(dz)

      do k = 1, nz-1
         ! kz_rho(k) = kz(k) * (rho(k) + rho(k+1))/(dz(k) + dz(k+1))
         kz_rho(k) = 2._fp * kz(k) * (rho(k)*dz(k+1) + rho(k+1)*dz(k))/(dz(k) + dz(k+1))**2
      end do
      ! 后向欧拉
      ! Lower boundary condition
      aa(1) = 0.
      bb(1) = 1. + dt/dz(1) * kz_rho(1)/rho(1)
      ! Upper boundary condition
      bb(nz) = 1. + dt/dz(nz) * kz_rho(nz-1)/rho(nz)
      cc(nz) = 0.

      ! middle
      do k = 2, nz
         aa(k) = - dt/dz(k) * kz_rho(k-1)/rho(k-1)
      end do

      do k = 2, nz-1
         bb(k) = 1. + dt/dz(k) * (kz_rho(k-1)/rho(k) + kz_rho(k)/rho(k))
      end do

      do k = 1, nz-1
         cc(k) = - dt/dz(k) * kz_rho(k)/rho(k+1)
      end do

      ! A c_{t+1} = c_t
      call thomas_solver(nz, aa, bb, cc, conc)

      where(conc < eps) conc = 0._fp

   end subroutine vdiff_by_k_theory

   subroutine thomas_solver(n, a, b, c, x)
      !! Thomas算法求解三对角矩阵线性方程组 Ax = d,
      !! 其中,A = [a, b, c]
      implicit none
      integer, intent(in) :: n     !! 矩阵规模
      real(fp), intent(in) :: a(n) !! 下对角线
      real(fp), intent(in) :: b(n) !! 主对角线
      real(fp), intent(in) :: c(n) !! 上对角线
      real(fp), intent(inout) :: x(n) !! 求解得到的解向量

      real(fp) :: b_(n) !! 临时数组用于存储修正后的对角线
      integer :: i
      ! 前向消去, 消去下对角线(a)
      b_(1) = b(1)
      x(1) = x(1)/b_(1) ! 最开始的时候 d = x
      do i = 2, n
         b_(i) = b(i) - a(i)/b_(i-1) * c(i-1) ! c(i-1) ==> b(i)
         x(i) = (x(i) - a(i)*x(i-1))/b_(i) ! x(i-1) ==> x(i)
      end do

      ! 回带求解
      x(n) = x(n)
      do i = n-1, 1, -1
         x(i) = x(i) - c(i) * x(i+1) / (b_(i))
      end do
   end subroutine thomas_solver

end module mod_vdiff