MODULE WATER_DENSITY

 use LAKE_DATATYPES, only : ireals, iintegers
 use PHYS_CONSTANTS, only : &
 & row0


 implicit none

!The coefficients of UNESCO formula
!for water density dependence on temperature

 real(kind=ireals), parameter:: a0 = 800.969d-7
 real(kind=ireals), parameter:: a1 = 588.194d-7
 real(kind=ireals), parameter:: a2 = 811.465d-8
 real(kind=ireals), parameter:: a3 = 476.600d-10

!The coefficients of formula for
!water density dependence on temperature and salinity
!(McCutcheon et al.,Water Quality and Maidment. 
! Handbook on hydrology, 1993)
 
 real(kind=ireals), parameter:: A11 = 288.9414d0
 real(kind=ireals), parameter:: A12 = 508929.2d0
 real(kind=ireals), parameter:: A13 = 68.12963d0
 real(kind=ireals), parameter:: A14 = 3.9863d0
 real(kind=ireals), parameter:: alpha1 = 8.2449d-1
 real(kind=ireals), parameter:: alpha2 = 4.0899d-3
 real(kind=ireals), parameter:: alpha3 = 7.6438d-5
 real(kind=ireals), parameter:: alpha4 = 8.2467d-7
 real(kind=ireals), parameter:: alpha5 = 5.3675d-9
 real(kind=ireals), parameter:: beta1 = 5.724d-3
 real(kind=ireals), parameter:: beta2 = 1.0227d-4
 real(kind=ireals), parameter:: beta3 = 1.6546d-6
 real(kind=ireals), parameter:: gamma1 = 4.8314d-4

!The coefficients for "Kivu" EOS (Schmid et al., 2003)
 real(kind=ireals), parameter :: at1 = 999.843, at2 = 65.4891d-3, at3 = - 8.56272d-3, at4 = 0.059385d-3
 real(kind=ireals), parameter :: beta = 0.75d-3 ! kg/g
 real(kind=ireals), parameter :: beta_co2 = 0.284d-3 ! coefficient for co2, kg/g
 real(kind=ireals), parameter :: beta_ch4 = -1.25d-3 ! coefficient for ch4, kg/g
 real(kind=ireals), parameter :: co2_ref = 0.d0, ch4_ref = 0.d0 ! reference concentrations, kg/g

 real(kind=ireals), save ::  DDENS_DTEMP0, DDENS_DSAL0, DENS_REF

 integer(kind=iintegers), parameter :: eos_Hostetler = 1
 integer(kind=iintegers), parameter :: eos_TEOS = 2
 integer(kind=iintegers), parameter :: eos_Kivu = 3
 integer(kind=iintegers), parameter :: eos_UNESCO = 4
 integer(kind=iintegers), parameter :: eos_McCatcheon = 5

 !Temperature and salinity reference values
 real(kind=ireals), parameter :: temp_ref = 15. ! deg. C
 real(kind=ireals), parameter :: sal_ref = 0. !kg/kg


 contains

 SUBROUTINE SET_DENS_CONSTS(eos)

 implicit none 

 integer(kind=iintegers), intent(in) :: eos
 

 select case (eos)
 case(eos_Hostetler)
   call DDENS_HOSTETLER(temp_ref,DDENS_DTEMP0,DDENS_DSAL0)
   DENS_REF = DENS_HOSTETLER(temp_ref)
 case(eos_TEOS)
   print*, 'Not operational eos: STOP '
   STOP
 case(eos_Kivu)
   call DDENS_KIVU(temp_ref,sal_ref,DDENS_DTEMP0,DDENS_DSAL0)
   DENS_REF = WATER_DENS_TS_KIVU(temp_ref,sal_ref)
 case(eos_UNESCO)
   call DDENS_UNESCO(temp_ref,DDENS_DTEMP0,DDENS_DSAL0)
   DENS_REF = WATER_DENS_T_UNESCO(temp_ref)
 case(eos_McCatcheon)
   DDENS_DTEMP0 = DDENS_DTEMP(temp_ref,sal_ref) 
   DDENS_DSAL0  = DDENS_DSAL (temp_ref,sal_ref)
   DENS_REF = WATER_DENS_TS(temp_ref,sal_ref)
 end select

 END SUBROUTINE SET_DENS_CONSTS


 FUNCTION SET_DDENS_DTEMP(eos,lindens,Temp,Sal)

 implicit none 

 ! Input/output variables
 integer(kind=iintegers), intent(in) :: eos !> Equation of state identifier
 integer(kind=iintegers), intent(in) :: lindens !> Switch for linear density function
 real(kind=ireals), intent(in) :: Temp, Sal

 real(kind=ireals) :: SET_DDENS_DTEMP

 ! Local variables
 real(kind=ireals) :: x

 if (lindens == 0) then
   select case (eos)
   case(eos_Hostetler)
     call DDENS_HOSTETLER(Temp,SET_DDENS_DTEMP,x)
   case(eos_TEOS)
     print*, 'Not operational eos: STOP '
     STOP
   case(eos_Kivu)
     call DDENS_KIVU(Temp,Sal,SET_DDENS_DTEMP,x)
   case(eos_UNESCO)
     call DDENS_UNESCO(Temp,SET_DDENS_DTEMP,x)
   case(eos_McCatcheon)
     SET_DDENS_DTEMP = DDENS_DTEMP(Temp,Sal) 
   end select
 else
   SET_DDENS_DTEMP = DDENS_DTEMP0
 endif

 END FUNCTION SET_DDENS_DTEMP


 FUNCTION SET_DDENS_DSAL(eos,lindens,Temp,Sal)

 implicit none 

 ! Input/output variables
 integer(kind=iintegers), intent(in) :: eos !> Equation of state identifier
 integer(kind=iintegers), intent(in) :: lindens !> Switch for linear density function
 real(kind=ireals), intent(in) :: Temp, Sal

 real(kind=ireals) :: SET_DDENS_DSAL

 ! Local variables
 real(kind=ireals) :: x

 if (lindens == 0) then
   select case (eos)
   case(eos_Hostetler)
     call DDENS_HOSTETLER(Temp,x,SET_DDENS_DSAL)
   case(eos_TEOS)
     print*, 'Not operational eos: STOP '
     STOP
   case(eos_Kivu)
     call DDENS_KIVU(Temp,Sal,x,SET_DDENS_DSAL)
   case(eos_UNESCO)
     call DDENS_UNESCO(Temp,x,SET_DDENS_DSAL)
   case(eos_McCatcheon)
     SET_DDENS_DSAL = DDENS_DSAL(Temp,Sal) 
   end select
 else
   SET_DDENS_DSAL = DDENS_DSAL0
 endif

 END FUNCTION SET_DDENS_DSAL


 !>Subroutine DENSITY_W calculates density profile
 SUBROUTINE DENSITY_W(M,eos,lindens,Tw,Sal,preswat,row)

 integer(kind=iintegers), intent(in) :: eos, M, lindens

 real(kind=ireals), intent(in) :: Tw(1:M+1), Sal(1:M+1), preswat(1:M+1)

 real(kind=ireals), intent(out) :: row(1:M+1)

 integer(kind=iintegers) :: i

 !Calculation of water density profile at the current timestep
 if (lindens == 0) then
   select case (eos)
   case(eos_Hostetler)
     do i = 1, M+1
       row(i) = DENS_HOSTETLER(Tw(i))
     enddo
   case(eos_TEOS)
     do i = 1, M+1
       row(i) = GSW_RHO(Sal(i),Tw(i),preswat(i))
     enddo
   case(eos_Kivu)
     do i = 1, M+1
       row(i) = WATER_DENS_TS_KIVU(Tw(i),Sal(i)) !0.d0
     enddo
   case(eos_UNESCO)
     do i = 1, M+1
       row(i) = WATER_DENS_T_UNESCO(Tw(i)) !0.d0
     enddo
   case(eos_McCatcheon)
     do i = 1, M+1
       row(i) = WATER_DENS_TS(Tw(i),Sal(i)) ! McCutcheon et al., 1993
     enddo
   end select
 else
   do i = 1, M+1
     row(i) = DENS_REF + DDENS_DTEMP0*(Tw(i) - temp_ref) + &
     &                   DDENS_DSAL0 *(Sal(i) - sal_ref) 
   enddo
 endif

 END SUBROUTINE DENSITY_W


 real(kind=ireals) FUNCTION WATER_DENS_T_UNESCO(Temp)

!The function WATER_DENS_T_UNESCO
!returns the density of water, kg/m**3, 
!as a function of temperature 
!according to UNESCO formula
 
 implicit none

 real(kind=ireals), intent(in):: Temp
 
 WATER_DENS_T_UNESCO = &
&  row0*(1+a0+a1*Temp-a2*Temp**2+a3*Temp**3)
 END FUNCTION WATER_DENS_T_UNESCO


 SUBROUTINE DDENS_UNESCO(Temp,ddens_dtemp,ddens_dsal)
 implicit none

 real(kind=ireals), intent(in):: Temp
 real(kind=ireals), intent(out):: ddens_dtemp, ddens_dsal
 
 ddens_dtemp = &
 & row0*(a1 - 2.*a2*Temp + 3.*a3*Temp**2)
 ddens_dsal = 0.

 END SUBROUTINE DDENS_UNESCO


 FUNCTION WATER_DENS_TS_KIVU(Temp,Sal)

! The function WATER_DENS_TS_KIVU
! resturns the density of water, kg/m**3,
! as a function of temperature and salinity
! adjusted for Lake Kivu (Rwanda & DRC) according to
! (Schmid et al. 2003)

! Input variables:
 
! Temp --- water temperature, deg C
! Sal  --- water salinity,    kg/kg
  
  implicit none

  real(kind=ireals), intent(in):: Temp
  real(kind=ireals), intent(in):: Sal

  real(kind=ireals) :: WATER_DENS_TS_KIVU

  real(kind=ireals) :: Sal_g_kg,A,B,C

! Converting salinity units from kg/kg to g/kg
  Sal_g_kg = Sal*1.d+3

  WATER_DENS_TS_KIVU = (at1 + at2*Temp + at3*Temp**2 + at4*Temp**3)* &
  & (1. + beta*Sal_g_kg + beta_co2*co2_ref + beta_ch4*ch4_ref)

  END FUNCTION WATER_DENS_TS_KIVU


  SUBROUTINE DDENS_KIVU(Temp,Sal,ddens_dtemp,ddens_dsal)
  implicit none

  real(kind=ireals), intent(in) :: Temp, Sal
  real(kind=ireals), intent(out) :: ddens_dtemp, ddens_dsal

  real(kind=ireals) :: Sal_g_kg

! Converting salinity units from kg/kg to g/kg
  Sal_g_kg = Sal*1.d+3

  ddens_dtemp = (at2 + 2.*at3*Temp + 3.*at4*Temp**2)* &
  & (1. + beta*Sal_g_kg + beta_co2*co2_ref + beta_ch4*ch4_ref)
  ddens_dsal = (at1 + at2*Temp + at3*Temp**2 + at4*Temp**3)* &
  & beta*1.d+3

  END SUBROUTINE DDENS_KIVU


  real(kind=ireals) FUNCTION WATER_DENS_TS(Temp,Sal)

