modthermodynamics.f90 Source File


This file depends on

sourcefile~~modthermodynamics.f90~~EfferentGraph sourcefile~modthermodynamics.f90 modthermodynamics.f90 sourcefile~modfields.f90 modfields.f90 sourcefile~modthermodynamics.f90->sourcefile~modfields.f90 sourcefile~modglobal.f90 modglobal.f90 sourcefile~modthermodynamics.f90->sourcefile~modglobal.f90 sourcefile~modmpi.f90 modmpi.f90 sourcefile~modthermodynamics.f90->sourcefile~modmpi.f90 sourcefile~modsurfdata.f90 modsurfdata.f90 sourcefile~modthermodynamics.f90->sourcefile~modsurfdata.f90 sourcefile~modfields.f90->sourcefile~modglobal.f90 sourcefile~modglobal.f90->sourcefile~modmpi.f90

Files dependent on this one

sourcefile~~modthermodynamics.f90~~AfferentGraph sourcefile~modthermodynamics.f90 modthermodynamics.f90 sourcefile~modstartup.f90 modstartup.f90 sourcefile~modstartup.f90->sourcefile~modthermodynamics.f90 sourcefile~program.f90 program.f90 sourcefile~program.f90->sourcefile~modthermodynamics.f90 sourcefile~program.f90->sourcefile~modstartup.f90

Source Code

!>\file modthermodynamics.f90
!! Do the thermodynamics

!>
!! Do the thermodynamics
!>
!! Timeseries of the most relevant parameters. Written to tmser1.expnr and tmsurf.expnr
!! If netcdf is true, this module leads the tmser.expnr.nc output
!!  \author Pier Siebesma, K.N.M.I.
!!  \author Stephan de Roode,TU Delft
!!  \author Thijs Heus,MPI-M
!!  \par Revision list
!  This file is part of DALES.
!
! DALES is free software; you can redistribute it and/or modify
! it under the terms of the GNU General Public License as published by
! the Free Software Foundation; either version 3 of the License, or
! (at your option) any later version.
!
! DALES is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
! GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License
! along with this program.  If not, see <http://www.gnu.org/licenses/>.
!
!  Copyright 1993-2009 Delft University of Technology, Wageningen University, Utrecht University, KNMI
!

module modthermodynamics

  implicit none
  !   private
  public :: thermodynamics,calc_halflev
  public :: lqlnr
  logical :: lqlnr    = .false. !< switch for ql calc. with Newton-Raphson (on/off)
  real, allocatable :: th0av(:)
  real :: chi_half=0.5  !< set wet, dry or intermediate (default) mixing over the cloud edge
  real, allocatable :: thv0(:,:,:)
contains

  !> Allocate and initialize arrays
  subroutine initthermodynamics
    use modglobal, only : kb,ke,kh,ib,ie,jb,je

    implicit none

    allocate(th0av(kb:ke+kh))
    allocate(thv0(ib:ie,jb:je,kb:ke+kh))
    th0av = 0.

  end subroutine initthermodynamics

  !> Do moist thermodynamics.
  !! Calculate the liquid water content, do the microphysics, calculate the mean hydrostatic pressure, calculate the fields at the half levels, and finally calculate the virtual potential temperature.
  subroutine thermodynamics
    use modglobal, only : lmoist, timee, kb, ke, kh, ib, ih, ie, jb, jh, je,rlv, cp, rslabs, rd, rv, libm, eps1
    use modfields, only : thl0,thl0h,qt0,qt0h,ql0,ql0h,presf,presh,exnf,exnh,thvh,thv0h,qt0av,ql0av,thvf,rhof,IIc,IIw,IIcs,IIws
    use modmpi,    only : slabsum,avexy_ibm,myid
!ILS13 added variables behind "exnh"
    implicit none
    integer :: k
    if (timee==0) call diagfld
    if (lmoist) then
       call thermo(thl0,qt0,ql0,presf,exnf)
    end if

    call diagfld
    call calc_halflev !calculate halflevel values of qt0 and thl0
    if (lmoist) then
       call thermo(thl0h,qt0h,ql0h,presh,exnh)
    end if
    call calthv

!ILS13 introduced from DALES4.0   13.05.2015
    thvh=0.