! The function WATER_DENS_TS
! resturns the density of water, kg/m**3,
! as a function of temperature and salinity
! according to
! (McCutcheon et al.,Water Quality and Maidment. 
!  Handbook on Hydrology, 1993)

! Input variables:
 
! Temp --- water temperature, deg C
! Sal  --- water salinity,    kg/kg
  
  implicit none

  real(kind=ireals), intent(in):: Temp
  real(kind=ireals), intent(in):: Sal

  real(kind=ireals) Sal_g_kg,A,B,C

! Converting salinity units from kg/kg to g/kg
  Sal_g_kg = Sal*1.d+3

! The first term, dependent on temperature      
  WATER_DENS_TS = row0 * &
 & ( 1.-(Temp+A11)*(Temp-A14)**2/(A12*(Temp+A13) ) )

  A =  alpha1         - alpha2*Temp    + alpha3*Temp**2 &
 &    -alpha4*Temp**3 + alpha5*Temp**4

  B = -beta1          + beta2*Temp     - beta3*Temp**2

  C = gamma1

! Adding the second term, dependent on temperature and salinity
  WATER_DENS_TS = WATER_DENS_TS + &
 & A*Sal_g_kg + B*Sal_g_kg**1.5 + C*Sal_g_kg**2.

  END FUNCTION WATER_DENS_TS


  real(kind=ireals) FUNCTION DDENS_DTEMP(Temp,Sal)

! The function DDENS_DTEMP
! returns the derivative of water density
! on temperature, kg/(m**3*C)
  
! Input variables:
 
! Temp --- water temperature, deg C
! Sal  --- water salinity,    kg/kg

  implicit none

  real(kind=ireals), intent(in):: Temp
  real(kind=ireals), intent(in):: Sal      

  real(kind=ireals) Sal_g_kg,A,B,C

  DDENS_DTEMP = &
  & -(row0/A12)*(Temp-A14)/( (Temp+A13)**2 ) * &
  & ( (Temp+A13)*( (Temp-A14)+2.*(Temp+A11) ) - &
  &  (Temp+A11)*(Temp-A14) )

! Converting salinity units from kg/kg to g/kg
  Sal_g_kg = Sal*1.d+3

  A = - alpha2 + 2.*alpha3*Temp - 3.*alpha4*Temp**2 + 4.*alpha5*Temp**3

  B = + beta2  - 2.*beta3*Temp

  DDENS_DTEMP = DDENS_DTEMP + A*Sal_g_kg + B*Sal_g_kg**1.5

  END FUNCTION DDENS_DTEMP
  

  real(kind=ireals) FUNCTION DDENS_DSAL(Temp,Sal)

! The function DDENS_DSAL
! returns the derivative of water density
! on salinity, , kg/(m**3*kg/kg)
  
! Input variables:
 
! Temp --- water temperature, deg C
! Sal  --- water salinity,    kg/kg

  implicit none

  real(kind=ireals), intent(in):: Temp
  real(kind=ireals), intent(in):: Sal

  real(kind=ireals) Sal_g_kg,A,B,C

  A =   alpha1         - alpha2*Temp    + alpha3*Temp**2 &
  &   - alpha4*Temp**3 + alpha5*Temp**4

  B = - beta1          + beta2*Temp     - beta3*Temp**2

  C = gamma1

! Converting salinity units from kg/kg to g/kg
  Sal_g_kg = Sal*1.d+3

  DDENS_DSAL = &
 & A + 1.5*B*Sal_g_kg**0.5 + 2.*C*Sal_g_kg

  DDENS_DSAL = DDENS_DSAL*1.d+3

  END FUNCTION DDENS_DSAL
  
  
  FUNCTION DENS_HOSTETLER(temp)
  
! Function DENS_HOSTETLER calculates the density of water
! dependent on temperature only, following Hostetler and Bartlein, 1990

  implicit none

  real(kind=ireals) :: DENS_HOSTETLER
  
  real(kind=ireals), intent(in) :: temp
  
! Parameters      
  real(kind=ireals), parameter :: row0 = 1.d+3
  real(kind=ireals), parameter :: temp0 = 3.85
  real(kind=ireals), parameter :: const = 1.9549d-5
  real(kind=ireals), parameter :: const_power = 1.68
  
  DENS_HOSTETLER = row0*(1.-const*abs(temp-temp0)**const_power)
  
  END FUNCTION DENS_HOSTETLER


  SUBROUTINE DDENS_HOSTETLER(Temp,ddens_dtemp,ddens_dsal)
  implicit none

! Parameters      
  real(kind=ireals), parameter :: row0 = 1.d+3
  real(kind=ireals), parameter :: temp0 = 3.85
  real(kind=ireals), parameter :: const = 1.9549d-5
  real(kind=ireals), parameter :: const_power = 1.68

  real(kind=ireals), intent(in):: Temp
  real(kind=ireals), intent(out):: ddens_dtemp, ddens_dsal
  
  ddens_dtemp = row0*( - const_power*const*abs(temp-temp0)**(const_power-1)* &
  & sign(1._ireals,temp-temp0))
  ddens_dsal = 0.

  END SUBROUTINE DDENS_HOSTETLER


!--------------------------------------------------------------------------

!--------------------------------------------------------------------------
! density and enthalpy, based on the 48-term expression for density from TEOS-2010
!--------------------------------------------------------------------------

!==========================================================================
FUNCTION GSW_RHO(sa_,ct_,p_) 
!==========================================================================

!  Calculates in-situ density from Absolute Salinity and Conservative 
!  Temperature, using the computationally-efficient 48-term expression for
!  density in terms of SA, CT and p (McDougall et al., 2011).
!
! sa     : Absolute Salinity                               [kg/kg]
! ct     : Conservative Temperature                        [deg C]
! p      : sea pressure                                    [Pa]
! 
! gsw_rho  : in-situ density (48 term equation)

implicit none

integer, parameter :: r14 = selected_real_kind(14,30)

real (r14), parameter :: v01 =  9.998420897506056d2, v02 =  2.839940833161907d0
real (r14), parameter :: v03 = -3.147759265588511d-2, v04 =  1.181805545074306d-3
real (r14), parameter :: v05 = -6.698001071123802d0, v06 = -2.986498947203215d-2
real (r14), parameter :: v07 =  2.327859407479162d-4, v08 = -3.988822378968490d-2
real (r14), parameter :: v09 =  5.095422573880500d-4, v10 = -1.426984671633621d-5
real (r14), parameter :: v11 =  1.645039373682922d-7, v12 = -2.233269627352527d-2
real (r14), parameter :: v13 = -3.436090079851880d-4, v14 =  3.726050720345733d-6
real (r14), parameter :: v15 = -1.806789763745328d-4, v16 =  6.876837219536232d-7
real (r14), parameter :: v17 = -3.087032500374211d-7, v18 = -1.988366587925593d-8
real (r14), parameter :: v19 = -1.061519070296458d-11, v20 =  1.550932729220080d-10
real (r14), parameter :: v21 =  1.0d0, v22 =  2.775927747785646d-3, v23 = -2.349607444135925d-5
real (r14), parameter :: v24 =  1.119513357486743d-6, v25 =  6.743689325042773d-10
real (r14), parameter :: v26 = -7.521448093615448d-3, v27 = -2.764306979894411d-5
real (r14), parameter :: v28 =  1.262937315098546d-7, v29 =  9.527875081696435d-10
real (r14), parameter :: v30 = -1.811147201949891d-11, v31 = -3.303308871386421d-5
real (r14), parameter :: v32 =  3.801564588876298d-7, v33 = -7.672876869259043d-9
real (r14), parameter :: v34 = -4.634182341116144d-11, v35 =  2.681097235569143d-12
real (r14), parameter :: v36 =  5.419326551148740d-6, v37 = -2.742185394906099d-5
real (r14), parameter :: v38 = -3.212746477974189d-7, v39 =  3.191413910561627d-9
real (r14), parameter :: v40 = -1.931012931541776d-12, v41 = -1.105097577149576d-7
real (r14), parameter :: v42 =  6.211426728363857d-10, v43 = -1.119011592875110d-10
real (r14), parameter :: v44 = -1.941660213148725d-11, v45 = -1.864826425365600d-14
real (r14), parameter :: v46 =  1.119522344879478d-14, v47 = -1.200507748551599d-15
real (r14), parameter :: v48 =  6.057902487546866d-17 

real (kind=ireals), intent(in) :: sa_, ct_, p_
real (r14) :: sa, ct, p, sqrtsa, v_hat_denominator, &
& v_hat_numerator, gsw_rho

sa = sa_*1.d+3 ! Converting kg/kg to g/kg
p = p_*1.d-4   ! Converting pressure from Pa to dbar
ct = ct_

sqrtsa = sqrt(sa)

v_hat_denominator = v01 + ct*(v02 + ct*(v03 + v04*ct))  &
         + sa*(v05 + ct*(v06 + v07*ct) &
         + sqrtsa*(v08 + ct*(v09 + ct*(v10 + v11*ct)))) &
         + p*(v12 + ct*(v13 + v14*ct) + sa*(v15 + v16*ct) &
         + p*(v17 + ct*(v18 + v19*ct) + v20*sa))

v_hat_numerator = v21 + ct*(v22 + ct*(v23 + ct*(v24 + v25*ct))) &
       + sa*(v26 + ct*(v27 + ct*(v28 + ct*(v29 + v30*ct))) + v36*sa &
       + sqrtsa*(v31 + ct*(v32 + ct*(v33 + ct*(v34 + v35*ct)))))  &
       + p*(v37 + ct*(v38 + ct*(v39 + v40*ct))  &
       + sa*(v41 + v42*ct) &
       + p*(v43 + ct*(v44 + v45*ct + v46*sa) &
       + p*(v47 + v48*ct)))

GSW_RHO = v_hat_denominator/v_hat_numerator

return
END FUNCTION GSW_RHO


  END MODULE WATER_DENSITY


  MODULE PHYS_FUNC

  use LAKE_DATATYPES, only : ireals, iintegers

  contains
  real(kind=ireals) FUNCTION TURB_DENS_FLUX(tempflux,salflux,Temp,Sal)

! Function TURB_DENS_FLUX            _____
! returns the turbulent density flux w'ro' in water
! at given temperature, 
!          salinity,         ____
!          temperature flux  w'T'
!                            ____
!      and salinity    flux  w's'

! Input variables:
! tempflux --- kinematic heat flux, m*C/s
! salflux  --- salinity       flux, m*(kg/kg)/s
! Temp     --- temperature        , C
! Sal      --- salinity           , kg/kg

  use water_density, only : &
 & ddens_dtemp, &
 & ddens_dsal
  
  implicit none
  
  real(kind=ireals), intent(in):: tempflux
  real(kind=ireals), intent(in):: salflux
  real(kind=ireals), intent(in):: Temp
  real(kind=ireals), intent(in):: Sal

  TURB_DENS_FLUX = &
 & ddens_dtemp(Temp,Sal)*tempflux + &
 & ddens_dsal (Temp,Sal)*salflux

  END FUNCTION TURB_DENS_FLUX

 