!    call slabsum(thvh,kb,ke+kh,thv0h(:,:,kb:ke+kh),ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh) !redefine halflevel thv using calculated thv
!    thvh = thvh/rslabs
    call avexy_ibm(thvh(kb:ke+kh),thv0h(ib:ie,jb:je,kb:ke+kh),ib,ie,jb,je,kb,ke,ih,jh,kh,IIw(ib:ie,jb:je,kb:ke+kh),IIws(kb:ke+kh),.false.)

!    if (libm) then
!      call avexy_ibm(thvh(kb:ke),thv0h(ib:ie,jb:je,kb:ke),ib,ie,jb,je,kb,ke,IIw(ib:ie,jb:je,kb:ke),IIws(kb:ke))    
!    else
!      call slabsum(thvh,kb,ke+kh,thv0h(:,:,kb:ke+kh),ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
!     !redefine halflevel thv using calculated thv
!     thvh = thvh/rslabs
!    end if

    thvh(kb) = th0av(kb)*(1+(rv/rd-1)*qt0av(kb)-rv/rd*ql0av(kb)) ! override first level
    if (abs(thvh(kb+1))<eps1) then
      thvh(kb+1) = th0av(kb+1)*(1+(rv/rd-1)*qt0av(kb+1)-rv/rd*ql0av(kb+1)) ! override second level if all blocks at kb
    end if
!    where (thvh==0) !override slabs completely covered by blocks
!      thvh = th0av(kb)*(1+(rv/rd-1)*qt0av(kb)-rv/rd*ql0av(kb))
!    endwhere

    do k=kb,ke+kh
!    thv0(ib+ih:ie,jb+jh:je,k) = (thl0(ib+ih:ie,jb+ih:je,k)+rlv*ql0(ib+ih:ie,jb+ih:je,k)/(cp*exnf(k)))*(1+(rv/rd-1)*qt0(ib+ih:ie,jb+ih:je,k)-rv/rd*ql0(ib+ih:ie,jb+ih:je,k))
    thv0(ib:ie,jb:je,k) = (thl0(ib:ie,jb:je,k)+rlv*ql0(ib:ie,jb:je,k)/(cp*exnf(k)))*(1+(rv/rd-1)*qt0(ib:ie,jb:je,k)-rv/rd*ql0(ib:ie,jb:je,k))
    enddo
    thvf = 0.0

    !write(*,*) "thv0",thv0
!    call slabsum(thvf,kb,ke+kh,thv0,ib,ie+ih,jb,je+jh,kb,ke+kh,ib+ih,ie,jb+ih,je,kb,ke+kh)
!    call slabsum(thvf,kb,ke+kh,thv0,ib,ie,jb,je,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
    call avexy_ibm(thvf(kb:ke+kh),thv0(ib:ie,jb:je,kb:ke+kh),ib,ie,jb,je,kb,ke,ih,jh,kh,IIc(ib:ie,jb:je,kb:ke+kh),IIcs(kb:ke+kh),.false.)
!    write(*,*) 'IIc(2,2,:), myid' , IIc(12,2,:), myid

!    where (thvf==0) !override slabs completely covered by blocks
!      thvf = th0av(kb)*(1+(rv/rd-1)*qt0av(kb)-rv/rd*ql0av(kb))
!    endwhere

!    thvf = thvf/rslabs
    !write(*,*) "thvf",thvf
    !write(*,*) "exnf",exnf
   
!    do k=1,k1
!      rhof(k) = presf(k)/(rd*thvf(k)*exnf(k))
!    end do

  end subroutine thermodynamics
  !> Cleans up after the run
  subroutine exitthermodynamics
    implicit none
    deallocate(th0av)
  end subroutine exitthermodynamics

  !> Calculate thetav and dthvdz
  subroutine calthv
    use modglobal, only : lmoist,ib,ie,jb,je,kb,ke,kh,zf,zh,dzh,rlv,rd,rv,cp,eps1
    use modfields, only : thl0,thl0h,ql0,ql0h,qt0,qt0h,sv0,exnf,exnh,thv0h,dthvdz
    use modsurfdata,only : dthldz,dqtdz

    implicit none

    integer i, j, k
    real    qs
    real    c1,c2,dq,dth,dthv,temp
    real    a_dry, b_dry, a_moist, b_moist, c_liquid, epsilon, eps_I, chi_sat, chi
    real    del_thv_sat, del_thv_dry
    dthvdz = 0.0
    if (lmoist) then

       do  k=kb,ke+kh
          do  j=jb,je
             do  i=ib,ie
                thv0h(i,j,k) = (thl0h(i,j,k)+rlv*ql0h(i,j,k)/(cp*exnh(k))) &
                     *(1+(rv/rd-1)*qt0h(i,j,k)-rv/rd*ql0h(i,j,k))
             end do
          end do
       end do

       do k=kb+1,ke
          do j=jb,je
             do i=ib,ie
                !
                !         default thv jump computed unsaturated
                !
                epsilon = rd/rv
                eps_I = 1/epsilon - 1.  !cstep approx 0.608

                a_dry = 1. + eps_I * qt0(i,j,k)
                b_dry = eps_I * thl0(i,j,k)

                dth = thl0(i,j,k+1)-thl0(i,j,k-1)
                dq  = qt0(i,j,k+1)-qt0(i,j,k-1)

                del_thv_dry = a_dry   * dth + b_dry * dq

                dthv = del_thv_dry

                if  (ql0(i,j,k)> 0) then  !include moist thermodynamics
                   temp = thl0(i,j,k)*exnf(k)+(rlv/cp)*ql0(i,j,k)
                   qs   = qt0(i,j,k) - ql0(i,j,k)

                   a_moist = (1.-qt0(i,j,k)+qs/epsilon*(1.+rlv/(rv*temp))) &
                        /(1.+rlv**2*qs/(cp*rv*temp**2))
                   b_moist = a_moist*rlv/cp-temp
                   c_liquid = a_dry * rlv / cp - thl0(i,j,k) / epsilon

                   del_thv_sat = a_moist * dth + b_moist * dq

                   chi     = 2*chi_half*(zf(k) - zf(k-1))/(dzh(k)+dzh(k+1))
                   chi_sat = c_liquid * ql0(i,j,k) / (del_thv_dry - del_thv_sat)

                   if (chi < chi_sat) then  !mixed parcel is saturated
                      dthv = del_thv_sat
                   end if
                end if

                dthvdz(i,j,k) = dthv/(dzh(k+1)+dzh(k))
             end do
          end do
       end do

       do j=jb,je
          do i=ib,ie
            dthvdz(i,j,kb)=0.
          end do
       end do

    else
       !      thv0h = thl0h
       thv0h = thl0h(:,:,kb:ke+kh)
       do k=kb+1,ke
          do j=jb,je
             do i=ib,ie
                dthvdz(i,j,k) = (thl0(i,j,k+1)-thl0(i,j,k-1))/(dzh(k+1)+dzh(k))
             end do
          end do
       end do
       do  j=jb,je
          do  i=ib,ie
            dthvdz(i,j,kb)=0.
          end do
       end do
    end if

    !CvH remove WHERE
    !where (abs(dthvdz)<eps1)
    !  dthvdz = sign(eps1,dthvdz)
    !end where
    do k=kb,ke
       do j=jb,je
          do i=ib,ie
             if(abs(dthvdz(i,j,k)) < eps1) then
                dthvdz(i,j,k) = sign(eps1, dthvdz(i,j,k))
             end if
          end do
       end do
    end do



  end subroutine calthv
  !> Calculate diagnostic slab averaged fields.
  !!     Calculates slab averaged fields assuming
  !!     hydrostatic equilibrium for: u,v,theta_l,theta_v,
  !!     qt,ql,exner,pressure and the density
  !! \author      Pier Siebesma   K.N.M.I.     06/01/1995
  subroutine diagfld

    use modglobal, only : ib,ie,ih,jb,je,jh,kb,ke,kh,khc,nsv,zh,zf,rslabs,grav,rlv,cp,rd,rv,pref0
    use modfields, only : u0,v0,thl0,qt0,ql0,sv0,u0av,v0av,thl0av,qt0av,ql0av,sv0av, &
         presf,presh,exnf,exnh,rhof,thvf,IIc,IIcs,IIu,IIus,IIv,IIvs
    use modsurfdata,only : thls,ps
    use modmpi,    only : slabsum,myid,avexy_ibm
    implicit none

    real     tv
    integer  k, n


    !!*********************************************************
    !!  1.0   calculate average profiles of u,v,thl,qt and ql *
    !!        assuming hydrostatic equilibrium                *
    !!*********************************************************

    ! initialise local MPI arrays
    u0av = 0.0
    v0av = 0.0
    thl0av = 0.0
    th0av  = 0.0
    qt0av  = 0.0
    ql0av  = 0.0
    sv0av = 0.


    !CvH changed momentum array dimensions to same value as scalars!
    !  call slabsum(u0av  ,kb,ke+kh,u0  ,ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
!    call slabsum(u0av  ,kb,ke+kh,u0(:,:,kb:ke+kh)  ,ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
    call avexy_ibm(u0av(kb:ke+kh),u0(ib:ie,jb:je,kb:ke+kh),ib,ie,jb,je,kb,ke,ih,jh,kh,IIu(ib:ie,jb:je,kb:ke+kh),IIus(kb:ke+kh),.false.)
    !  call slabsum(v0av  ,kb,ke+kh,v0  ,ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
!    call slabsum(v0av  ,kb,ke+kh,v0(:,:,kb:ke+kh)  ,ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
    call avexy_ibm(v0av(kb:ke+kh),v0(ib:ie,jb:je,kb:ke+kh),ib,ie,jb,je,kb,ke,ih,jh,kh,IIv(ib:ie,jb:je,kb:ke+kh),IIvs(kb:ke+kh),.false.)
    !  call slabsum(thl0av,kb,ke+kh,thl0,ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
!    call slabsum(thl0av,kb,ke+kh,thl0(:,:,kb:ke+kh),ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
    call avexy_ibm(thl0av(kb:ke+kh),thl0(ib:ie,jb:je,kb:ke+kh),ib,ie,jb,je,kb,ke,ih,jh,kh,IIc(ib:ie,jb:je,kb:ke+kh),IIcs(kb:ke+kh),.false.)

    !write(*,*) 'thl0av(kb), thl0av(kb+1)', thl0av(kb), thl0av(kb+1)
   
    !if (IIbl == 0) then ! as lEB applies blocks to kb and masking matrices average this to zero
    !  thl0av(kb) = thl0av(kb+1)
    !end if

    !  call slabsum(qt0av ,kb,ke+kh,qt0 ,ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
!    call slabsum(qt0av ,kb,ke+kh,qt0(:,:,kb:ke+kh) ,ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
    call avexy_ibm(qt0av(kb:ke+kh),qt0(ib:ie,jb:je,kb:ke+kh),ib,ie,jb,je,kb,ke,ih,jh,kh,IIc(ib:ie,jb:je,kb:ke+kh),IIcs(kb:ke+kh),.false.)
!    call slabsum(ql0av ,kb,ke+kh,ql0 ,ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
    call avexy_ibm(ql0av(kb:ke+kh),ql0(ib:ie,jb:je,kb:ke+kh),ib,ie,jb,je,kb,ke,ih,jh,kh,IIc(ib:ie,jb:je,kb:ke+kh),IIcs(kb:ke+kh),.false.)

    exnf   = 1-grav*zf/(cp*thls)
    exnh  = 1-grav*zh/(cp*thls)
    th0av  = thl0av + (rlv/cp)*ql0av/exnf

    !write(*,*) 'thl0av',thl0av
    !write(*,*) 'th0av',th0av
    

    do n=1,nsv
!       call slabsum(sv0av(kb,n),kb,ke+kh,sv0(ib-ih,jb-jh,kb,n),ib-ih,ie+ih,jb-jh,je+jh,kb,ke+kh,ib,ie,jb,je,kb,ke+kh)
    call avexy_ibm(sv0av(kb:ke+khc,n),sv0(ib:ie,jb:je,kb:ke+khc,n),ib,ie,jb,je,kb,ke,ih,jh,kh,IIc(ib:ie,jb:je,kb:ke+khc),IIcs(kb:ke+khc),.false.)
    end do
!    sv0av = sv0av/rslabs

    !***********************************************************
    !  2.0   calculate average profile of pressure at full and *
    !        half levels, assuming hydrostatic equilibrium.    *
    !***********************************************************

    !    2.1 Use first guess of theta, then recalculate theta
    call fromztop
    exnf = (presf/pref0)**(rd/cp)
    th0av = thl0av + (rlv/cp)*ql0av/exnf


    !    2.2 Use new updated value of theta for determination of pressure

    call fromztop



    !***********************************************************
    !  3.0   Construct density profiles and exner function     *
    !       for further use in the program                     *
    !***********************************************************

    !    3.1 determine exner

    exnh(kb) = (ps/pref0)**(rd/cp)
    exnf(kb) = (presf(kb)/pref0)**(rd/cp)
    do k=kb+1,ke+kh
       exnf(k) = (presf(k)/pref0)**(rd/cp)
       exnh(k) = (presh(k)/pref0)**(rd/cp)
    end do

    thvf(kb)      = th0av(kb)*exnf(kb)*(1+(rv/rd-1)*qt0av(kb)-rv/rd*ql0av(kb))
    rhof(kb) = presf(kb)/(rd*thvf(kb))

    !    3.2 determine rho

    do k=kb+1,ke     !+kh    ?
    !   write(*,*) "exnf(k)",exnf(k)
    !   write(*,*) "th0av(k)",th0av(k)
    !   write(*,*) "qt0av(k)",qt0av(k)
    !   write(*,*) "ql0av(k)",ql0av(k)
       thvf(k) = th0av(k)*exnf(k)*(1.+(rv/rd-1)*qt0av(k)-rv/rd*ql0av(k))
       rhof(k) = presf(k)/(rd*thvf(k))
    end do
    return
  end subroutine diagfld


  !> Calculates slab averaged pressure
  !!      Input :  zf,zh,theta and qt profile
  !!      Output:  pressure profile at full and
  !!               half levels
  !!
  !!      Method: Using hydrostatic equilibrium
  !!
  !!                              -g*pref0**(rd/cp)
  !! =====>       dp**(rd/cp)/dz = --------------
  !!                                 cp*thetav
  !! \author Pier Siebesma   K.N.M.I.     06/01/1995
  subroutine fromztop

    use modglobal, only : kmax,kb,ke,kh,dzf,dzh,rv,rd,cp,tmelt,zf,grav,pref0,lEB
    use modfields, only : qt0av,ql0av,presf,presh,thvh,thvf,IIcs
    use modsurfdata,only : ps,thvs
    implicit none

    integer   k
    real      rdocp
    real,allocatable,dimension (:) :: thetah, qth, qlh

    allocate(thetah(kb:ke+kh), qth(kb:ke+kh), qlh(kb:ke+kh))
    rdocp = rd/cp

    !**************************************************
    !    1.0 Determine theta and qt at half levels    *
    !**************************************************

    do k=kb+1,ke+kh
       thetah(k) = (th0av(k)*dzf(k-1) + th0av(k-1)*dzf(k))/(2*dzh(k))
       qth   (k) = (qt0av(k)*dzf(k-1) + qt0av(k-1)*dzf(k))/(2*dzh(k))
       qlh   (k) = (ql0av(k)*dzf(k-1) + ql0av(k-1)*dzf(k))/(2*dzh(k))
    end do

    !**************************************************
    !     2.1  calculate pressures at full levels     *
    !          assuming hydrostatic equilibrium       *
    !**************************************************

    !     1: lowest level: use thvs

    thvh(kb) = thvs
    presf(kb) = ps**rdocp - &
         grav*(pref0**rdocp)*zf(kb) /(cp*thvh(kb))
    presf(kb) = presf(kb)**(1./rdocp)

    !     2: higher levels

    do k=kb+1,ke+kh 
       thvh(k)  = thetah(k)*(1+(rv/rd-1)*qth(k)-rv/rd*qlh(k))
       presf(k) = presf(k-1)**rdocp - grav*(pref0**rdocp)*dzh(k) /(cp*thvh(k))
       presf(k) = presf(k)**(1./rdocp)
    end do

    !**************************************************
    !     2.2   calculate pressures at half levels    *
    !           assuming hydrostatic equilibrium      *
    !**************************************************

    presh(kb) = ps
    thvf(kb) = th0av(kb)*(1+(rv/rd-1)*qt0av(kb)-rv/rd*ql0av(kb))
    do k=kb+1,ke+kh
       thvf(k)  = th0av(k)*(1+(rv/rd-1)*qt0av(k)-rv/rd*ql0av(k))
       presh(k) = presh(k-1)**rdocp - grav*(pref0**rdocp)*dzf(k-1) / (cp*thvf(k-1))
       presh(k) = presh(k)**(1./rdocp)
    end do

    deallocate(thetah, qth, qlh)

    return
  end subroutine fromztop

  !> Calculates liquid water content.
  !!     Given theta_l and q_tot the liquid water content
  !!     is calculated, making an "all-or-nothing" assumption.
  !!     if lfull=true   ==> ql at full levels on output
  !!     if lfull=false  ==> ql at half levels on output
  !!
  !! \author Hans Cuijpers   I.M.A.U.
  !! \author Pier Siebesma   K.N.M.I.     06/01/1995
  subroutine thermo (thl,qt,ql,pressure,exner)



    !  use modglobal, only : ih,jh,i1,j1,k1,es0,at,bt,rd,rv,rlv,cp,tmelt
    use modglobal, only : ih,jh,ib,ie,jb,je,kb,ke,kh,es0,at,bt,rd,rv,rlv,cp,tmelt
    use modsurfdata, only : thls
    implicit none

    integer i, j, k
    real tl, es, qs, qsl, b1
    !  real, intent(in)  :: qt(ib-ih:ie+ih,jb-jh:je+jh,kb:ke+kh),thl(ib-ih:ie+ih,jb-jh:je+jh,kb:ke+kh),exner(kb:ke+kh),pressure(kb:ke+kh)
    real, intent(in)  :: qt(ib-ih:ie+ih,jb-jh:je+jh,kb-kh:ke+kh),thl(ib-ih:ie+ih,jb-jh:je+jh,kb-kh:ke+kh),exner(kb:ke+kh),pressure(kb:ke+kh)
    real, intent(out) :: ql(ib-ih:ie+ih,jb-jh:je+jh,kb:ke+kh)
    real :: Tnr,qsatur,Tnr_old
    integer :: niter,nitert

    if (lqlnr) then
       !mc      calculation of T with Newton-Raphson method
       !mc      first guess is Tnr=tl
       !mc
       nitert = 0
       do k=kb,ke+kh
          do j=jb,je
             do i=ib,ie

                tl  = thl(i,j,k)*exner(k)
                Tnr=tl
                Tnr_old=0.
                do while (abs(Tnr-Tnr_old)/Tnr>1e-5)
                   niter = niter+1
                   Tnr_old = Tnr
                   es    = es0*exp(at*(Tnr-tmelt)/(Tnr-bt))
                   qsatur= rd/rv*es/(pressure(k)-(1-rd/rv)*es)
                   Tnr = Tnr - (Tnr+(rlv/cp)*qsatur-tl- &
                        (rlv/cp)*qt(i,j,k))/(1+(rlv**2*qsatur)/ &
                        (rv*cp*Tnr**2))
                end do
                nitert =max(nitert,niter)
                niter = 0

                ql(i,j,k) = dim(qt(i,j,k)-qsatur,0.)

             end do
          end do
       end do
    else


       do k=kb,ke+kh
          do j=jb,je
             do i=ib,ie
                tl  = thl(i,j,k)*exner(k)
                es  = es0*exp(at*(tl-tmelt)/(tl-bt))
                qsl = rd/rv*es/(pressure(k)-(1-rd/rv)*es)
                b1  = rlv**2/(tl**2*cp*rv)
                qs  = qsl*(1.+b1*qt(i,j,k))/(1.+b1*qsl)
                ql(i,j,k) = dim(qt(i,j,k)-qs,0.)
             end do
          end do
       end do
    end if

    return
  end subroutine thermo

  !> Calculates the scalars at half levels.
  !! If the kappa advection scheme is active, interpolation needs to be done consistently.
  subroutine calc_halflev
    use modglobal, only : ib,ie,jb,je,kb,ke,kh,dzf,dzh,iadv_thl, iadv_qt, iadv_kappa
    use modfields, only : thl0,thl0h,qt0,qt0h
    use modsurfdata,only: qts,thls
    implicit none

    integer :: i,j,k


    !      do  k=kb+1,ke+kh
    do  k=kb,ke+kh
       do  j=jb,je
          do  i=ib,ie
             thl0h(i,j,k) = (thl0(i,j,k)*dzf(k-1)+thl0(i,j,k-1)*dzf(k))/(2*dzh(k))
          end do
       end do

    end do
        thl0h(ib:ie,jb:je,kb) = thls

    !      do  k=kb+1,ke+kh
    do  k=kb,ke+kh
       do  j=jb,je
          do  i=ib,ie
             qt0h(i,j,k)  = (qt0 (i,j,k)*dzf(k-1)+qt0 (i,j,k-1)*dzf(k))/(2*dzh(k))
          end do
       end do
    end do
          qt0h(ib:ie,jb:je,kb)  = qts

  end subroutine calc_halflev

end module modthermodynamics