!  real(kind=ireals) FUNCTION dirdif()
!  use atmos, only:
! & shortwave
! implicit none
!  real(kind=ireals) cloud
!  real(kind=ireals) dirdif0,b,S0,sinh0

!  SAVE

!  b=1./3.
!  S0=1367.
!  cloud = 0.
 
!  dirdif0 = (shortwave-b*S0*sinh0())/(b*(S0*sinh0()-shortwave))
!  dirdif = dirdif0*(1.-cloud)
!  dirdif = max(dirdif,0.d0)
  
!  END FUNCTION dirdif


  FUNCTION SINH0(year,month,day,hour,phi)

! SINH0 is sine of solar angle ( = cosine of zenith angle)   
  use TIME_LAKE_MOD, only : JULIAN_DAY  
  implicit none
  
  real(kind=ireals) :: sinh0
  
  integer(kind=iintegers), intent(in) :: year
  integer(kind=iintegers), intent(in) :: month
  integer(kind=iintegers), intent(in) :: day

  real(kind=ireals)   , intent(in) :: hour
  real(kind=ireals)   , intent(in) :: phi

  real(kind=ireals) delta
  real(kind=ireals) theta
  real(kind=ireals) pi
   real(kind=ireals) phi_rad

  integer(kind=iintegers) nday
 
  pi=4.*datan(1.d0)

  nday  = JULIAN_DAY(year,month,day)

  delta = 23.5d0*pi/180.d0*cos(2*pi*(float(nday)-173.d0)/365.d0)
  theta = pi*(hour-12.d0)/12.d0
  phi_rad = phi*pi/180.d0
  sinh0 = sin(phi_rad)*sin(delta) + &
  & cos(phi_rad)*cos(delta)*cos(theta)
  sinh0=max(sinh0,0.d0) 

  END FUNCTION SINH0


  !> Function LONGWAVE_RADIATION returns incident 
  !! longwave (atmospheric) radiation on the earth surface
  FUNCTION LONGWAVE_RADIATION(tempair,humair,pressure,cloud_sky_fraction) result(LR)
  use UNITS, only : Pa_to_hPa
  use PHYS_CONSTANTS, only : Kelvin0, Rd_d_Rwv, sigma
  implicit none
  real(kind=ireals), intent(in) :: tempair !> Surface air temperature, Celsius
  real(kind=ireals), intent(in) :: humair  !> Surface air specific humidity, kg/kg
  real(kind=ireals), intent(in) :: pressure!> Surface atmospheric pressure, Pa
  real(kind=ireals), intent(in) :: cloud_sky_fraction !> Cloud-sky fraction, 0-1, n/d
  !> Output variables
  real(kind=ireals) :: LR
  !> Local variables
  real(kind=ireals) :: emis, a1, a2, a3, parpres, Rwv_d_Rd

  integer(kind=iintegers), parameter :: CAN = 1 !(Anstrom, 1915; Marthews et al., Theor Appl Climatol, 2012)
  integer(kind=iintegers), parameter :: CBR = 2 !(Brunt, 1932; Marthews et al., Theor Appl Climatol, 2012)
  integer(kind=iintegers), parameter :: CSW = 3 !(Swinbank, 1963; Marthews et al., Theor Appl Climatol, 2012)
  integer(kind=iintegers), parameter :: CIJ = 4 !(Idso and Jackson, 1969; Marthews et al., Theor Appl Climatol, 2012)
  integer(kind=iintegers), parameter :: CBT = 5 !(Brutsaert, 1975, 1982; Marthews et al., Theor Appl Climatol, 2012)
  integer(kind=iintegers), parameter :: CID = 6 !(Idso, 1981; Marthews et al., Theor Appl Climatol, 2012)
  integer(kind=iintegers), parameter :: CKZ = 7 !(Konzelmann et al., 1994; Marthews et al., Theor Appl Climatol, 2012)
  integer(kind=iintegers), parameter :: nCSE = CAN !switch for clear-sky emissivity parameterization

  Rwv_d_Rd = 1./Rd_d_Rwv
  parpres = humair*pressure*Rwv_d_Rd/(1. + humair*(Rwv_d_Rd - 1.))*Pa_to_hPa

  select case(nCSE)
  case(CAN)
    a1 = 0.83
    a2 = 0.18
    a3 = 0.067
    emis = a1 - a2*10**( - a3*parpres)
  case(CBR)
    a1 = 0.51
    a2 = 0.066
    emis = a1 + a2*sqrt(parpres)
  case(CSW)
    a1 = 0.0000092
    emis = a1*(tempair + Kelvin0)**2
  case(CIJ)
    a1 = 0.261
    a2 = 0.000777
    emis = 1. - a1*exp( - a2*tempair**2)
  case(CBT)
    a1 = 1.24
    emis = a1*(parpres/(tempair + Kelvin0))**(1./7.)
  case(CID)
    a1 = 0.7
    a2 = 0.0000595
    a3 = 1500.
    emis = a1 + a2*parpres*exp(a3/(tempair + Kelvin0))
  case(CKZ)
    a1 = 0.23
    a2 = 0.484
    emis = a1 + a2*(parpres/(tempair + Kelvin0))**(1./8.)
  end select

  !Correction of emissivity for cloudiness
  a1 = 0.22
  emis = emis*(1. + a1*cloud_sky_fraction)
  emis = min(emis,1._ireals)
  LR = emis*sigma*(tempair + Kelvin0)**4

  END FUNCTION LONGWAVE_RADIATION

  !> Function SHORTWAVE_RADIATION returns incident 
  !! shortwave (solar) radiation (direct+diffuse) on the earth surface
  FUNCTION SHORTWAVE_RADIATION(time_group,phi,cloud_sky_fraction) result(SR)
  use PHYS_CONSTANTS, only : solar_constant
  use ARRAYS, only : time_type
  implicit none
  !> Input variables
  type(time_type), intent(in) :: time_group !>The group of time/date variables, time assumed local, not GMT
  real(kind=ireals), intent(in) :: phi !>The latitude, deg.
  real(kind=ireals), intent(in) :: cloud_sky_fraction !> Cloud-sky fraction, 0-1, n/d
  !> Output variables
  real(kind=ireals) :: SR
  !> Local variables
  real(kind=ireals) :: sinsolh, trans_atm, SR_dir, SR_dif, a1, a2, SR_atten

  sinsolh = SINH0(time_group%year,time_group%month,time_group%day,time_group%hour,phi)
  trans_atm = 0.6 ! atmospheric transmissivity for direct solar radiation
  SR_atten = trans_atm**(1./sinsolh)
  !Direct solar radiation at the horizontal surface (Burger's law)
  SR_dir = solar_constant*SR_atten*sinsolh
  !Diffuse solar radiation at the horizontal surface (Liu and Jordan, Solar Energy, 1960; 
  !Jemaa et al., Energy Procedia, 2013)
  a1 = 0.271
  a2 = 0.294
  SR_dif = solar_constant*(a1 - a2*SR_atten)*sinsolh
  SR = SR_dir + SR_dif
  !Correction of global radiation by cloudiness (Kasten and Czeplak, Solar Energy, 1980; 
  !Jemaa et al., Energy Procedia, 2013)
  a1 = 0.75
  a2 = 3.4
  SR = SR*(1.-a1*cloud_sky_fraction**a2)

  END FUNCTION SHORTWAVE_RADIATION


  real(kind=ireals) FUNCTION QS(phase,t,p)
  
! QS - specific humidity, kg/kg, for saturated water vapour

  implicit none
  real(kind=ireals) t,p,aw,bw,ai,bi,a,b,es
  integer(kind=iintegers) phase
!phase = 1 - liquid, 0 - ice
aw = 7.6326    
bw = 241.9    
ai = 9.5  
bi = 265.5 
a  = phase*aw+(1-phase)*ai
b  = phase*bw+(1-phase)*bi
es=610.7*10.**(a*t/(b+t))
QS=0.622*es/p
END FUNCTION

!> Derivative of saturated specific humidity on temperature
FUNCTION DQSDT(phase,t,p)
! QS - specific humidity, kg/kg, for saturated water vapour
implicit none
real(kind=ireals) :: t,p,aw,bw,ai,bi,a,b,qs,es
real(kind=ireals) :: DQSDT
integer(kind=iintegers) :: phase
!phase = 1 - liquid, 0 - ice
aw = 7.6326    
bw = 241.9    
ai = 9.5  
bi = 265.5 
a  = phase*aw+(1-phase)*ai
b  = phase*bw+(1-phase)*bi
es = 610.7*10.**(a*t/(b+t))
qs = 0.622*es/p
DQSDT = qs*a*b*log(10.)/(b+t)**2
END FUNCTION DQSDT


real(kind=ireals) FUNCTION ES(phase,t,p)

!     ES is pressure of saturated water vapour, Pa    

implicit none
real(kind=ireals) t,p,aw,bw,ai,bi,a,b
integer(kind=iintegers) phase
!phase = 1 - liquid, 0 - ice
aw = 7.6326    
bw = 241.9    
ai = 9.5  
bi = 265.5 
a  = phase*aw+(1-phase)*ai
b  = phase*bw+(1-phase)*bi
ES = 610.7*10.**(a*t/(b+t))
END FUNCTION


real(kind=ireals) FUNCTION MELTPNT(C,p,npar)
implicit none

real(kind=ireals), intent(in) :: C ! salinity, kg/kg
real(kind=ireals), intent(in) :: p ! pressure, Pa
integer(kind=iintegers), intent(in) :: npar 

real(kind=ireals), parameter :: dtdc = 66.7, pnorm = 101325
real(kind=ireals), parameter :: Pa2dbar = 1.d-4

select case(npar)
case(0)
  MELTPNT = 0.
case(1)
  MELTPNT = 0. - C*dtdc
case(2)
  ! Jackett et al. 2004 formula
  MELTPNT = FP_THETA(C*1.E+3_ireals, (p-pnorm)*Pa2dbar,'air-sat') ! convertion to 0/00
end select

END FUNCTION MELTPNT

FUNCTION FP_THETA(s,p,sat)

!   potential temperature freezing point of seawater, as in
!   Jackett, McDougall, Feistel, Wright and Griffies (2004), submitted JAOT
!
!   s                : salinity                               (psu)
!   p                : gauge pressure                         (dbar)
!                      (absolute pressure - 10.1325 dbar)
!   sat              : string variable
!                       'air-sat'  - air saturated water       
!                       'air-free' - air free water
!
!   fp_theta         : potential freezing temperature         (deg C, ITS-90)
!
!   check value      : fp_theta(35,200,'air-sat')   = -2.076426227617581 deg C
!                      fp_theta(35,200,'air-free') = -2.074408175943127 deg C
!
!   DRJ on 2/6/04


implicit real(kind=ireals)(a-h,o-z)

character*(*) sat


sqrts = sqrt(s)

tf_num =                          2.5180516744541290d-03    +     &
                              s*(-5.8545863698926184d-02    +     &
                          sqrts*( 2.2979985780124325d-03    -     &
                         sqrts *  3.0086338218235500d-04))  +     &
                              p*(-7.0023530029351803d-04    +     &
                              p*( 8.4149607219833806d-09    +     &
                             s *  1.1845857563107403d-11));

tf_den =                          1.0000000000000000d+00    +     &
                              p*(-3.8493266309172074d-05    +     &
                             p *  9.1686537446749641d-10)   +     &
                      s*s*sqrts*  1.3632481944285909d-06 


fp_theta = tf_num/tf_den;


if(sat.eq.'air-sat') then 
    fp_theta = fp_theta          -2.5180516744541290d-03    +     &
                             s *  1.428571428571429d-05
elseif(sat.eq.'air-free') then  
    continue
else  
    print *, '***   Error in fp_theta.f90: invalid third argument   ***'
    print *
    stop
endif


return
END FUNCTION FP_THETA
  
  FUNCTION WATER_FREEZE_MELT(temperature, grid_size, &
 & melting_point, switch)
 
! The function WATER_FREEZE_MELT checks, if the
! heat storage of a grid cell is larger or equal
! the latent heat, necessary for phase transition
  
  use PHYS_CONSTANTS, only : &
 & cw_m_row0, &
 & ci_m_roi, &
 & row0_m_Lwi, &
 & roi_m_Lwi
  use NUMERIC_PARAMS, only : &
 & min_ice_thick, &
 & min_water_thick, &
 & T_phase_threshold
 
  implicit none
  
! Input variables
  real(kind=ireals), intent(in) :: temperature ! Temperature, Celsius
  real(kind=ireals), intent(in) :: grid_size
  real(kind=ireals), intent(in) :: melting_point
  
  integer(kind=iintegers), intent(in) :: switch ! +1 for water -> ice transition
                                   ! -1 for ice -> water transition
  logical :: WATER_FREEZE_MELT
  
  if (switch == +1) then
    if ( ( melting_point - T_phase_threshold - temperature) * &
 &   cw_m_row0*grid_size > min_ice_thick*roi_m_Lwi .or. &
 &   ( melting_point - T_phase_threshold - temperature) > 0.2d0) &
 &   then
      WATER_FREEZE_MELT = .true.
    else
      WATER_FREEZE_MELT = .false.
    endif
  elseif (switch == -1) then
    if ( (temperature - T_phase_threshold - melting_point) * &
 &   ci_m_roi*grid_size > min_water_thick*row0_m_Lwi .or. &
 &   (temperature - T_phase_threshold - melting_point) > 0.2d0) &
 &   then
      WATER_FREEZE_MELT = .true.
    else
      WATER_FREEZE_MELT = .false.
    endif     
  else
    write(*,*) 'Wrong switch in WATER_FREEZE_MELT: STOP'
    STOP
  endif
  
  END FUNCTION WATER_FREEZE_MELT


  !> Subroutine TURB_SCALES calculates turbulent scales, both bulk and local
  SUBROUTINE TURB_SCALES(gsp, ls, bathymwater, wst, RadWater, &
  & k_turb_T_flux, T_massflux, row, eflux0_kinem, &
  & turb_density_flux, Buoyancy0, tau, kor, i_maxN, H_mixed_layer, maxN, w_conv_scale, &
  & T_conv_scale, Wedderburn, LakeNumber, Rossby_rad, ThermThick, ReTherm, RiTherm, trb)
 
  use DRIVING_PARAMS, only : M, eos, lindens
  use PHYS_CONSTANTS, only : g, row0, cw_m_row0, g_d_Kelvin0, niu_wat
  use ARRAYS_BATHYM, only : bathym, layers_type
  use ARRAYS_GRID, only : gridspacing_type
  use WATER_DENSITY, only : DDENS_DTEMP0, DDENS_DSAL0
  use NUMERIC_PARAMS, only : small_value
  use ARRAYS_WATERSTATE, only : waterstate_type
  use RADIATION, only : rad_type
  use ARRAYS_TURB, only : turb_type
  use WATER_DENSITY, only : SET_DDENS_DTEMP, SET_DDENS_DSAL

  implicit none

! Input variables
  type(gridspacing_type), intent(in) :: gsp
  type(layers_type), intent(in) :: ls
  type(bathym), intent(in) :: bathymwater(1:M+1)
  type(waterstate_type), intent(in) :: wst
  type(rad_type), intent(in) :: RadWater

  real(kind=ireals), intent(in) :: k_turb_T_flux(1:M)
  real(kind=ireals), intent(in) :: T_massflux(1:M)
  real(kind=ireals), intent(in) :: row(1:M+1)
  real(kind=ireals), intent(in) :: eflux0_kinem
  real(kind=ireals), intent(in) :: turb_density_flux
  real(kind=ireals), intent(in) :: Buoyancy0
  real(kind=ireals), intent(in) :: tau
  real(kind=ireals), intent(in) :: kor

! Output variables
  integer(kind=iintegers), intent(out) :: i_maxN

  real(kind=ireals), intent(out) :: H_mixed_layer
  real(kind=ireals), intent(out) :: maxN
  real(kind=ireals), intent(out) :: w_conv_scale
  real(kind=ireals), intent(out) :: T_conv_scale
  real(kind=ireals), intent(out) :: Wedderburn !Wedderburn number
  real(kind=ireals), intent(out) :: LakeNumber
  real(kind=ireals), intent(out) :: Rossby_rad !Internal Rossby radius
  real(kind=ireals), intent(out) :: ThermThick !Thermocline thickness
  real(kind=ireals), intent(out) :: ReTherm    !Reynolds number in thermocline
  real(kind=ireals), intent(out) :: RiTherm    !Richardson number in thermocline

  type(turb_type), intent(inout) :: trb
  
! External functions
  real(kind=ireals), external:: DZETA
  
  real(kind=ireals), parameter :: Ttherm0 = 14., Ttherm1 = 8. !temperatures of top and bottom of thermocline, C

! Auxilliary variables
  integer(kind=iintegers) :: maxlocat, i
  real(kind=ireals), allocatable :: bvf(:)
  real(kind=ireals) :: zv, zm, x, y, x1, x2
  real(kind=ireals) :: u1, u2, v1, v2, Sal1, Sal2

! Mixed-layer depth - depth of maximal heat flux
!  maxlocat = 1
!  do i = 2, M
!    if (k_turb_T_flux(i) + T_massflux(i) > &
!    & k_turb_T_flux(maxlocat) + T_massflux(maxlocat)) maxlocat = i
!  enddo
!  H_mixed_layer = dzeta_05int(maxlocat)*h1

! Mixed-layer depth - depth of maximal Bruent-Vaisala frequency
!  allocate (bvf(2:M-1))      
!  do i = 2, M-1
!    bvf(i) = g/row0*(row(i+1) - row(i-1))/(h1*(ddz(i-1) + ddz(i)))
!  enddo
!  maxlocat = maxloc(bvf,1) + lbound(bvf,1) - 1
!  deallocate (bvf)
!  H_mixed_layer = dzeta_int(maxlocat)*h1

  call MIXED_LAYER_CALC(row,gsp%ddz,gsp%ddz2,gsp%dzeta_int,gsp%dzeta_05int, &
  & ls%h1,M,i_maxN,H_mixed_layer,maxN)

  w_conv_scale = max( (Buoyancy0 - &
  & (RadWater%integr(1) - RadWater%integr(i_maxN))*g_d_Kelvin0/cw_m_row0) * &
  & H_mixed_layer, 0._ireals)**(1._ireals/3._ireals) 

  T_conv_scale = -eflux0_kinem/(w_conv_scale + small_value)

  Wedderburn = max(min(g*(row(M+1) - row(1))*H_mixed_layer*H_mixed_layer/&
  & ((tau+small_value)*max(bathymwater(1)%Lx,bathymwater(1)%Ly)),&
  & 1.e+2_ireals),1.e-2_ireals)

  ! Depth of volume center (zv) and of center of mass (zm)
  zm = 0.; x1 = 0.
  zv = 0.; x2 = 0.
  do i = 1, M+1
    y = gsp%ddz05(i-1)*ls%h1*bathymwater(i)%area_int
    x = y*gsp%z_full(i)
    zm = zm + row(i)*x
    x1 = x1 + row(i)*y
    zv = zv + x
    x2 = x2 + y
  enddo
  zm = zm/x1
  zv = zv/x2

  LakeNumber = (zm - zv)*ls%vol*row0*g*2.*H_mixed_layer / &
  &            (zv*(tau+small_value)*bathymwater(1)%area_int* &
  &            max(bathymwater(1)%Lx,bathymwater(1)%Ly))

  LakeNumber = max(min(LakeNumber,1.e+2_ireals),1.e-2_ireals)

  Rossby_rad = sqrt(g*max(row(M+1) - row(1),small_value)/row0*H_mixed_layer)/max(kor,small_value)

  ! Thermocline thickness
  x1 = 0.; x2 = ls%h1
  u1 = 0.; u2 = 0.
  v1 = 0.; v2 = 0.
  Sal1 = 0.; Sal2 = 0.
  do i = 1, M
    if (wst%Tw2(i) >= Ttherm0 .and. wst%Tw2(i+1) < Ttherm0) then
      y = gsp%ddz(i)*ls%h1
      x1 = gsp%z_full(i) + (wst%Tw2(i) - Ttherm0)*y/(wst%Tw2(i) - wst%Tw2(i+1))
      x = ( x1 - gsp%z_full(i) )/y
      u1 = wst%u2(i) + x*( wst%u2(i+1) - wst%u2(i) )
      v1 = wst%v2(i) + x*( wst%v2(i+1) - wst%v2(i) )
      Sal1 = wst%Sal2(i) + x*( wst%Sal2(i+1) - wst%Sal2(i) )
    endif
    if (wst%Tw2(i) >= Ttherm1 .and. wst%Tw2(i+1) < Ttherm1) then
      y = gsp%ddz(i)*ls%h1
      x2 = gsp%z_full(i) + (wst%Tw2(i) - Ttherm1)*y/(wst%Tw2(i) - wst%Tw2(i+1))
      x = ( x2 - gsp%z_full(i) )/y
      u2 = wst%u2(i) + x*( wst%u2(i+1) - wst%u2(i) )
      v2 = wst%v2(i) + x*( wst%v2(i+1) - wst%v2(i) )
      Sal2 = wst%Sal2(i) + x*( wst%Sal2(i+1) - wst%Sal2(i) )
    endif
  enddo
  ThermThick = x2 - x1 

  ReTherm = sqrt((u2 - u1)*(u2 - u1) + (v2 - v1)*(v2 - v1))*ThermThick / niu_wat

  RiTherm = g/row0*(DDENS_DTEMP0*(Ttherm1 - Ttherm0) + DDENS_DSAL0*(Sal2 - Sal1))*ThermThick / &
  & ( (u2 - u1)*(u2 - u1) + (v2 - v1)*(v2 - v1) + small_value)

  ! Rp: ratio of density increments by salinity and temperature,
  ! Rpdens : ratio of density fluxes caused by salinity and temperature fluxes
  do i = 1, M
    x1 = SET_DDENS_DTEMP(eos%par,lindens%par,0.5*(wst%Tw2(i+1) + wst%Tw2(i)), &
    & 0.5*(wst%Sal2(i+1) + wst%Sal2(i)))
    x2 = SET_DDENS_DSAL(eos%par,lindens%par, 0.5*(wst%Tw2(i+1) + wst%Tw2(i)), &
    & 0.5*(wst%Sal2(i+1) + wst%Sal2(i)))
    trb%Rp(i) = - x2/x1*(wst%Sal2(i+1) - wst%Sal2(i))/(wst%Tw2(i+1) - wst%Tw2(i) + small_value)
    trb%Rpdens(i) = - wst%lamsal(i)/wst%lamw(i)*x2/x1* &
    & (wst%Sal2(i+1) - wst%Sal2(i))/(wst%Tw2(i+1) - wst%Tw2(i) + small_value)
  enddo

  !if (Wedderburn < 0) then
  !print*, Wedderburn, (row(M+1) - row(1)), tau
  !read*
  !endif
 
  END SUBROUTINE TURB_SCALES


  SUBROUTINE MIXED_LAYER_CALC(row,ddz,ddz2,dzeta_int,dzeta_05int,h,M, &
  & i_mixed_layer,H_mixed_layer,maxN)

  ! Subroutine calculates the mixed-layer depth

  use PHYS_CONSTANTS, only: &
  & g, &
  & row0

  implicit none

! Input variables
  real(kind=ireals), intent(in) :: row (1:M+1)
  real(kind=ireals), intent(in) :: ddz(1:M)
  real(kind=ireals), intent(in) :: ddz2(1:M-1)
  real(kind=ireals), intent(in) :: dzeta_int(1:M+1)
  real(kind=ireals), intent(in) :: dzeta_05int(1:M)
 
  real(kind=ireals), intent(in) :: h

  integer(kind=iintegers), intent(in) :: M

! Output variables
  integer(kind=iintegers), intent(out) :: i_mixed_layer
  real(kind=ireals), intent(out) :: H_mixed_layer
  real(kind=ireals), intent(out) :: maxN

! Local variables
  integer(kind=iintegers) :: i, ml
  real(kind=ireals) :: a, b, c, x1, x2

  real(kind=ireals), allocatable :: bvf(:)

! Mixed-layer depth - depth of maximal heat flux
!  maxlocat = 1
!  do i = 2, M
!    if (k_turb_T_flux(i) + T_massflux(i) > &
!    & k_turb_T_flux(maxlocat) + T_massflux(maxlocat)) maxlocat = i
!  enddo
!  H_mixed_layer = dzeta_05int(maxlocat)*h1

  allocate (bvf(1:M))      
  do i = 1, M
    bvf(i) = g/row0*(row(i+1) - row(i))/(h*ddz(i))
  enddo

  ! Mixed-layer depth - depth of maximal Bruent-Vaisala frequency
  ml = maxloc(bvf,1) !+ lbound(bvf,1) - 1
  maxN = sqrt(max(bvf(ml),0._ireals))

  if ((row(M) - row(1))/row0 < 1.E-3) ml = M

  !! Mixed-layer depth as a depth of sharp increase of static stability
  !ml = M
  !do i = ml, 1, -1
  !  if (abs(bvf(i)/bvf(ml)) < 7.E-1_ireals) then
  !    ml = i
  !    exit
  !  endif
  !enddo

  ! Maximum of quadratic function
  !if (ml >= 2 .and. ml <= M-1) then
  !  x1 = (bvf(ml+1) - bvf(ml)  )/(h*(dzeta_05int(ml+1) - dzeta_05int(ml  )))
  !  x2 = (bvf(ml)   - bvf(ml-1))/(h*(dzeta_05int(ml  ) - dzeta_05int(ml-1)))
  !  a =   ( x1 - x2 ) / (h*(dzeta_05int(ml+1) - dzeta_05int(ml-1)))
  !  b =   x1 - a*(h*(dzeta_05int(ml+1) + dzeta_05int(ml  )))
  !  H_mixed_layer = - 0.5*b/a
  !else
    H_mixed_layer = dzeta_05int(ml)*h
  !endif
  deallocate (bvf)

  i_mixed_layer = ml

  !if (H_mixed_layer < 0.05) then
  !  H_mixed_layer = dzeta_05int(M)*h
  !  i_mixed_layer = M
  !endif

  ! H_mixed_layer = dzeta_int(ml)*h

  END SUBROUTINE MIXED_LAYER_CALC


  !> The function W_SEDIM calculates the sedimentation speed
  !! of organic particles, following Song et al., 2008, 
  !! DOI: 10.3882/j. issn. 1674-2370.2008.01.005
  FUNCTION W_SEDIM(d,ind)
     
  use PHYS_CONSTANTS, only : g, niu_wat

  implicit none

  ! Input variables
  !> Particle diameter, m
  real(kind=ireals), intent(in) :: d
  !> Switch between \f$Re\rightarrow 0\f$ and \f$Re \geq 10^5\f$ limits
  integer(kind=iintegers), intent(in) :: ind

  ! Output variables
  !> Sedimentation speed, m/s
  real(kind=ireals) :: W_SEDIM

  ! Local variables
  real(kind=ireals), parameter :: A = 30., B = 1.25 
  real(kind=ireals), parameter :: delta = 0.25 ! Density parameter for organic particles, Avnimelech et al. 2001

  real(kind=ireals), save :: A1, B1
  logical, save :: firstcall = .true.

  if (firstcall) then
    A1 = 4.*delta*g/(3.*A*niu_wat) 
    B1 = 4.*delta*g/(3.*B)
  endif

  if     (ind == 1) then
    W_SEDIM = A1*d*d
  elseif (ind == 2) then
    W_SEDIM = sqrt(B1*d)
  endif

  if (firstcall) firstcall = .false.
  END FUNCTION W_SEDIM


  FUNCTION SHORTRAD(shortrad0,z)

  implicit none

  real(kind=ireals), intent(in) :: shortrad0 ! Radiation at the surface
  real(kind=ireals), intent(in) :: z ! depth, m

! Shortwave radiation in water column from Arctic ocean model by N.Yakovlev
! Penetrating into ocean radiation parameters (Paulson&Simpson, 1977).
  real(kind=ireals), parameter :: Ra = 0.68 ! Fraction of light frequency radiation
  real(kind=ireals), parameter :: dzi1 = 1.2 ! Penetration of high frequency, m
  real(kind=ireals), parameter :: dzi2 = 28. ! Penetration of low frequency, m

  real(kind=ireals) :: SHORTRAD

  SHORTRAD = shortrad0*(Ra*exp(-z/dzi1)+(1.-Ra)*exp(-z/dzi2))

  END FUNCTION SHORTRAD


  FUNCTION WATER_ALBEDO(sinh0)
  implicit none

  real(kind=ireals) :: WATER_ALBEDO

! Input variables
  real(kind=ireals), intent(in) :: sinh0

! Local variables
  real(kind=ireals), parameter :: const1 = 0.05d0
  real(kind=ireals), parameter :: const2 = 0.15d0

  WATER_ALBEDO = const1/(sinh0 + const2)

  END FUNCTION WATER_ALBEDO


  FUNCTION F_AI(T,h)
! Ice albedo, from Arctic ocean model by N.Yakovlev
  implicit none 

! Input variables
  real(kind=ireals), intent(in) :: T, h

  real(kind=ireals) :: F_AI
  real(kind=ireals), parameter :: aow = 0.10, & ! AOMIP
  &                     ai = 0.65 ! Boulder Ice CCSM3 (Ice version 4, 2002) 

  if (T .LT. -1.0)then ! -1C - see BoulderIce 
    if (h .LE. 50.)then ! see BoulderIce - this is a good approx.
      F_ai=aow +(ai-aow)*h/50.
    else
      F_ai= ai
    end if
  else
    if(h.LE.50.)then ! see BoulderIce - this is a good approx.
      F_ai=aow +(ai-0.075*(T+1.)-aow)*h/50. 
    else
      F_ai= ai -0.075*(T+1.)
    end if
  end if

  return
  END FUNCTION F_AI
 
  
  FUNCTION F_AS(T)
! Snow albedo, from Arctic ocean model by N.Yakovlev
  if(T .LT. -1.0)then ! -1C - see BoulderIce

    F_as=0.80 ! Old Aomip, close to CCSM3

  else

    F_as=0.80 -0.1*(T+1.0) ! Pinto, 1999, SHEBA + Boulder Ice, CCSM3

  end if

  return
  END FUNCTION F_AS


  FUNCTION NETLWRAD(T,Ta,epsa,cloud,emis)
! Net longwave radiation at the surface, Rosati&Miyakoda, 1988
  use PHYS_CONSTANTS, only: &
  & sigma

  implicit none

  real(kind=ireals), intent(in) :: T ! Surface temperature, K
  real(kind=ireals), intent(in) :: Ta ! Air temperature, K
  real(kind=ireals), intent(in) :: epsa ! Water vapor pressure, Pa
  real(kind=ireals), intent(in) :: cloud ! Cloudiness, fraction
  real(kind=ireals), intent(in) :: emis ! Emissivity, fraction

  real(kind=ireals) :: NETLWRAD

  real(kind=ireals) :: AA, BB

  AA = emis*sigma*(0.39-0.005*sqrt(epsa))*(1.-0.8*cloud)
  BB = 4.*emis*sigma
  NETLWRAD = - (AA*T + BB*(T-Ta))*T**3 ! TC - corrected

  END FUNCTION NETLWRAD


  FUNCTION EXTINCT_SNOW(snow_density)
  implicit none

  real(kind=ireals) :: EXTINCT_SNOW

! Input variables
  real(kind=ireals), intent(in) :: snow_density ! Snow density, kg/m**3

! Local variables
  real(kind=ireals), parameter :: const1 = 0.13d0
  real(kind=ireals), parameter :: const2 = 3.4d0
  real(kind=ireals), parameter :: extinct_snow_max = 1.d+7

  EXTINCT_SNOW = exp(-(const1*snow_density+const2) )
  
! For Sparkling2002-2005 experiment
! EXTINCT_SNOW = exp(-extinct_snow_max)


  END FUNCTION EXTINCT_SNOW


  real(kind=ireals) FUNCTION UNFRWAT(T,i)
  use DRIVING_PARAMS
  use ARRAYS_SOIL, only : WLM0, WLM7
  
!CALCULATION OF LIQUID WATER CONTENT IN FREEZING SOIL
!T - DEG. C; WLM0,WLM7,WLMAX - KG/KG

  implicit none
  real(kind=ireals) T
  integer(kind=iintegers) i

  unfrwat = (WLM0(i)-WLM7(i))*exp(T/3.) + WLM7(i)
  !unfrwat = 0 
  
  RETURN
  END FUNCTION UNFRWAT


  real(kind=ireals) FUNCTION WL_MAX(por,rosdry,wi,mh)
  use PHYS_CONSTANTS, only: &
  & row0, &
  & roi
  use METH_OXYG_CONSTANTS, only : &
  & densmh
  implicit none
  real(kind=ireals), intent(in):: por,rosdry,wi,mh
  real(kind=ireals) :: work

  if (mh > 0.) then
    work = densmh
  else
    work = roi
  endif

  WL_MAX = por*row0/(rosdry*(1 - por)) - wi*row0/work
  END FUNCTION WL_MAX


  real(kind=ireals) FUNCTION WI_MAX(por,rosdry,mh)
  use PHYS_CONSTANTS, only: &
  & roi
  use METH_OXYG_CONSTANTS, only : &
  & densmh
  implicit none
  real(kind=ireals), intent(in):: por,rosdry,mh
  real(kind=ireals) :: work

  if (mh > 0.) then
    work = densmh
  else
    work = roi
  endif

  WI_MAX = por*work/(rosdry*(1 - por))
  END FUNCTION WI_MAX

  
  FUNCTION SOIL_COND_JOHANSEN(wl,wi,rosdry,por)
  
  use PHYS_CONSTANTS, only: &
  & row0, roi, &
  & row0_d_roi, roi_d_row0, &
  & lamw0, lami
  
  implicit none
  
  real(kind=ireals) :: SOIL_COND_JOHANSEN
  
! Input variables
  real(kind=ireals), intent(in) :: wl, wi ! liquid water and ice content 
                                ! (in respect to dry soil mass), kg/kg
  real(kind=ireals), intent(in) :: rosdry ! dry soil (soil particles) density, kg/m**3
  real(kind=ireals), intent(in) :: por ! soil porosity, m**3/m**3
  
! Local variables
  real(kind=ireals) :: water_vol_ratio, ice_vol_ratio ! water and ice volume ratio 
                                            ! (in respect to bulk soil volume), m**3/m**3
  real(kind=ireals) :: waterice_vol_ratio ! total volume ratio of water and ice, m**3/m**3
  real(kind=ireals) :: Kersten ! Kersten number, n/d
  real(kind=ireals) :: CK_const, CK_const1, CK_const2
  real(kind=ireals) :: lambda_sat, lambda_dry ! heat conduction coefficients for saturated
                                    ! and dry soil, W/(m*K)
                                    
  real(kind=ireals) :: water_sat_ratio, ice_sat_ratio                       
                   
  real(kind=ireals), save :: CK_consts(1:4) ! Cote and Konrad (2005) constants, n/d
  real(kind=ireals), save :: CK_consts1(1:3) ! Cote and Konrad (2005) constants, W/(m*K)
  real(kind=ireals), save :: CK_consts2(1:3) ! Cote and Konrad (2005) constants, n/d
  real(kind=ireals), save :: quartz_ratio ! quartz content of the total solids content
  real(kind=ireals), save :: lambda_quartz ! heat conduction coefficient for quartz, W/(m*K)
  real(kind=ireals), save :: lambda_othmin ! heat conduction coefficient for non-quartz
                                 ! minerals, W/(m*K)
  real(kind=ireals), save :: lambda_solids ! heat conduction coefficient for soild part
                                 ! of the soil, W/(m*K)
  
  logical, save :: firstcall = .true.
  
  if (firstcall) then
    CK_consts(1) = 4.6d0 ! for gravel and coarse sand
    CK_consts(2) = 3.55d0 ! for medium and fine sand
    CK_consts(3) = 1.9d0 ! silty and clay soils
    CK_consts(4) = 0.6d0 ! organic fibrous soils
    
    CK_consts1(1) = 1.7d0 ! for crashed rocks
    CK_consts1(2) = 0.75d0 ! for mineral soils
    CK_consts1(3) = 0.3d0 ! organic fibrous soils
    
    CK_consts2(1) = 1.8d0 ! for crashed rocks
    CK_consts2(2) = 1.2d0 ! for mineral soils
    CK_consts2(3) = 0.87d0 ! organic fibrous soils
    
    quartz_ratio = 0.1d0
    lambda_quartz = 7.7d0
    if (quartz_ratio > 0.2d0) then
      lambda_othmin = 2.d0
    else
      lambda_othmin = 3.d0
    endif
    lambda_solids = lambda_quartz**quartz_ratio * &
    &               lambda_othmin**(1.d0-quartz_ratio)
  endif
  
! Convertation from mass ratios to volume ratios      
  water_vol_ratio = wl / &
  & (por*(wl + row0/roi*wi + row0/rosdry))
  ice_vol_ratio = wi / &
  & (por*(wi + roi/row0*wl + roi/rosdry))
  
  waterice_vol_ratio = water_vol_ratio + ice_vol_ratio
  
  CK_const = CK_consts(3) ! silty and clay soils are assumed
  Kersten = CK_const*waterice_vol_ratio / &
  & (1.d0 + (CK_const - 1.d0)*waterice_vol_ratio)
  
  water_sat_ratio = por*water_vol_ratio/waterice_vol_ratio
  ice_sat_ratio = por*ice_vol_ratio/waterice_vol_ratio
  
! This is the original formula from Johansen (1975) extended for the case
! with the ice content
  lambda_sat = lambda_solids**(1.d0 - por) * &
  & lamw0**(water_sat_ratio)*lami**(ice_sat_ratio)
  
  CK_const1 = CK_consts1(2) ! mineral soils are assumed
  CK_const2 = CK_consts2(2) ! mineral soils are assumed
! Cote and Konrad (2005) formula for heat conduction coefficient of dry soil
  lambda_dry = CK_const1*10.d0**(-CK_const2*por)
  
! The normalized soil conductivity concept by Johansen (1975)      
  SOIL_COND_JOHANSEN = (lambda_sat - lambda_dry)*Kersten + lambda_dry
  
  if (firstcall) firstcall = .false.
  END FUNCTION SOIL_COND_JOHANSEN


  FUNCTION PRESMHYDRDISS(T,S)

  implicit none

  real(kind=ireals), intent(in) :: T ! Temperature, K
  real(kind=ireals), intent(in) :: S ! Salinity, ppt

  real(kind=ireals) :: PRESMHYDRDISS ! Pressure of lower limit of methane hydrate stability, Pa 
                           ! (Tishchenko et al. 2005)

  real(kind=ireals), parameter :: c1 = 1.6444866d+3, c2 = 0.1374178, c3 = 5.4979866d+4
  real(kind=ireals), parameter :: c4 = 2.64118188d+2, c5 = 1.1178266d+4, c6 = 7.67420344
  real(kind=ireals), parameter :: c7 = 4.515213d-3, c8 = 2.04872879d+5, c9 = 2.17246046d+3
  real(kind=ireals), parameter :: c10 = 1.70484431d+2, c11 = 0.118594073, c12 = 7.0581304d-5
  real(kind=ireals), parameter :: c13 = 3.09796169d+3, c14 = 33.2031996 

  real(kind=ireals) :: logpres

  logpres =  - c1 - c2*T + &
  & c3/T + c4*log(T) + S* &
  & (c5 + c6*T - c7*T**2 - c8/T - c9*log(T)) + S**2* &
  & (c10 + c11*T - c12*T**2 - c13/T - c14*log(T))
  PRESMHYDRDISS = exp(logpres)*1.d+6 !Converting to Pa

  END FUNCTION PRESMHYDRDISS



  FUNCTION TEMPMHYDRDISS(p)

! The temperature (K) of methane hydrate dissociation in seawater 
! at 35 ppt salinity according to (Dickens and Quinby-Hunt, 1994, GRL)
  use PHYS_CONSTANTS, only : &
  & Kelvin0

  implicit none

  real(kind=ireals), intent(in) :: p ! Pressure, Pa

  real(kind=ireals) :: TEMPMHYDRDISS

  real(kind=ireals), parameter ::  c1 = 3.79E-3, c2 = 2.83E-4

  TEMPMHYDRDISS = 1./(c1 - c2*log10(p*1.E-6)) - Kelvin0

  END FUNCTION TEMPMHYDRDISS


  FUNCTION MELTINGPOINT(S,p,methhydr)

  use DRIVING_PARAMS, only : nmeltpoint

  implicit none

  real(kind=ireals), intent(in) :: S, p 
  real(kind=ireals), intent(in) :: methhydr
  real(kind=ireals) :: MELTINGPOINT

  if (methhydr > 0.) then
    MELTINGPOINT = TEMPMHYDRDISS(p)
  else
    MELTINGPOINT = MELTPNT(S,p,nmeltpoint%par)
  endif

  END FUNCTION MELTINGPOINT


  !> Function calculates ice salinity at the phase change front
  !! according to V.L.Tsurikov (Nazintsev and Panov, 2000)
  FUNCTION SALICEBOT(dhbdt,salwat,por)
  use PHYS_CONSTANTS, only : row0, roi
  implicit none
  !>Input/output variables
  real(kind=ireals), intent(in) :: dhbdt !> the rate of water freeze at the phase change front, m/s
  real(kind=ireals), intent(in) :: salwat !> water salinity below the phase change front, kg/kg
  real(kind=ireals), intent(in) :: por  !> ice porosity, m**3/m**3
  real(kind=ireals) :: SALICEBOT

  !>Local variables
  real(kind=ireals), parameter :: alpha = 7., beta = 7., gamma_ = 10.3
  real(kind=ireals) :: w
  
  w = max(dhbdt,0._ireals)*3.6E+6 !Converting from m/s to mm/h

  SALICEBOT = (row0*por + (1.-por)*roi) * &
  &           salwat*alpha*sqrt(w)/(beta*sqrt(w) + gamma_) 

  END FUNCTION SALICEBOT


  FUNCTION REACPOT_ARRHEN &
  & (delta_E, temp, temp0, reacpot_arrhen0)

! The FUNCTION REACPOT_ARRHEN calculates the reaction potential
! according to Arrhenius equation

  use PHYS_CONSTANTS, only : &
  & R_univ

  implicit none      
  
! Input variables
  real(kind=ireals), intent(in) :: delta_E ! activation energy, J/mol
  real(kind=ireals), intent(in) :: temp    ! temperature, Kelvin
  real(kind=ireals), intent(in) :: temp0   ! reference temperature, Kelvin
  real(kind=ireals), intent(in) :: reacpot_arrhen0 ! reaction potential at the
                                         ! reference temeperature, mol/(m**3*s)
                                         
! Output variables
  real(kind=ireals) :: REACPOT_ARRHEN
  
! Local variables and constants
  
  REACPOT_ARRHEN = &
  & reacpot_arrhen0*exp(delta_E/R_univ*(1./temp0 - 1./temp))
  
  END FUNCTION REACPOT_ARRHEN
  
  
  FUNCTION HENRY_CONST(henry_const0, temp_dep, temp_ref, temp) !, radius)
  
  ! Function HENRY_CONST calculates the Henry constant of a substance for a given temperature
  
  use PHYS_CONSTANTS, only : &
  & surf_tension_wat, R_univ

  implicit none
  
  real(kind=ireals) :: HENRY_CONST
  
  ! Input variables
  real(kind=ireals), intent(in) :: henry_const0 ! Henry constant at the reference temperature, mol/(m**3*Pa)
  real(kind=ireals), intent(in) :: temp_dep ! Temperature dependence (enthalpy solution devided by universal gas constant), K
  real(kind=ireals), intent(in) :: temp_ref ! Reference temperature, K
  real(kind=ireals), intent(in) :: temp ! Temperature, K
!  real(kind=ireals), intent(in) :: radius ! Curvature radius, m, positive for drops, negative for bubbles and zero for flat surface
  
  HENRY_CONST = henry_const0*exp(temp_dep*(1./temp-1./temp_ref))
! Effect of bubble surface curvatue on saturation pressure
!  if (radius /= 0.d0) HENRY_CONST = HENRY_CONST* &
!  & exp(-2.*surf_tension_wat*mol_vol_water/(radius*R_univ*temp))
  
  END FUNCTION HENRY_CONST


  !> Function HC_CORR_CARBEQUIL returns a correction multiplier for 
  !! CO_2 Henry constant to get solubulity, taking into account
  !! carbonate equilibrium.
  !! \f[
  !! HC\_CORR\_CARBEQUIL = (1+k_1 10^{pH}+k_1*k_2 10^{2pH})
  !! \f]
  !! Concomitantly, it is a ratio of DIC to CO_2 molar concenatrations.
  !! DIC molar concentration is a molar concentration of C atoms in DIC.
  FUNCTION HC_CORR_CARBEQUIL(temp,pH)

  implicit none

  !Input variables
  !>Water temperature, deg. Kelvin
  real(kind=ireals), intent(in) :: temp 
  !>pH
  real(kind=ireals), intent(in) :: pH 

  real(kind=ireals) :: HC_CORR_CARBEQUIL

  !Local variables
  real(kind=ireals), parameter :: k1_0 = 4.3E-7, k2_0 = 4.7E-11
  real(kind=ireals), parameter :: Eact_d_RT_1 = 921.4, Eact_d_RT_2 = 1787.4
  real(kind=ireals), parameter :: temp_ref = 298.

  real(kind=ireals) :: k1,k2

  k1 = k1_0*exp( - Eact_d_RT_1 * (1./temp - 1./temp_ref) )
  k2 = k2_0*exp( - Eact_d_RT_2 * (1./temp - 1./temp_ref) )
  HC_CORR_CARBEQUIL = (1. + k1*10._ireals**(pH) + k1*k2*10._ireals**(2*pH))

  END FUNCTION HC_CORR_CARBEQUIL


  FUNCTION DIFF_WATER_OXYGEN(temp_C)
  
  ! Function DIFF_WATER_OXYGEN calculates the molecular diffusivity 
  ! of oxygen dissolved in liquid water, m**2/s
  ! (Broecker and Peng, 1974)
  
  implicit none
  
  real(kind=ireals) :: DIFF_WATER_OXYGEN
  
  ! Input variables
  real(kind=ireals), intent(in) :: temp_C ! temperature, degrees Celsius

  ! Local variables
  real(kind=ireals), parameter :: const1 = 1.11d-9
  real(kind=ireals), parameter :: const2 = 4.96d-11
  
  DIFF_WATER_OXYGEN = const1 + const2*temp_C
   
  END FUNCTION DIFF_WATER_OXYGEN

  
  FUNCTION DIFF_WATER_METHANE(temp_C)
  
  ! Function DIFF_WATER_METHANE calculates the molecular diffusivity 
  ! of methane dissolved in liquid water, m**2/s
  ! (Broecker and Peng, 1974)
  
  implicit none
  
  real(kind=ireals) :: DIFF_WATER_METHANE
  
  ! Input variables
  real(kind=ireals), intent(in) :: temp_C ! temperature, degrees Celsius

  ! Local variables
  real(kind=ireals), parameter :: const1 = 9.798d-10
  real(kind=ireals), parameter :: const2 = 2.986d-11
  real(kind=ireals), parameter :: const3 = 4.381d-13
  
  DIFF_WATER_METHANE = const1 + const2*temp_C + const3*temp_C*temp_C
   
  END FUNCTION DIFF_WATER_METHANE
  
  
  FUNCTION DIFF_AIR_METHANE(temp_C)
  
  ! Function DIFF_WATER_METHANE calculates the molecular diffusivity 
  ! of methane dissolved in liquid water, m**2/s
  ! (Lerman, 1979)
  
  implicit none
  
  real(kind=ireals) :: DIFF_AIR_METHANE
  
  ! Input variables
  real(kind=ireals), intent(in) :: temp_C ! temperature, degrees Celsius

  ! Local variables
  real(kind=ireals), parameter :: const1 = 1.875d-5
  real(kind=ireals), parameter :: const2 = 1.3d-7
  
  DIFF_AIR_METHANE = const1 + const2*temp_C
   
  END FUNCTION DIFF_AIR_METHANE

  
  FUNCTION DIFF_WATER_CARBDI(temp_C)
  
  ! Function DIFF_WATER_CARBDI calculates the molecular diffusivity 
  ! of crabon dioxide dissolved in liquid water, m**2/s
  ! (Broecker and Peng, 1974)
  
  implicit none
  
  real(kind=ireals) :: DIFF_WATER_CARBDI
  
  ! Input variables
  real(kind=ireals), intent(in) :: temp_C ! temperature, degrees Celsius

  ! Local variables
  real(kind=ireals), parameter :: const1 = 9.39d-10
  real(kind=ireals), parameter :: const2 = 2.671d-11
  real(kind=ireals), parameter :: const3 = 4.095d-13
  
  DIFF_WATER_CARBDI = const1 + const2*temp_C + const3*temp_C*temp_C
   
  END FUNCTION DIFF_WATER_CARBDI

  
  FUNCTION DIFF_AIR_CARBDI(temp_C)
  
  ! Function DIFF_WATER_CARBDI calculates the molecular diffusivity 
  ! of carbon dioxide dissolved in liquid water, m**2/s
  ! (Lerman, 1979)
  
  implicit none
  
  real(kind=ireals) :: DIFF_AIR_CARBDI
  
  ! Input variables
  real(kind=ireals), intent(in) :: temp_C ! temperature, degrees Celsius

  ! Local variables
  real(kind=ireals), parameter :: const1 = 1.35d-5
  real(kind=ireals), parameter :: const2 = 0.9d-7
        
  DIFF_AIR_CARBDI = const1 + const2*temp_C
   
  END FUNCTION DIFF_AIR_CARBDI
  
  
  FUNCTION SCHMIDT_NUMBER_METHANE(tempC)
  
  implicit none
  
  real(kind=ireals) :: SCHMIDT_NUMBER_METHANE
  
  ! Input variables      
  real(kind=ireals), intent(in) :: tempC
  
  ! Local variables
  real(kind=ireals), parameter :: const1 = 1.898d+3
  real(kind=ireals), parameter :: const2 = -1.101d+2
  real(kind=ireals), parameter :: const3 = 2.834
  real(kind=ireals), parameter :: const4 = -2.791d-2
  
  SCHMIDT_NUMBER_METHANE = &
  & const1 + const2*tempC + const3*tempC**2 + const4*tempC**3
  
  END FUNCTION SCHMIDT_NUMBER_METHANE
  
  
  FUNCTION SCHMIDT_NUMBER_OXYGEN(tempC)
  
  implicit none
  
  real(kind=ireals) :: SCHMIDT_NUMBER_OXYGEN
  
  ! Input variables      
  real(kind=ireals), intent(in) :: tempC
  
  ! Local variables
  real(kind=ireals), parameter :: const1 = 1.8006d+3
  real(kind=ireals), parameter :: const2 = -1.201d+2
  real(kind=ireals), parameter :: const3 = 3.7818
  real(kind=ireals), parameter :: const4 = -4.7608d-2
  
  SCHMIDT_NUMBER_OXYGEN = &
  & const1 + const2*tempC + const3*tempC**2 + const4*tempC**3
  
  END FUNCTION SCHMIDT_NUMBER_OXYGEN
  
  
  FUNCTION SCHMIDT_NUMBER_CARBDI(tempC)
  
  implicit none
  
  real(kind=ireals) :: SCHMIDT_NUMBER_CARBDI
  
  ! Input variables      
  real(kind=ireals), intent(in) :: tempC
  
  ! Local variables
  real(kind=ireals), parameter :: const1 = 1.911d+3
  real(kind=ireals), parameter :: const2 = -1.137d+2
  real(kind=ireals), parameter :: const3 = 2.967
  real(kind=ireals), parameter :: const4 = -2.943d-2
  
  SCHMIDT_NUMBER_CARBDI = &
  & const1 + const2*tempC + const3*tempC**2 + const4*tempC**3
  
  END FUNCTION SCHMIDT_NUMBER_CARBDI
  
  
  FUNCTION GAS_WATATM_FLUX &
  & (tempC,wind10,surf_conc,partial_pressure,henry_const,gasindic,eps)

  use PHYS_CONSTANTS, only: &
  & niu_wat
        
  ! Subroutine GAS_WATATM_FLUX calculates the upward gas flux at the water-air interface, mol/(m**2*s)
  ! following formulations by (McGillis et al., 2000; Cole and Caraco, 1998; Riera et al., 1999) 
  ! and others (described in Wania, 2007)
        
  implicit none
  
  real(kind=ireals) :: GAS_WATATM_FLUX
  
  ! Input variables
  real(kind=ireals), intent(in) :: tempC ! water surface temperature, Celsius
  real(kind=ireals), intent(in) :: wind10 ! wind speed at 10 m above the surface, m/s
  real(kind=ireals), intent(in) :: surf_conc ! gas concentration at the water surface, mol/m**3
  real(kind=ireals), intent(in) :: partial_pressure ! partial pressure of a gas in the atmosphere, Pa
  real(kind=ireals), intent(in) :: henry_const ! Henry constant of a gas, mol/(m**3*Pa)
  real(kind=ireals), intent(in) :: eps  ! kinetic energy dissipation
  
  integer(kind=iintegers), intent(in) :: gasindic ! gas indicator: methane - 8, oxygen - 9, carbon dioxide - 10
        
  ! Local constants
  real(kind=ireals), parameter :: constvel1 = 5.75d-6 !(Cole and Coraco et al.,1998) ! 3.78d-8 ! SI units
  real(kind=ireals), parameter :: constvel2 = 5.97d-7 !(Cole and Coraco et al.,1998) ! 1.36d-9 ! SI units
  real(kind=ireals), parameter :: c1 = 0.5 ! (JOUNI J. HEISKANEN et al., 2014)
  ! real(kind=ireals), parameter :: c1 = 1.2 (MacIntyre et al., 2010)
  real(kind=ireals), parameter :: Schmidt_scale = 600.
  real(kind=ireals), parameter :: Schmidt_number_min = 1.
  real(kind=ireals), parameter :: wind10_power = 1.7
  
  integer(kind=iintegers), parameter :: methane_indic = 8
  integer(kind=iintegers), parameter :: oxygen_indic = 9
  integer(kind=iintegers), parameter :: carbdi_indic = 10
  integer(kind=iintegers), parameter :: COLE_CARACO = 1 ! model depending on wind-speed (Cole and Coraco et al.,1998)
  integer(kind=iintegers), parameter :: SURFACE_RENEWAL = 2 ! surface renewal model (Soloviev and Schluessel, 1994;&
  ! & MacIntyre et al.,1995, 2001; Zappa et al., 2007; Turney and Banerjee,2008)
  
  ! Local variables
  real(kind=ireals) :: Schmidt_number
  real(kind=ireals) :: piston_velocity, piston_velocity600
  real(kind=ireals) :: surf_conc_atmequil

  integer(kind=iintegers) :: piston_velocity_model ! choice of model

  piston_velocity_model = SURFACE_RENEWAL

  if (piston_velocity_model == COLE_CARACO) then
    piston_velocity600 = constvel1 + constvel2*wind10**wind10_power
  elseif (piston_velocity_model == SURFACE_RENEWAL) then
    piston_velocity600 = c1*(eps*niu_wat)**0.25/sqrt(Schmidt_scale)
  endif
  
  ! piston_velocity600 = constvel1 + constvel2*wind10**wind10_power      
  if     (gasindic == methane_indic) then
    Schmidt_number = max(SCHMIDT_NUMBER_METHANE(tempC),Schmidt_number_min)
  elseif (gasindic == oxygen_indic) then
    Schmidt_number = max(SCHMIDT_NUMBER_OXYGEN(tempC),Schmidt_number_min)
  elseif (gasindic == carbdi_indic) then
    Schmidt_number = max(SCHMIDT_NUMBER_CARBDI(tempC),Schmidt_number_min)
  endif
  piston_velocity = piston_velocity600*sqrt(Schmidt_scale/Schmidt_number)
  surf_conc_atmequil = partial_pressure*henry_const
  GAS_WATATM_FLUX = piston_velocity*(surf_conc-surf_conc_atmequil)
  
  END FUNCTION GAS_WATATM_FLUX
  
  
  FUNCTION CHARNOCK_Z0(velfrict)

  use PHYS_CONSTANTS, only : &
  & g, niu_atm, const2 => charnock_const
  
  implicit none

  real(kind=ireals) :: CHARNOCK_Z0

  ! Input variables
  real(kind=ireals), intent(in) :: velfrict

  ! Local variables
  real(kind=ireals), parameter :: const1 = 0.111
  ! real(kind=ireals), parameter :: const2 = 0.0144
  ! real(kind=ireals), parameter :: const2 = 0.35
  real(kind=ireals), parameter :: roughness_min = 1.d-5
  real(kind=ireals), parameter :: roughness_max = 1.1d-1

  CHARNOCK_Z0 = &
  & min(max(const1*niu_atm/velfrict + const2*velfrict**2/g, &
  & roughness_min),roughness_max)

  END FUNCTION CHARNOCK_Z0


  FUNCTION DOMWAVESPEED(ufr,fetch)

! Calculating fetch-dependent dominant wave speed,
! following Wuest and Lorke (2003)

  use PHYS_CONSTANTS, only : &
  & g

  implicit none
  real(kind=ireals) :: DOMWAVESPEED

  ! Input variables
  real(kind=ireals), intent(in) :: ufr ! Friction velocity, m/s
  real(kind=ireals), intent(in) :: fetch ! Wind fetch, m

  ! Locals
  real(kind=ireals), parameter :: C1 = 0.051, C2 = 0.96
  real(kind=ireals), save :: C3
  logical, save :: firstcall = .true.

  if (firstcall) then
    C3 = (C1/C2)**(2./3.)
  endif

  DOMWAVESPEED = C3*(ufr*g*fetch)**(1./3.)

  if (firstcall) firstcall = .false.
  END FUNCTION DOMWAVESPEED


  FUNCTION H13(momentum_flux,fetch)

! Significant wave height, Hasselman et al. (1973)

  use PHYS_CONSTANTS, only : &
  & g, roa0

  implicit none
  
  real(kind=ireals) :: H13
 
! Input variables
  real(kind=ireals), intent(in) :: momentum_flux, fetch

! Locals
  real(kind=ireals), parameter :: const = 0.051

  H13 = const*sqrt(momentum_flux*fetch/(g*roa0))

  END FUNCTION H13



  FUNCTION LOGFLUX(vel, ds, z, z0, z0s, mult, ind)

  ! Computes a flux of substance in neutral (logarythmic) surface layer
  ! LOGFLUX is positive in the direction in respect to which the difference
  ! ds is taken

  use PHYS_CONSTANTS, only : &
  & kappa

  implicit none

  ! Input variables
  real(kind=ireals), intent(in) :: vel, ds, z, z0, z0s, mult
  integer(kind=iintegers), intent(in) :: ind
  
  ! Output varaible
  real(kind=ireals) :: LOGFLUX

  ! Local variables
  real(kind=ireals), save :: kappa2
  logical, save :: firstcall = .true.

  if (firstcall) kappa2 = kappa*kappa

  if (ind == 1) then ! return flux
    LOGFLUX = - mult*kappa2*vel*ds/(log(z/z0)*log(z/z0s))
  elseif (ind == 2) then ! return exchange coefficient
    LOGFLUX =   mult*kappa2*vel/(log(z/z0)*log(z/z0s))
  endif

  if (firstcall) firstcall = .false.
  END FUNCTION LOGFLUX


  FUNCTION TEMPWATR(kturb,rad,Tsoil,exchcoef,Tw,Tflux)

  ! Water temperature near lateral bottom from radial temperature
  ! profile scaling

  implicit none

  ! Input variables
  real(kind=ireals), intent(in) :: kturb,rad,Tsoil,exchcoef,Tw,Tflux

  ! Output variable
  real(kind=ireals) :: TEMPWATR

  ! Local variables
  real(kind=ireals) :: C = 1.e+1

  TEMPWATR = Tw + C*rad/kturb*(Tsoil*exchcoef - Tflux)/ & ! 
  &          (1 + C*rad/kturb*       exchcoef)

  !print*, Tsoil*exchcoef, Tflux

  END FUNCTION TEMPWATR


  !> Subroutine calculates background eddy diffusivity after (Hondzo and Stefan, 1993)
  SUBROUTINE DIFFMIN_HS(area,wst,gsp,ls,M)
  use PHYS_CONSTANTS, only : row0, g, cw_m_row0
  use ARRAYS_GRID, only : gridspacing_type
  use ARRAYS_WATERSTATE, only : waterstate_type
  use ARRAYS_BATHYM, only : layers_type
  use DRIVING_PARAMS, only : backdiff0
  implicit none
  !Input/output variables
  real(kind=ireals)     , intent(in) :: area
  type(waterstate_type) , intent(in) :: wst
  type(gridspacing_type), intent(in) :: gsp
  type(layers_type)     , intent(in) :: ls
  integer(kind=iintegers), intent(in) :: M
  !Local variables
  integer(kind=iintegers) :: i
  real(kind=ireals) :: x, y

  real(kind=ireals), parameter :: C1 = 8.17E-4, C2 = 0.56, C3 = -0.43, xmin = 7.E-5
  real(kind=ireals), save :: z !A multiplier in expression for background diffusivity
  logical, save :: firstcall = .true.

  if (firstcall) then
    if (backdiff0%par >= 0.) then
      z = backdiff0%par 
    else
      z = C1 !default value
    endif
  endif

  do i = 1, M
    x = g/row0*(wst%row(i+1)-wst%row(i))/(ls%h1*gsp%ddz(i))
    if (x <= 0.) then
      wst%lamw_back(i) = 0.
    else
      x = max(x, xmin)
      y = area*1.E-6 ! converting from m**2 to km**2
      wst%lamw_back(i) = z*(y)**C2 * x**C3
      wst%lamw_back(i) = wst%lamw_back(i) * 1.E-4 !converting from cm**2/s to m**2/s
      wst%lamw_back(i) = wst%lamw_back(i) * cw_m_row0
      wst%lamw_back(i) = wst%lamw_back(i) * 5.E-1 !Calibration multiplyer
    endif
  enddo

  if (firstcall) firstcall = .false.
  END SUBROUTINE DIFFMIN_HS


  !> Subroutine calculates background eddy diffusivity from KPP model 
  !! (Zhang et al., HESS, 2019 and references therein)
  SUBROUTINE DIFFMIN_KPP(wst,gsp,ls,M) 
  use PHYS_CONSTANTS, only : row0, g, cw_m_row0
  use ARRAYS_GRID, only : gridspacing_type
  use ARRAYS_WATERSTATE, only : waterstate_type
  use ARRAYS_BATHYM, only : layers_type
  use DRIVING_PARAMS, only : backdiff0
  implicit none
  !Input/output variables
  type(waterstate_type) , intent(inout) :: wst
  type(gridspacing_type), intent(in) :: gsp
  type(layers_type)     , intent(in) :: ls
  integer(kind=iintegers), intent(in) :: M
  !Local variables
  logical, save :: firstcall = .true.
  real(kind=ireals), parameter :: k0_default = 1.E-5, Ri0 = 7.E-1, p = 3.
  real(kind=ireals), save :: k0
  real(kind=ireals) :: x, y, Ri, dz
  integer(kind=iintegers) :: i !Loop index

  if (firstcall) then
    if (backdiff0%par >= 0.) then
      k0 = backdiff0%par 
    else
      k0 = k0_default !default value
    endif
  endif

  do i = 1, M
    dz = ls%h1*gsp%ddz(i)
    !Brunt-Vaisala frequency squared
    x = g/row0*(wst%row(i+1) - wst%row(i)) / dz
    !Shear frequency squared
    y = ( (wst%u1(i+1) - wst%u1(i))**2 + (wst%v1(i+1) - wst%v1(i))**2 ) / dz**2
    !Gradient Richardson number
    Ri = x / y
    if     (Ri <= 0.) then
      wst%lamw_back(i) = k0
    elseif (Ri < Ri0) then
      wst%lamw_back(i) = k0*(1. - (Ri/Ri0)**2)**p
    else
      wst%lamw_back(i) = 0.
    endif
  enddo
  wst%lamw_back(:) = wst%lamw_back(:) * cw_m_row0

  if (firstcall) firstcall = .false.
  END SUBROUTINE DIFFMIN_KPP

  !> Function HORIZCONC returns a value of dissolved concentration in the mixed layer
  !! at distance r from center of circular lake; according to 
  !! (DelSontro et al., Ecosystems, 2018) extended by inclusion of linear sink term
  FUNCTION HORIZCONC(Caver,r,rL,kdiff,kexch,ksink,hML) result(Cr)
  use NUMERICS, only : BESSI !Bessel function
  implicit none
  !Input/output variables
  real(kind=ireals), intent(in) :: Caver !> horizontally averaged concentration in the ML
  real(kind=ireals), intent(in) :: r     !> distance form lake center, m
  real(kind=ireals), intent(in) :: rL    !> lake radius, m
  real(kind=ireals), intent(in) :: kdiff !> effective diffusion coefficient in horizontal, m**2/s
  real(kind=ireals), intent(in) :: kexch !> gas exchange koefficient with the atmosphere (piston velocity), m/s
  real(kind=ireals), intent(in) :: ksink !> the rate of concentration sink in the ML, s**(-1)
  real(kind=ireals), intent(in) :: hML   !> mixed-layer (ML) depth
  real(kind=ireals)             :: Cr    !> concentration at the distance r from lake center
  !Local variables
  real(kind=ireals) :: x
  x = sqrt((kexch/hML+ksink)/kdiff)
  Cr = 0.5*Caver*rL*BESSI(0_4,x*r)/BESSI(1_4,x*rL)
  END FUNCTION HORIZCONC

  END MODULE PHYS_FUNC