From 93ffc2f0a80519746971a18f22292a02ddc3b21a Mon Sep 17 00:00:00 2001
From: Evgeny Mortikov <evgeny.mortikov@gmail.com>
Date: Sun, 17 Dec 2023 21:16:45 +0300
Subject: [PATCH] major code update

---
 COMP_DRAG.txt                 |   2 +-
 compile2.sh                   |  11 +-
 drag3.f90                     | 505 -----------------------------
 makefile                      |   4 +-
 param.f90                     |  69 ----
 sfx_esm.f90                   | 593 ++++++++++++++++++++++++++++++++++
 sfx_esm_param.f90             |  71 ++++
 main_drag.f90 => sfx_main.f90 | 100 +++---
 sfx_phys_const.f90            |  12 +
 9 files changed, 734 insertions(+), 633 deletions(-)
 delete mode 100644 drag3.f90
 delete mode 100644 param.f90
 create mode 100644 sfx_esm.f90
 create mode 100644 sfx_esm_param.f90
 rename main_drag.f90 => sfx_main.f90 (62%)
 create mode 100644 sfx_phys_const.f90

diff --git a/COMP_DRAG.txt b/COMP_DRAG.txt
index 8e9d5fc..0dd43a3 100644
--- a/COMP_DRAG.txt
+++ b/COMP_DRAG.txt
@@ -1,4 +1,4 @@
-ifort -c inputdata.f90
+fort -c inputdata.f90
 ifort -c param.f90
 ifort -c prmt.f90
 ifort -c drag3.F 
diff --git a/compile2.sh b/compile2.sh
index e874355..0e6d889 100755
--- a/compile2.sh
+++ b/compile2.sh
@@ -1,9 +1,10 @@
 #!/bin/bash
 
 rm drag_ddt.exe *.o
-gfortran -c -Wuninitialized inputdata.f90
-gfortran -c -Wuninitialized param.f90
-gfortran -c -Wuninitialized drag3.f90
-gfortran -c -Wuninitialized main_drag.f90
-gfortran -o drag_ddt.exe main_drag.o drag3.o  inputdata.o param.o 
+gfortran -c -cpp -Wuninitialized inputdata.f90
+gfortran -c -cpp -Wuninitialized sfx_phys_const.f90
+gfortran -c -cpp -Wuninitialized sfx_esm_param.f90
+gfortran -c -cpp -Wuninitialized sfx_esm.f90
+gfortran -c -Wuninitialized sfx_main.f90
+gfortran -o drag_ddt.exe sfx_main.o sfx_esm.o inputdata.o sfx_esm_param.o sfx_phys_const.o
 
diff --git a/drag3.f90 b/drag3.f90
deleted file mode 100644
index c93706f..0000000
--- a/drag3.f90
+++ /dev/null
@@ -1,505 +0,0 @@
-    MODULE drag3
-        USE param
-
-        implicit none
-
-        type, public :: meteoDataType
-            real :: h       ! constant flux layer height [m]
-            real :: U       ! abs(wind speed) at 'h' [m/s]
-            real :: dT      ! difference between potential temperature at 'h' and at surface [K]
-            real :: Tsemi   ! semi-sum of potential temperature at 'h' and at surface [K]
-            real :: dQ      ! difference between humidity at 'h' and at surface [g/g]
-            real :: z0_m    ! surface aerodynamic roughness (should be < 0 for water bodies surface)
-        end type
-
-        type, public :: meteoDataVecType
-            real, allocatable :: h(:)       ! constant flux layer height [m]
-            real, allocatable :: U(:)       ! abs(wind speed) at 'h' [m/s]
-            real, allocatable :: dT(:)      ! difference between potential temperature at 'h' and at surface [K]
-            real, allocatable :: Tsemi(:)   ! semi-sum of potential temperature at 'h' and at surface [K]
-            real, allocatable :: dQ(:)      ! difference between humidity at 'h' and at surface [g/g]
-            real, allocatable :: z0_m(:)    ! surface aerodynamic roughness (should be < 0 for water bodies surface)
-        end type
-
-        type, public :: sfxDataType
-            real :: zeta            ! = z/L [n/d]
-            real :: Rib             ! bulk Richardson number [n/d]
-            real :: Re              ! Reynolds number [n/d]
-            real :: lnzuzt
-            real :: z0_m            ! aerodynamic roughness [m]
-            real :: z0_t            ! thermal roughness [m]
-            real :: Rib_conv_lim    ! Ri-bulk convection critical value [n/d]
-            real :: cm
-            real :: ch
-            real :: ct
-            real :: ckt
-        end type
-
-        type, public :: numericsType
-            integer :: maxiters_convection = 10    ! maximum (actual) number of iterations in convection
-            integer :: maxiters_charnock = 10      ! maximum (actual) number of iterations in charnock roughness
-        end type
-
-        type, public:: data_lutyp
-            integer, public :: lu_indx=1
-        end type
-
-    contains
-
-        subroutine surf_flux_vec(meteo, &
-                masout_zl,  masout_ri, masout_re, masout_lnzuzt, masout_zu, masout_ztout,&
-                masout_rith, masout_cm, masout_ch, masout_ct, masout_ckt,&
-                numerics, lu1,numst)
-
-            type (meteoDataVecType), intent(in) :: meteo
-            type (numericsType), intent(in) :: numerics
-
-            real, dimension (numst) :: masout_zl
-            real, dimension (numst) :: masout_ri
-            real, dimension (numst) :: masout_re
-            real, dimension (numst) :: masout_lnzuzt
-            real, dimension (numst) :: masout_zu
-            real, dimension (numst) :: masout_ztout
-            real, dimension (numst) :: masout_rith
-            real, dimension (numst) :: masout_cm
-            real, dimension (numst) :: masout_ch
-            real, dimension (numst) :: masout_ct
-            real, dimension (numst) :: masout_ckt
-
-            type (meteoDataType)  meteo_cell
-            type (sfxDataType) sfx_cell
-
-            type (data_lutyp) lu1
-            integer i,numst
-
-            do i = 1, numst
-                meteo_cell = meteoDataType(&
-                        h = meteo%h(i), &
-                        U = meteo%U(i), dT = meteo%dT(i), Tsemi = meteo%Tsemi(i), dQ = meteo%dQ(i), &
-                        z0_m = meteo%z0_m(i))
-
-                call surf_flux(meteo_cell, sfx_cell, numerics, lu1)
-
-                masout_zl(i)=sfx_cell%zeta
-                masout_ri(i)=sfx_cell%Rib
-                masout_re(i)=sfx_cell%Re
-                masout_lnzuzt(i)=sfx_cell%lnzuzt
-                masout_zu(i)=sfx_cell%z0_m
-                masout_ztout(i)=sfx_cell%z0_t
-                masout_rith(i)=sfx_cell%Rib_conv_lim
-                masout_cm(i)=sfx_cell%cm
-                masout_ch(i)=sfx_cell%ch
-                masout_ct(i)=sfx_cell%ct
-                masout_ckt(i)=sfx_cell%ckt
-            enddo
-        END SUBROUTINE  surf_flux_vec
-
-        function f_m_conv(zeta)
-            real f_m_conv
-            real zeta
-
-            f_m_conv = (1.0 - alpha_m * zeta)**0.25
-
-        end function f_m_conv
-
-        function f_h_conv(zeta)
-            real f_h_conv
-            real zeta
-
-            f_h_conv = (1.0 - alpha_h * zeta)**0.5
-
-        end function f_h_conv
-
-
-        ! stability functions (neutral)
-        ! --------------------------------------------------------------------------------
-        subroutine get_psi_neutral(psi_m, psi_h, zeta, h0_m, h0_t, B)
-            ! ----------------------------------------------------------------------------
-            real, intent(out) :: psi_m, psi_h, zeta
-            real, intent(in) :: h0_m, h0_t
-            real, intent(in) :: B
-            ! ----------------------------------------------------------------------------
-
-            zeta = 0.0
-            psi_m = log(h0_m)
-            psi_h = log(h0_t) / Pr_t_0_inv
-            if (abs(B) < 1.0e-10) psi_h = psi_m / Pr_t_0_inv
-
-        end subroutine
-        ! --------------------------------------------------------------------------------
-
-        ! stability functions (stable)
-        ! --------------------------------------------------------------------------------
-        subroutine get_psi_stable(psi_m, psi_h, zeta, Rib, h0_m, h0_t, B)
-            ! ----------------------------------------------------------------------------
-            real, intent(out) :: psi_m, psi_h, zeta
-            real, intent(in) :: Rib
-            real, intent(in) :: h0_m, h0_t
-            real, intent(in) :: B
-
-            real :: Rib_coeff
-            real :: psi0_m, psi0_h
-            real :: phi
-            real :: c
-            ! ----------------------------------------------------------------------------
-
-            psi0_m = alog(h0_m)
-            psi0_h = B / psi0_m
-
-            Rib_coeff = beta_m * Rib
-            c = (psi0_h + 1.0) / Pr_t_0_inv - 2.0 * Rib_coeff
-            zeta = psi0_m * (sqrt(c**2 + 4.0 * Rib_coeff * (1.0 - Rib_coeff)) - c) / &
-                    (2.0 * beta_m * (1.0 - Rib_coeff))
-
-            phi = beta_m * zeta
-
-            psi_m = psi0_m + phi
-            psi_h = (psi0_m + B) / Pr_t_0_inv + phi
-
-        end subroutine
-        ! --------------------------------------------------------------------------------
-
-        ! stability functions (convection-semistrong)
-        ! --------------------------------------------------------------------------------
-        subroutine get_psi_semi_convection(psi_m, psi_h, zeta, Rib, h0_m, h0_t, B, maxiters)
-            ! ----------------------------------------------------------------------------
-            real, intent(out) :: psi_m, psi_h, zeta
-            real, intent(in) :: Rib
-            real, intent(in) :: h0_m, h0_t
-            real, intent(in) :: B
-            integer, intent(in) :: maxiters
-
-            real :: zeta0_m, zeta0_h
-            real :: x0, x1, y0, y1
-
-            integer :: i
-            ! ----------------------------------------------------------------------------
-
-            psi_m = log(h0_m)
-            psi_h = log(h0_t)
-            if (abs(B) < 1.0e-10) psi_h = psi_m
-
-            zeta = Rib * Pr_t_0_inv * psi_m**2 / psi_h
-
-            do i = 1, maxiters + 1
-                zeta0_m = zeta / h0_m
-                zeta0_h = zeta / h0_t
-                if (abs(B) < 1.0e-10) zeta0_h = zeta0_m
-
-                y1 = (1.0 - alpha_m * zeta)**0.25e0
-                x1 = sqrt(1.0 - alpha_h_fix * zeta)
-
-                y0 = (1.0 - alpha_m * zeta0_m)**0.25e0
-                x0 = sqrt(1.0 - alpha_h_fix * zeta0_h)
-
-                y0 = max(y0, 1.000001e0)
-                x0 = max(x0, 1.000001e0)
-
-                psi_m = log((y1 - 1.0e0)*(y0 + 1.0e0)/((y1 + 1.0e0)*(y0 - 1.0e0))) + 2.0e0*(atan(y1) - atan(y0))
-                psi_h = log((x1 - 1.0e0)*(x0 + 1.0e0)/((x1 + 1.0e0)*(x0 - 1.0e0))) / Pr_t_0_inv
-
-                if (i == maxiters + 1) exit
-
-                zeta = Rib * psi_m**2 / psi_h
-            end do
-
-        end subroutine
-        ! --------------------------------------------------------------------------------
-
-        ! stability functions (convection)
-        ! --------------------------------------------------------------------------------
-        subroutine get_psi_convection(psi_m, psi_h, zeta, Rib, &
-                zeta_conv_lim, x10, y10, &
-                h0_m, h0_t, B, maxiters)
-            ! ----------------------------------------------------------------------------
-            real, intent(out) :: psi_m, psi_h, zeta
-            real, intent(in) :: Rib
-            real, intent(in) :: zeta_conv_lim
-            real, intent(in) :: x10, y10
-            real, intent(in) :: h0_m, h0_t
-            real, intent(in) :: B
-            integer, intent(in) :: maxiters
-
-            real :: zeta0_m, zeta0_h
-            real :: x0, y0
-            real :: p1, p0
-            real :: a1, b1, c, f
-
-            integer :: i
-            ! ----------------------------------------------------------------------------
-
-            p1 = 2.0 * atan(y10) + log((y10 - 1.0) / (y10 + 1.0))
-            p0 = log((x10 - 1.0) / (x10 + 1.0))
-
-            zeta = zeta_conv_lim
-            do i = 1, maxiters + 1
-                zeta0_m = zeta / h0_m
-                zeta0_h = zeta / h0_t
-                if (abs(B) < 1.0e-10) zeta0_h = zeta0_m
-
-                a1 = (zeta_conv_lim / zeta)**(1.0 / 3.0)
-                x0 = sqrt(1.0 - alpha_h_fix * zeta0_h)
-                y0 = (1.0 - alpha_m * zeta0_m)**0.25
-                c = log((x0 + 1.0)/(x0 - 1.0))
-                b1 = -2.0*atan(y0) + log((y0 + 1.0)/(y0 - 1.0))
-                f = 3.0 * (1.0 - a1)
-
-                psi_m = f / y10 + p1 + b1
-                psi_h = (f / x10 + p0 + c) / Pr_t_0_inv
-
-                if (i == maxiters + 1) exit
-                zeta = Rib * psi_m**2 / psi_h
-            end do
-
-        end subroutine
-        ! --------------------------------------------------------------------------------
-
-        ! define convection limit
-        ! --------------------------------------------------------------------------------
-        subroutine get_convection_lim(zeta_lim, Rib_lim, x10, y10, &
-                h0_m, h0_t, B)
-            ! ----------------------------------------------------------------------------
-            real, intent(out) :: zeta_lim, Rib_lim
-            real, intent(out) :: x10, y10
-
-            real, intent(in) :: h0_m, h0_t
-            real, intent(in) :: B
-
-            real :: an4, an5
-            real :: psi_m, psi_h
-            ! ----------------------------------------------------------------------------
-
-            an5=(Pr_t_inf_inv / Pr_t_0_inv)**4
-            zeta_lim = (2.0E0*alpha_h-an5*alpha_m-SQRT((an5*alpha_m)**2+4.0E0*an5*alpha_h*(alpha_h-alpha_m))) &
-                    / (2.0E0*alpha_h**2)
-
-            y10 = f_m_conv(zeta_lim)
-            x10 = f_h_conv(zeta_lim)
-
-            !     ......definition of r-prim......
-            an4 = zeta_lim / h0_m
-            an5 = zeta_lim / h0_t
-            if (abs(B) < 1.0e-10) an5=an4
-
-            an5 = sqrt(1.0 - alpha_h_fix * an5)
-            an4 = (1.0 - alpha_m * an4)**0.25
-
-            psi_m = 2.0 * (atan(y10) - atan(an4)) + alog((y10 - 1.0) * (an4 + 1.0)/((y10 + 1.0) * (an4 - 1.0)))
-            psi_h = alog((x10 - 1.0) * (an5 + 1.0)/((x10 + 1.0) * (an5 - 1.0))) / Pr_t_0_inv
-
-            Rib_lim = zeta_lim * psi_h / (psi_m * psi_m)
-
-        end subroutine
-        ! --------------------------------------------------------------------------------
-
-        ! charnock roughness
-        ! --------------------------------------------------------------------------------
-        subroutine get_charnock_roughness(z0_m, u_dyn0, U, h, maxiters)
-            ! ----------------------------------------------------------------------------
-            real, intent(out) :: z0_m, u_dyn0
-
-            real, intent(in) :: U, h
-            integer, intent(in) :: maxiters
-
-            real :: U10m
-            real :: a1, c1, y1, c1min, f
-
-            integer :: i, j
-            ! ----------------------------------------------------------------------------
-
-            U10m = U
-            a1 = 0.0e0
-            y1 = 25.0e0
-            c1min = log(h_charnock) / kappa
-            do i = 1, maxiters
-                f = c1_charnock - 2.0 * log(U10m)
-                do j = 1, maxiters
-                    c1 = (f + 2.0 * log(y1)) / kappa
-                    ! looks like the check should use U10 instead of U
-                    !   but note that a1 should be set = 0 in cycle beforehand
-                    if(U <= 8.0e0) a1 = log(1.0 + c2_charnock * ((y1 / U10m)**3)) / kappa
-                    c1 = max(c1 - a1, c1min)
-                    y1 = c1
-                end do
-                z0_m = h_charnock * exp(-c1 * kappa)
-                z0_m = max(z0_m,0.000015e0)
-                U10m = U*alog(h_charnock/z0_m)/(alog(h/z0_m))
-            end do
-
-            ! --- define dynamic velocity in neutral conditions
-            u_dyn0 = U10m / c1
-
-        end subroutine
-        ! --------------------------------------------------------------------------------
-
-
-        SUBROUTINE  surf_flux(meteo, sfx, numerics, lu)
-            type (sfxDataType), intent(out) :: sfx
-
-            type (meteoDataType), intent(in) :: meteo
-            type (numericsType), intent(in) :: numerics
-
-            type (data_lutyp) lu
-
-            real h              ! surface flux layer height [m]
-
-            real z0_m, z0_t     ! aerodynamic & thermal roughness [m]
-            real B              ! = ln(z0_m / z0_t) [n/d]
-            real h0_m, h0_t     ! = h / z0_m, h / z0_h [n/d]
-
-            real Re             ! roughness Reynolds number = u_dyn0 * z0 / nu [n/d]
-            real u_dyn0         ! dynamic velocity in neutral conditions [m/s]
-
-            real zeta           ! = z/L [n/d]
-            real zeta_conv_lim  ! z/L critical value for matching free convection limit [n/d]
-
-            real Rib            ! bulk Richardson number
-            real Rib_conv_lim   ! Ri-bulk critical value for matching free convection limit [n/d]
-
-            real psi_m, psi_h   ! universal functions [momentum] & [thermal]
-
-            real U              ! wind velocity at h [m/s]
-            real Tsemi          !
-
-
-            integer lu_indx
-
-            ! output ... !
-            real an4, o, am
-            real c4, c0, an0
-            ! ...
-
-            ! local unnamed !
-            real x10, y10
-            real al
-
-            real q4, t4
-            ! .....
-
-            ! just local variables
-            real f1, a1
-            ! ....
-
-            integer is_ocean
-            integer i, j
-
-
-            Tsemi = meteo%Tsemi
-
-            U = meteo%U
-            t4 = meteo%dT
-            q4 = meteo%dQ
-            h = meteo%h
-            z0_m = meteo%z0_m
-
-            if(z0_m < 0.0) then
-                !> @brief Test - definition z0 of sea surface
-                !> @details  if lu_indx=2.or.lu_indx=3 call z0sea module (Ramil_Dasha)
-                is_ocean = 1
-
-                call get_charnock_roughness(z0_m, u_dyn0, U, h, numerics%maxiters_charnock)
-
-                ! --- define relative height
-                h0_m = h / z0_m
-            else
-                !     ......parameters from viscosity sublayer......
-                is_ocean = 0
-
-                ! --- define relative height
-                h0_m = h / z0_m
-                ! --- define dynamic velocity in neutral conditions
-                u_dyn0 = U * kappa / log(h0_m)
-            end if
-
-            Re = u_dyn0 * z0_m / nu_air
-            if(Re <= Re_rough_min) then
-                B = B1_rough * alog(B3_rough * Re) + B2_rough
-            else
-                ! B4 takes into account Re value at z' ~ O(10) z0
-                B = B4_rough * (Re**B2_rough)
-            end if
-
-            ! --- apply max restriction based on surface type
-            if (is_ocean == 1) then
-                B = min(B, B_max_ocean)
-            else
-                B = min(B, B_max_land)
-            end if
-
-            ! --- define roughness [thermal]
-            z0_t = z0_m / exp(B)
-            ! --- define relative height [thermal]
-            h0_t = h / z0_t
-
-            !     ......humidity stratification and ri-number......
-            al = g / Tsemi
-            Rib = al * h * (t4 + 0.61e0 * Tsemi * q4) / U**2
-
-            ! --- define free convection transition zeta = z/L value
-            call get_convection_lim(zeta_conv_lim, Rib_conv_lim, x10, y10, &
-                h0_m, h0_t, B)
-
-            if (Rib > 0.0e0) then
-                !     ......stable stratification......
-                !write (*,*) 'stable'
-
-                Rib = min(Rib, Rib_max)
-                call get_psi_stable(psi_m, psi_h, zeta, Rib, h0_m, h0_t, B)
-
-                f1 = beta_m * zeta
-                am = 1.0 + f1
-                o = 1.0/Pr_t_0_inv + f1
-
-            else if (Rib < Rib_conv_lim) then
-                !     ......strong instability.....
-                !write (*,*) 'instability'
-
-                call get_psi_convection(psi_m, psi_h, zeta, Rib, &
-                        zeta_conv_lim, x10, y10, h0_m, h0_t, B, numerics%maxiters_convection)
-
-                a1 = (zeta_conv_lim / zeta)**(1.0/3.0)
-                am = a1 / y10
-                o = a1 / (Pr_t_0_inv * x10)
-
-            else if (Rib > -0.001e0) then
-
-                !     ......nearly neutral......
-                write (*,*) 'neutral'
-
-                call get_psi_neutral(psi_m, psi_h, zeta, h0_m, h0_t, B)
-
-                am = 1.0e0
-                o = 1.0e0 / Pr_t_0_inv
-            else
-                !     ......week and semistrong instability......
-                !write (*,*) 'semistrong'
-
-                call get_psi_semi_convection(psi_m, psi_h, zeta, Rib, h0_m, h0_t, B, numerics%maxiters_convection)
-
-                am = (1.0 - alpha_m * zeta)**(-0.25)
-                o = 1.0/(Pr_t_0_inv * sqrt(1.0 - alpha_h_fix * zeta))
-            end if
-
-            !     ......computation of cu,co,k(h),alft
-            c4=kappa/psi_m
-            c0=kappa/psi_h
-            an4=kappa*c4*U*h/am
-            an0=am/o
-
-            !     ......exit......
-            sfx%zeta = zeta
-            sfx%Rib = Rib
-            sfx%Re = Re
-            sfx%lnzuzt=B
-            sfx%z0_m = z0_m
-            sfx%z0_t = z0_t
-            sfx%Rib_conv_lim = Rib_conv_lim
-            sfx%cm=c4
-            sfx%ch=c0
-            sfx%ct=an4
-            sfx%ckt=an0
-            return
-
-        END SUBROUTINE  surf_flux
-
-    END MODULE drag3
\ No newline at end of file
diff --git a/makefile b/makefile
index ef11984..bd4ab1b 100644
--- a/makefile
+++ b/makefile
@@ -1,4 +1,4 @@
-RUN = drag.exe
+RUN = sfx
 COMPILER ?= gnu
 FC_KEYS ?= 
 
@@ -10,7 +10,7 @@ ifeq ($(COMPILER),gnu)
   FC = gfortran
 endif 
 
-OBJ_F90 = inputdata.o param.o prmt.o
+OBJ_F90 = sfx_phys_const.o sfx_esm_param.o sfx_esm.o
 OBJ_F = DRAG.o drag3.o
 OBJ = $(OBJ_F90) $(OBJ_F)
 
diff --git a/param.f90 b/param.f90
deleted file mode 100644
index 4a1519e..0000000
--- a/param.f90
+++ /dev/null
@@ -1,69 +0,0 @@
-module param
-      implicit none
-      ! acceleration due to gravity [m/s^2]
-      real, parameter :: g = 9.81
-      ! molecular Prandtl number (air) [n/d]
-      real, parameter :: Pr_m = 0.71
-      ! kinematic viscosity of air [m^2/s]
-      real, parameter :: nu_air = 0.000015e0
-      ! von Karman constant [n/d]
-      real, parameter :: kappa = 0.40
-      ! inverse Prandtl (turbulent) number in neutral conditions [n/d]
-      real, parameter :: Pr_t_0_inv = 1.15
-      ! inverse Prandtl (turbulent) number in free convection [n/d]
-      real, parameter :: Pr_t_inf_inv = 3.5
-
-      ! stability function coeff. (unstable) [= g4 & g10 in deprecated code]
-      real, parameter :: alpha_m = 16.0
-      real, parameter :: alpha_h = 16.0
-      real, parameter :: alpha_h_fix = 1.2
-
-      ! stability function coeff. (stable)
-      real, parameter :: beta_m = 4.7
-      real, parameter :: beta_h = beta_m
-
-      ! --- max Ri-bulk value in stable case ( < 1 / beta_m )
-      real, parameter ::  Rib_max = 0.9 / beta_m
-
-      ! Re fully roughness minimum value [n/d]
-      real, parameter ::  Re_rough_min = 16.3
-
-      ! roughness model coeff. [n/d]
-      ! --- transitional mode
-      !     B = log(z0_m / z0_t) = B1 * log(B3 * Re) + B2
-      real, parameter :: B1_rough = 5.0 / 6.0
-      real, parameter :: B2_rough = 0.45
-      real, parameter :: B3_rough = kappa * Pr_m
-      ! --- fully rough mode (Re > Re_rough_min)
-      !     B = B4 * Re^(B2)
-      real, parameter :: B4_rough =(0.14 * (30.0**B2_rough)) * (Pr_m**0.8)
-
-      real, parameter :: B_max_land = 2.0
-      real, parameter :: B_max_ocean = 8.0
-
-      ! Charnock parameters
-      !     z0 = Re_visc_min * (nu / u_dyn) + gamma_c * (u_dyn^2 / g)
-      real, parameter :: gamma_c = 0.0144
-      real, parameter :: Re_visc_min = 0.111
-
-      real, parameter :: h_charnock = 10.0
-      real, parameter :: c1_charnock = log(h_charnock * (g / gamma_c))
-      real, parameter :: c2_charnock = Re_visc_min * nu_air * c1_charnock
-
-!      AN5=(A6/A0)**4
-!      D1=(2.0E0*G10-AN5*G4-SQRT((AN5*G4)**2+4.0E0*AN5*G10*(G10-G4)))/(2.0E0*G10**2)
-!      Y10=(1.0E0-G4*D1)**.25E0
-!      X10=(1.0E0-G10*D1)**.5E0
-!      P1=2.0E0*ATAN(Y10)+ALOG((Y10-1.0E0)/(Y10+1.0E0))
-!      P0=ALOG((X10-1.0E0)/(X10+1.0E0))
-
-end module PARAM
-
-
-
-
-
-
-
-
-
diff --git a/sfx_esm.f90 b/sfx_esm.f90
new file mode 100644
index 0000000..188ab38
--- /dev/null
+++ b/sfx_esm.f90
@@ -0,0 +1,593 @@
+module sfx_esm
+    !> @brief main Earth System Model surface flux module
+
+    ! macro defs.
+    ! --------------------------------------------------------------------------------
+#define SFX_FORCE_DEPRECATED_CODE
+    ! --------------------------------------------------------------------------------
+
+    ! modules used
+    ! --------------------------------------------------------------------------------
+    use sfx_esm_param
+    ! --------------------------------------------------------------------------------
+
+    ! directives list
+    ! --------------------------------------------------------------------------------
+    implicit none
+    private
+    ! --------------------------------------------------------------------------------
+
+    ! public interface
+    ! --------------------------------------------------------------------------------
+    public :: get_surface_fluxes
+    public :: get_surface_fluxes_vec
+    ! --------------------------------------------------------------------------------
+
+    ! --------------------------------------------------------------------------------
+    type, public :: meteoDataType
+        !> @brief meteorological input for surface flux calculation
+
+        real :: h       !> constant flux layer height [m]
+        real :: U       !> abs(wind speed) at 'h' [m/s]
+        real :: dT      !> difference between potential temperature at 'h' and at surface [K]
+        real :: Tsemi   !> semi-sum of potential temperature at 'h' and at surface [K]
+        real :: dQ      !> difference between humidity at 'h' and at surface [g/g]
+        real :: z0_m    !> surface aerodynamic roughness (should be < 0 for water bodies surface)
+    end type
+
+    type, public :: meteoDataVecType
+        !> @brief meteorological input for surface flux calculation
+        !> &details using arrays as input
+
+        real, allocatable :: h(:)       !> constant flux layer height [m]
+        real, allocatable :: U(:)       !> abs(wind speed) at 'h' [m/s]
+        real, allocatable :: dT(:)      !> difference between potential temperature at 'h' and at surface [K]
+        real, allocatable :: Tsemi(:)   !> semi-sum of potential temperature at 'h' and at surface [K]
+        real, allocatable :: dQ(:)      !> difference between humidity at 'h' and at surface [g/g]
+        real, allocatable :: z0_m(:)    !> surface aerodynamic roughness (should be < 0 for water bodies surface)
+    end type
+    ! --------------------------------------------------------------------------------
+
+    ! --------------------------------------------------------------------------------
+    type, public :: sfxDataType
+        !> @brief surface flux output data
+
+        real :: zeta            !> = z/L [n/d]
+        real :: Rib             !> bulk Richardson number [n/d]
+        real :: Re              !> Reynolds number [n/d]
+        real :: B               !> = log(z0_m / z0_h) [n/d]
+        real :: z0_m            !> aerodynamic roughness [m]
+        real :: z0_t            !> thermal roughness [m]
+        real :: Rib_conv_lim    !> Ri-bulk convection critical value [n/d]
+        real :: Cm              !> transfer coefficient for momentum [n/d]
+        real :: Ct              !> transfer coefficient for heat [n/d]
+        real :: Km              !> eddy viscosity coeff. at h [m^2/s]
+        real :: Pr_t_inv        !> inverse turbulent Prandtl number at h [n/d]
+    end type
+
+    type, public :: sfxDataVecType
+        !> @brief surface flux output data
+        !> &details using arrays as output
+
+        real, allocatable :: zeta(:)            !> = z/L [n/d]
+        real, allocatable :: Rib(:)             !> bulk Richardson number [n/d]
+        real, allocatable :: Re(:)              !> Reynolds number [n/d]
+        real, allocatable :: B(:)               !> = log(z0_m / z0_h) [n/d]
+        real, allocatable :: z0_m(:)            !> aerodynamic roughness [m]
+        real, allocatable :: z0_t(:)            !> thermal roughness [m]
+        real, allocatable :: Rib_conv_lim(:)    !> Ri-bulk convection critical value [n/d]
+        real, allocatable :: Cm(:)              !> transfer coefficient for momentum [n/d]
+        real, allocatable :: Ct(:)              !> transfer coefficient for heat [n/d]
+        real, allocatable :: Km(:)              !> eddy viscosity coeff. at h [m^2/s]
+        real, allocatable :: Pr_t_inv(:)        !> inverse turbulent Prandtl number at h [n/d]
+    end type
+    ! --------------------------------------------------------------------------------
+
+    ! --------------------------------------------------------------------------------
+    type, public :: numericsType
+        integer :: maxiters_convection = 10    !> maximum (actual) number of iterations in convection
+        integer :: maxiters_charnock = 10      !> maximum (actual) number of iterations in charnock roughness
+    end type
+    ! --------------------------------------------------------------------------------
+
+contains
+
+    ! --------------------------------------------------------------------------------
+    subroutine get_surface_fluxes_vec(sfx, meteo, numerics, n)
+        !> @brief surface flux calculation for array data
+        !> @details contains C/C++ & CUDA interface
+        ! ----------------------------------------------------------------------------
+        type (sfxDataVecType), intent(inout) :: sfx
+
+        type (meteoDataVecType), intent(in) :: meteo
+        type (numericsType), intent(in) :: numerics
+        integer, intent(in) :: n
+        ! ----------------------------------------------------------------------------
+
+        ! --- local variables
+        type (meteoDataType)  meteo_cell
+        type (sfxDataType) sfx_cell
+        integer i
+        ! ----------------------------------------------------------------------------
+
+        do i = 1, n
+#ifdef USE_DEPRECATED_CODE
+#else
+            meteo_cell = meteoDataType(&
+                    h = meteo%h(i), &
+                    U = meteo%U(i), dT = meteo%dT(i), Tsemi = meteo%Tsemi(i), dQ = meteo%dQ(i), &
+                    z0_m = meteo%z0_m(i))
+
+            call get_surface_fluxes(sfx_cell, meteo_cell, numerics)
+
+            call push_sfx_data(sfx, sfx_cell, i)
+#endif
+        end do
+
+    end subroutine get_surface_fluxes_vec
+    ! --------------------------------------------------------------------------------
+
+    ! --------------------------------------------------------------------------------
+    subroutine push_sfx_data(sfx, sfx_cell, idx)
+        !> @brief helper subroutine for copying data in sfxDataVecType
+        ! ----------------------------------------------------------------------------
+        type (sfxDataVecType), intent(inout) :: sfx
+        type (sfxDataType), intent(in) :: sfx_cell
+        integer, intent(in) :: idx
+        ! ----------------------------------------------------------------------------
+
+        sfx%zeta(idx) = sfx_cell%zeta
+        sfx%Rib(idx) = sfx_cell%Rib
+        sfx%Re(idx) = sfx_cell%Re
+        sfx%B(idx) = sfx_cell%B
+        sfx%z0_m(idx) = sfx_cell%z0_m
+        sfx%z0_t(idx) = sfx_cell%z0_t
+        sfx%Rib_conv_lim(idx) = sfx_cell%Rib_conv_lim
+        sfx%Cm(idx) = sfx_cell%Cm
+        sfx%Ct(idx) = sfx_cell%Ct
+        sfx%Km(idx) = sfx_cell%Km
+        sfx%Pr_t_inv(idx) = sfx_cell%Pr_t_inv
+
+    end subroutine push_sfx_data
+    ! --------------------------------------------------------------------------------
+
+    ! --------------------------------------------------------------------------------
+    subroutine get_surface_fluxes(sfx, meteo, numerics)
+        !> @brief surface flux calculation for single cell
+        !> @details contains C/C++ interface
+        ! ----------------------------------------------------------------------------
+        type (sfxDataType), intent(out) :: sfx
+
+        type (meteoDataType), intent(in) :: meteo
+        type (numericsType), intent(in) :: numerics
+        ! ----------------------------------------------------------------------------
+
+        ! --- meteo derived datatype name shadowing
+        ! ----------------------------------------------------------------------------
+        real :: h       !> constant flux layer height [m]
+        real :: U       !> abs(wind speed) at 'h' [m/s]
+        real :: dT      !> difference between potential temperature at 'h' and at surface [K]
+        real :: Tsemi   !> semi-sum of potential temperature at 'h' and at surface [K]
+        real :: dQ      !> difference between humidity at 'h' and at surface [g/g]
+        real :: z0_m    !> surface aerodynamic roughness (should be < 0 for water bodies surface)
+        ! ----------------------------------------------------------------------------
+
+        ! --- local variables
+        ! ----------------------------------------------------------------------------
+        real z0_t               !> thermal roughness [m]
+        real B                  !> = ln(z0_m / z0_t) [n/d]
+        real h0_m, h0_t         !> = h / z0_m, h / z0_h [n/d]
+
+        real u_dyn0             !> dynamic velocity in neutral conditions [m/s]
+        real Re                 !> roughness Reynolds number = u_dyn0 * z0_m / nu [n/d]
+
+        real zeta               !> = z/L [n/d]
+        real Rib                !> bulk Richardson number
+
+        real zeta_conv_lim      !> z/L critical value for matching free convection limit [n/d]
+        real Rib_conv_lim       !> Ri-bulk critical value for matching free convection limit [n/d]
+
+        real f_m_conv_lim       !> stability function (momentum) value in free convection limit [n/d]
+        real f_h_conv_lim       !> stability function (heat) value in free convection limit [n/d]
+
+        real psi_m, psi_h       !> universal functions (momentum) & (heat) [n/d]
+        real phi_m, phi_h       !> stability functions (momentum) & (heat) [n/d]
+
+        real Km                 !> eddy viscosity coeff. at h [m^2/s]
+        real Pr_t_inv           !> invese Prandt number [n/d]
+
+        real Cm, Ct             !> transfer coeff. for (momentum) & (heat) [n/d]
+
+        integer surface_type    !> surface type = (ocean || land)
+
+        real fval               !> just a shortcut for partial calculations
+        ! ----------------------------------------------------------------------------
+
+        ! --- shadowing names for clarity
+        U = meteo%U
+        Tsemi = meteo%Tsemi
+        dT = meteo%dT
+        dQ = meteo%dQ
+        h = meteo%h
+        z0_m = meteo%z0_m
+
+        ! --- define surface type
+        if (z0_m < 0.0) then
+            surface_type = surface_ocean
+        else
+            surface_type = surface_land
+        end if
+
+        if (surface_type == surface_ocean) then
+            ! --- define surface roughness [momentum] & dynamic velocity in neutral conditions
+            call get_charnock_roughness(z0_m, u_dyn0, U, h, numerics%maxiters_charnock)
+            ! --- define relative height
+            h0_m = h / z0_m
+        endif
+        if (surface_type == surface_land) then
+            ! --- define relative height
+            h0_m = h / z0_m
+            ! --- define dynamic velocity in neutral conditions
+            u_dyn0 = U * kappa / log(h0_m)
+        end if
+
+        ! --- define B = log(z0_m / z0_h)
+        Re = u_dyn0 * z0_m / nu_air
+        if(Re <= Re_rough_min) then
+            B = B1_rough * alog(B3_rough * Re) + B2_rough
+        else
+            ! *: B4 takes into account Re value at z' ~ O(10) z0
+            B = B4_rough * (Re**B2_rough)
+        end if
+
+        !   --- apply max restriction based on surface type
+        if (surface_type == surface_ocean) then
+            B = min(B, B_max_ocean)
+        endif
+        if (surface_type == surface_land) then
+            B = min(B, B_max_land)
+        end if
+
+        ! --- define roughness [thermal]
+        z0_t = z0_m / exp(B)
+        ! --- define relative height [thermal]
+        h0_t = h / z0_t
+
+        ! --- define Ri-bulk
+        Rib = (g / Tsemi) * h * (dT + 0.61e0 * Tsemi * dQ) / U**2
+
+        ! --- define free convection transition zeta = z/L value
+        call get_convection_lim(zeta_conv_lim, Rib_conv_lim, f_m_conv_lim, f_h_conv_lim, &
+                h0_m, h0_t, B)
+
+        ! --- get the fluxes
+        ! ----------------------------------------------------------------------------
+        if (Rib > 0.0) then
+            ! --- stable stratification block
+
+            !   --- restrict bulk Ri value
+            !   *: note that this value is written to output
+            Rib = min(Rib, Rib_max)
+            call get_psi_stable(psi_m, psi_h, zeta, Rib, h0_m, h0_t, B)
+
+            fval = beta_m * zeta
+            phi_m = 1.0 + fval
+            phi_h = 1.0/Pr_t_0_inv + fval
+
+        else if (Rib < Rib_conv_lim) then
+            ! --- strong instability block
+
+            call get_psi_convection(psi_m, psi_h, zeta, Rib, &
+                    zeta_conv_lim, f_m_conv_lim, f_h_conv_lim, h0_m, h0_t, B, numerics%maxiters_convection)
+
+            fval = (zeta_conv_lim / zeta)**(1.0/3.0)
+            phi_m = fval / f_m_conv_lim
+            phi_h = fval / (Pr_t_0_inv * f_h_conv_lim)
+
+        else if (Rib > -0.001) then
+            ! --- nearly neutral [-0.001, 0] block
+
+            call get_psi_neutral(psi_m, psi_h, zeta, h0_m, h0_t, B)
+
+            phi_m = 1.0
+            phi_h = 1.0 / Pr_t_0_inv
+        else
+            ! --- weak & semistrong instability block
+
+            call get_psi_semi_convection(psi_m, psi_h, zeta, Rib, h0_m, h0_t, B, numerics%maxiters_convection)
+
+            phi_m = (1.0 - alpha_m * zeta)**(-0.25)
+            phi_h = 1.0 / (Pr_t_0_inv * sqrt(1.0 - alpha_h_fix * zeta))
+        end if
+
+        ! --- define transfer coeff. (momentum) & (heat)
+        Cm = kappa / psi_m
+        Ct = kappa / psi_h
+
+        ! --- define eddy viscosity & inverse Prandtl number
+        Km = kappa * Cm * U * h / phi_m
+        Pr_t_inv = phi_m / phi_h
+
+        ! --- setting output
+        sfx = sfxDataType(zeta = zeta, Rib = Rib, &
+            Re = Re, B = B, z0_m = z0_m, z0_t = z0_t, &
+            Rib_conv_lim = Rib_conv_lim, &
+            Cm = Cm, Ct = Ct, Km = Km, Pr_t_inv = Pr_t_inv)
+
+    end subroutine get_surface_fluxes
+    ! --------------------------------------------------------------------------------
+
+    ! convection universal functions shortcuts
+    ! --------------------------------------------------------------------------------
+    function f_m_conv(zeta)
+        ! ----------------------------------------------------------------------------
+        real :: f_m_conv
+        real, intent(in) :: zeta
+        ! ----------------------------------------------------------------------------
+
+        f_m_conv = (1.0 - alpha_m * zeta)**0.25
+
+    end function f_m_conv
+
+    function f_h_conv(zeta)
+        ! ----------------------------------------------------------------------------
+        real :: f_h_conv
+        real, intent(in) :: zeta
+        ! ----------------------------------------------------------------------------
+
+        f_h_conv = (1.0 - alpha_h * zeta)**0.5
+
+    end function f_h_conv
+    ! --------------------------------------------------------------------------------
+
+    ! universal functions
+    ! --------------------------------------------------------------------------------
+    subroutine get_psi_neutral(psi_m, psi_h, zeta, h0_m, h0_t, B)
+        !> @brief universal functions (momentum) & (heat): neutral case
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: psi_m, psi_h   !> universal functions
+        real, intent(out) :: zeta           !> = z/L
+
+        real, intent(in) :: h0_m, h0_t      !> = z/z0_m, z/z0_h
+        real, intent(in) :: B               !> = log(z0_m / z0_h)
+        ! ----------------------------------------------------------------------------
+
+        zeta = 0.0
+        psi_m = log(h0_m)
+        psi_h = log(h0_t) / Pr_t_0_inv
+        if (abs(B) < 1.0e-10) psi_h = psi_m / Pr_t_0_inv
+
+    end subroutine
+
+    subroutine get_psi_stable(psi_m, psi_h, zeta, Rib, h0_m, h0_t, B)
+        !> @brief universal functions (momentum) & (heat): stable case
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: psi_m, psi_h   !> universal functions [n/d]
+        real, intent(out) :: zeta           !> = z/L [n/d]
+
+        real, intent(in) :: Rib             !> bulk Richardson number [n/d]
+        real, intent(in) :: h0_m, h0_t      !> = z/z0_m, z/z0_h [n/d]
+        real, intent(in) :: B               !> = log(z0_m / z0_h) [n/d]
+        ! ----------------------------------------------------------------------------
+
+        ! --- local variables
+        real :: Rib_coeff
+        real :: psi0_m, psi0_h
+        real :: phi
+        real :: c
+        ! ----------------------------------------------------------------------------
+
+        psi0_m = alog(h0_m)
+        psi0_h = B / psi0_m
+
+        Rib_coeff = beta_m * Rib
+        c = (psi0_h + 1.0) / Pr_t_0_inv - 2.0 * Rib_coeff
+        zeta = psi0_m * (sqrt(c**2 + 4.0 * Rib_coeff * (1.0 - Rib_coeff)) - c) / &
+                (2.0 * beta_m * (1.0 - Rib_coeff))
+
+        phi = beta_m * zeta
+
+        psi_m = psi0_m + phi
+        psi_h = (psi0_m + B) / Pr_t_0_inv + phi
+
+    end subroutine
+
+    subroutine get_psi_semi_convection(psi_m, psi_h, zeta, Rib, h0_m, h0_t, B, maxiters)
+        !> @brief universal functions (momentum) & (heat): semi-strong convection case
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: psi_m, psi_h   !> universal functions [n/d]
+        real, intent(out) :: zeta           !> = z/L [n/d]
+
+        real, intent(in) :: Rib             !> bulk Richardson number [n/d]
+        real, intent(in) :: h0_m, h0_t      !> = z/z0_m, z/z0_h [n/d]
+        real, intent(in) :: B               !> = log(z0_m / z0_h) [n/d]
+        integer, intent(in) :: maxiters     !> maximum number of iterations
+
+        ! --- local variables
+        real :: zeta0_m, zeta0_h
+        real :: f0_m, f0_h
+        real :: f_m, f_h
+
+        integer :: i
+        ! ----------------------------------------------------------------------------
+
+        psi_m = log(h0_m)
+        psi_h = log(h0_t)
+        if (abs(B) < 1.0e-10) psi_h = psi_m
+
+        zeta = Rib * Pr_t_0_inv * psi_m**2 / psi_h
+
+        do i = 1, maxiters + 1
+            zeta0_m = zeta / h0_m
+            zeta0_h = zeta / h0_t
+            if (abs(B) < 1.0e-10) zeta0_h = zeta0_m
+
+            f_m = (1.0 - alpha_m * zeta)**0.25e0
+            f_h = sqrt(1.0 - alpha_h_fix * zeta)
+
+            f0_m = (1.0 - alpha_m * zeta0_m)**0.25e0
+            f0_h = sqrt(1.0 - alpha_h_fix * zeta0_h)
+
+            f0_m = max(f0_m, 1.000001e0)
+            f0_h = max(f0_h, 1.000001e0)
+
+            psi_m = log((f_m - 1.0e0)*(f0_m + 1.0e0)/((f_m + 1.0e0)*(f0_m - 1.0e0))) + 2.0e0*(atan(f_m) - atan(f0_m))
+            psi_h = log((f_h - 1.0e0)*(f0_h + 1.0e0)/((f_h + 1.0e0)*(f0_h - 1.0e0))) / Pr_t_0_inv
+
+            ! *: don't update zeta = z/L at last iteration
+            if (i == maxiters + 1) exit
+
+            zeta = Rib * psi_m**2 / psi_h
+        end do
+
+    end subroutine
+
+    subroutine get_psi_convection(psi_m, psi_h, zeta, Rib, &
+            zeta_conv_lim, f_m_conv_lim, f_h_conv_lim, &
+            h0_m, h0_t, B, maxiters)
+        !> @brief universal functions (momentum) & (heat): fully convective case
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: psi_m, psi_h               !> universal functions [n/d]
+        real, intent(out) :: zeta                       !> = z/L [n/d]
+
+        real, intent(in) :: Rib                         !> bulk Richardson number [n/d]
+        real, intent(in) :: h0_m, h0_t                  !> = z/z0_m, z/z0_h [n/d]
+        real, intent(in) :: B                           !> = log(z0_m / z0_h) [n/d]
+        integer, intent(in) :: maxiters                 !> maximum number of iterations
+
+        real, intent(in) :: zeta_conv_lim               !> convective limit zeta
+        real, intent(in) :: f_m_conv_lim, f_h_conv_lim  !> universal function shortcuts in limiting case
+        ! ----------------------------------------------------------------------------
+
+        ! --- local variables
+        real :: zeta0_m, zeta0_h
+        real :: f0_m, f0_h
+        real :: p_m, p_h
+        real :: a_m, a_h
+        real :: c_lim, f
+
+        integer :: i
+        ! ----------------------------------------------------------------------------
+
+        p_m = 2.0 * atan(f_m_conv_lim) + log((f_m_conv_lim - 1.0) / (f_m_conv_lim + 1.0))
+        p_h = log((f_h_conv_lim - 1.0) / (f_h_conv_lim + 1.0))
+
+        zeta = zeta_conv_lim
+        do i = 1, maxiters + 1
+            zeta0_m = zeta / h0_m
+            zeta0_h = zeta / h0_t
+            if (abs(B) < 1.0e-10) zeta0_h = zeta0_m
+
+            f0_m = (1.0 - alpha_m * zeta0_m)**0.25
+            f0_h = sqrt(1.0 - alpha_h_fix * zeta0_h)
+
+            a_m = -2.0*atan(f0_m) + log((f0_m + 1.0)/(f0_m - 1.0))
+            a_h = log((f0_h + 1.0)/(f0_h - 1.0))
+
+            c_lim = (zeta_conv_lim / zeta)**(1.0 / 3.0)
+            f = 3.0 * (1.0 - c_lim)
+
+            psi_m = f / f_m_conv_lim + p_m + a_m
+            psi_h = (f / f_h_conv_lim + p_h + a_h) / Pr_t_0_inv
+
+            ! *: don't update zeta = z/L at last iteration
+            if (i == maxiters + 1) exit
+
+            zeta = Rib * psi_m**2 / psi_h
+        end do
+
+    end subroutine
+    ! --------------------------------------------------------------------------------
+
+    ! convection limit definition
+    ! --------------------------------------------------------------------------------
+    subroutine get_convection_lim(zeta_lim, Rib_lim, f_m_lim, f_h_lim, &
+            h0_m, h0_t, B)
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: zeta_lim           !> limiting value of z/L
+        real, intent(out) :: Rib_lim            !> limiting value of Ri-bulk
+        real, intent(out) :: f_m_lim, f_h_lim   !> limiting values of universal functions shortcuts
+
+        real, intent(in) :: h0_m, h0_t          !> = z/z0_m, z/z0_h [n/d]
+        real, intent(in) :: B                   !> = log(z0_m / z0_h) [n/d]
+        ! ----------------------------------------------------------------------------
+
+        ! --- local variables
+        real :: psi_m, psi_h
+        real :: f_m, f_h
+        real :: c
+        ! ----------------------------------------------------------------------------
+
+        ! --- define limiting value of zeta = z / L
+        c = (Pr_t_inf_inv / Pr_t_0_inv)**4
+        zeta_lim = (2.0 * alpha_h - c * alpha_m - &
+                sqrt((c * alpha_m)**2 + 4.0 * c * alpha_h * (alpha_h - alpha_m))) / (2.0 * alpha_h**2)
+
+        f_m_lim = f_m_conv(zeta_lim)
+        f_h_lim = f_h_conv(zeta_lim)
+
+        ! --- universal functions
+        f_m = zeta_lim / h0_m
+        f_h = zeta_lim / h0_t
+        if (abs(B) < 1.0e-10) f_h = f_m
+
+        f_m = (1.0 - alpha_m * f_m)**0.25
+        f_h = sqrt(1.0 - alpha_h_fix * f_h)
+
+        psi_m = 2.0 * (atan(f_m_lim) - atan(f_m)) + alog((f_m_lim - 1.0) * (f_m + 1.0)/((f_m_lim + 1.0) * (f_m - 1.0)))
+        psi_h = alog((f_h_lim - 1.0) * (f_h + 1.0)/((f_h_lim + 1.0) * (f_h - 1.0))) / Pr_t_0_inv
+
+        ! --- bulk Richardson number
+        Rib_lim = zeta_lim * psi_h / (psi_m * psi_m)
+
+    end subroutine
+    ! --------------------------------------------------------------------------------
+
+    ! charnock roughness definition
+    ! --------------------------------------------------------------------------------
+    subroutine get_charnock_roughness(z0_m, u_dyn0, U, h, maxiters)
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: z0_m           !> aerodynamic roughness [m]
+        real, intent(out) :: u_dyn0         !> dynamic velocity in neutral conditions [m/s]
+
+        real, intent(in) :: h               !> constant flux layer height [m]
+        real, intent(in) :: U               !> abs(wind speed) [m/s]
+        integer, intent(in) :: maxiters     !> maximum number of iterations
+        ! ----------------------------------------------------------------------------
+
+        ! --- local variables
+        real :: Uc                  ! wind speed at h_charnock [m/s]
+
+        real :: a, b, c, c_min
+        real :: f
+
+        integer :: i, j
+        ! ----------------------------------------------------------------------------
+
+        Uc = U
+        a = 0.0
+        b = 25.0
+        c_min = log(h_charnock) / kappa
+
+        do i = 1, maxiters
+            f = c1_charnock - 2.0 * log(Uc)
+            do j = 1, maxiters
+                c = (f + 2.0 * log(b)) / kappa
+                ! looks like the check should use U10 instead of U
+                !   but note that a1 should be set = 0 in cycle beforehand
+                if (U <= 8.0e0) a = log(1.0 + c2_charnock * ((b / Uc)**3)) / kappa
+                c = max(c - a, c_min)
+                b = c
+            end do
+            z0_m = h_charnock * exp(-c * kappa)
+            z0_m = max(z0_m, 0.000015e0)
+            Uc = U * log(h_charnock / z0_m) / log(h / z0_m)
+        end do
+
+        ! --- define dynamic velocity in neutral conditions
+        u_dyn0 = Uc / c
+
+    end subroutine
+    ! --------------------------------------------------------------------------------
+
+end module sfx_esm
\ No newline at end of file
diff --git a/sfx_esm_param.f90 b/sfx_esm_param.f90
new file mode 100644
index 0000000..fad0d75
--- /dev/null
+++ b/sfx_esm_param.f90
@@ -0,0 +1,71 @@
+module sfx_esm_param
+      !> @brief ESM surface flux model parameters
+      !> @details  all in SI units
+
+      ! modules used
+      ! --------------------------------------------------------------------------------
+      use sfx_phys_const
+      ! --------------------------------------------------------------------------------
+
+      ! directives list
+      ! --------------------------------------------------------------------------------
+      implicit none
+      ! --------------------------------------------------------------------------------
+
+      integer, public, parameter :: surface_ocean = 0     !> ocean surface
+      integer, public, parameter :: surface_land = 1      !> land surface
+
+      !> von Karman constant [n/d]
+      real, parameter :: kappa = 0.40
+      !> inverse Prandtl (turbulent) number in neutral conditions [n/d]
+      real, parameter :: Pr_t_0_inv = 1.15
+      !> inverse Prandtl (turbulent) number in free convection [n/d]
+      real, parameter :: Pr_t_inf_inv = 3.5
+
+      !> stability function coeff. (unstable) [= g4 & g10 in deprecated code]
+      real, parameter :: alpha_m = 16.0
+      real, parameter :: alpha_h = 16.0
+      real, parameter :: alpha_h_fix = 1.2
+
+      !> stability function coeff. (stable)
+      real, parameter :: beta_m = 4.7
+      real, parameter :: beta_h = beta_m
+
+      !> --- max Ri-bulk value in stable case ( < 1 / beta_m )
+      real, parameter ::  Rib_max = 0.9 / beta_m
+
+      !> Re fully roughness minimum value [n/d]
+      real, parameter ::  Re_rough_min = 16.3
+
+      !> roughness model coeff. [n/d]
+      !> --- transitional mode
+      !>     B = log(z0_m / z0_t) = B1 * log(B3 * Re) + B2
+      real, parameter :: B1_rough = 5.0 / 6.0
+      real, parameter :: B2_rough = 0.45
+      real, parameter :: B3_rough = kappa * Pr_m
+      !> --- fully rough mode (Re > Re_rough_min)
+      !>     B = B4 * Re^(B2)
+      real, parameter :: B4_rough =(0.14 * (30.0**B2_rough)) * (Pr_m**0.8)
+
+      real, parameter :: B_max_land = 2.0
+      real, parameter :: B_max_ocean = 8.0
+
+      !> Charnock parameters
+      !>     z0 = Re_visc_min * (nu / u_dyn) + gamma_c * (u_dyn^2 / g)
+      real, parameter :: gamma_c = 0.0144
+      real, parameter :: Re_visc_min = 0.111
+
+      real, parameter :: h_charnock = 10.0
+      real, parameter :: c1_charnock = log(h_charnock * (g / gamma_c))
+      real, parameter :: c2_charnock = Re_visc_min * nu_air * c1_charnock
+
+end module sfx_esm_param
+
+
+
+
+
+
+
+
+
diff --git a/main_drag.f90 b/sfx_main.f90
similarity index 62%
rename from main_drag.f90
rename to sfx_main.f90
index 776bee4..40ac4b8 100644
--- a/main_drag.f90
+++ b/sfx_main.f90
@@ -1,8 +1,9 @@
    PROGRAM main_ddt
-   
-    USE param
+
+    use sfx_phys_const
+    USE sfx_esm_param
     USE inputdata
-	USE drag3
+	USE sfx_esm
 
     type (meteoDataType):: data_in1
        
@@ -11,7 +12,6 @@
 	type (numericsType) :: data_par1
 
 
-    type (data_lutyp) :: data_lutyp1
     integer :: numst, i
     real :: cflh, z0in
     character(len = 50) :: filename_in
@@ -39,21 +39,21 @@
     !  lu_indx -  1 for land, 2 for sea, 3 for lake
     !  test - file input
 
-    type :: datatype_outMAS1
-        real, allocatable :: masout_zl(:)
-        real, allocatable :: masout_ri(:)
-        real, allocatable :: masout_re(:)
-        real, allocatable :: masout_lnzuzt(:)
-        real, allocatable :: masout_zu(:)
-        real, allocatable :: masout_ztout(:)
-        real, allocatable :: masout_rith(:)
-        real, allocatable :: masout_cm(:)
-        real, allocatable :: masout_ch(:)
-        real, allocatable :: masout_ct(:)
-        real, allocatable :: masout_ckt(:)
-    end type
-
-    type(datatype_outMAS1) :: data_outMAS
+    !type :: datatype_outMAS1
+    !    real, allocatable :: masout_zl(:)
+    !    real, allocatable :: masout_ri(:)
+    !    real, allocatable :: masout_re(:)
+    !    real, allocatable :: masout_lnzuzt(:)
+    !    real, allocatable :: masout_zu(:)
+    !    real, allocatable :: masout_ztout(:)
+    !    real, allocatable :: masout_rith(:)
+    !    real, allocatable :: masout_cm(:)
+    !    real, allocatable :: masout_ch(:)
+    !    real, allocatable :: masout_ct(:)
+    !    real, allocatable :: masout_ckt(:)
+    !end type
+
+    type(sfxDataVecType) :: data_outMAS
 
     !output
     !masout_zl - non-dimensional cfl hight
@@ -101,18 +101,17 @@
     allocate(meteo%z0_m(numst))
 
 
-
-    allocate(data_outMAS%masout_zl(numst))
-    allocate(data_outMAS%masout_ri(numst))
-    allocate(data_outMAS%masout_re(numst))
-    allocate(data_outMAS%masout_lnzuzt(numst))
-    allocate(data_outMAS%masout_zu(numst))
-    allocate(data_outMAS%masout_ztout(numst))
-    allocate(data_outMAS%masout_rith(numst))
-    allocate(data_outMAS%masout_cm(numst))
-    allocate(data_outMAS%masout_ch(numst))
-    allocate(data_outMAS%masout_ct(numst))
-    allocate(data_outMAS%masout_ckt(numst))
+    allocate(data_outMAS%zeta(numst))
+    allocate(data_outMAS%Rib(numst))
+    allocate(data_outMAS%Re(numst))
+    allocate(data_outMAS%B(numst))
+    allocate(data_outMAS%z0_m(numst))
+    allocate(data_outMAS%z0_t(numst))
+    allocate(data_outMAS%Rib_conv_lim(numst))
+    allocate(data_outMAS%Cm(numst))
+    allocate(data_outMAS%Ct(numst))
+    allocate(data_outMAS%Km(numst))
+    allocate(data_outMAS%Pr_t_inv(numst))
 
     open (11, file=filename_in2, status ='old')
     open (1, file= filename_in, status ='old')
@@ -128,11 +127,11 @@
         meteo%z0_m(i)=z0in
     enddo
 
-    CALL surf_flux_vec(meteo, &
-            data_outMAS%masout_zl, data_outMAS%masout_ri, data_outMAS%masout_re, data_outMAS%masout_lnzuzt,&
-            data_outMAS%masout_zu,data_outMAS%masout_ztout,data_outMAS%masout_rith,data_outMAS%masout_cm,&
-            data_outMAS%masout_ch,data_outMAS%masout_ct,data_outMAS%masout_ckt,&
-            data_par1, data_lutyp1,numst)
+    CALL get_surface_fluxes_vec(data_outMAS, meteo, &
+            !data_outMAS%zeta, data_outMAS%Rib, data_outMAS%Re, data_outMAS%B,&
+            !data_outMAS%z0_m,data_outMAS%z0_t,data_outMAS%Rib_conv_lim,data_outMAS%Cm,&
+            !data_outMAS%Ct,data_outMAS%Km,data_outMAS%Pr_t_inv,&
+            data_par1, numst)
 
     !CALL surf_fluxMAS(meteo%mas_w, meteo%mas_dt, meteo%mas_st, meteo%mas_dq,&
     !        meteo%mas_cflh, meteo%mas_z0in,&
@@ -142,9 +141,9 @@
     !        data_par1, data_lutyp1,numst)
 
     do i=1,numst
-        write (2,20) data_outMAS%masout_zl(i), data_outMAS%masout_ri(i), data_outMAS%masout_re(i), data_outMAS%masout_lnzuzt(i),&
-                data_outMAS%masout_zu(i), data_outMAS%masout_ztout(i), data_outMAS%masout_rith(i), data_outMAS%masout_cm(i),&
-                data_outMAS%masout_ch(i), data_outMAS%masout_ct(i), data_outMAS%masout_ckt(i)
+        write (2,20) data_outMAS%zeta(i), data_outMAS%Rib(i), data_outMAS%Re(i), data_outMAS%B(i),&
+                data_outMAS%z0_m(i), data_outMAS%z0_t(i), data_outMAS%Rib_conv_lim(i), data_outMAS%Cm(i),&
+                data_outMAS%Ct(i), data_outMAS%Km(i), data_outMAS%Pr_t_inv(i)
     enddo
 
 
@@ -155,18 +154,17 @@
     deallocate(meteo%dQ)
     deallocate(meteo%z0_m)
 
-
-    deallocate(data_outMAS%masout_zl)
-    deallocate(data_outMAS%masout_ri)
-    deallocate(data_outMAS%masout_re)
-    deallocate(data_outMAS%masout_lnzuzt)
-    deallocate(data_outMAS%masout_zu)
-    deallocate(data_outMAS%masout_ztout)
-    deallocate(data_outMAS%masout_rith)
-    deallocate(data_outMAS%masout_cm)
-    deallocate(data_outMAS%masout_ch)
-    deallocate(data_outMAS%masout_ct)
-    deallocate(data_outMAS%masout_ckt)
+    deallocate(data_outMAS%zeta)
+    deallocate(data_outMAS%Rib)
+    deallocate(data_outMAS%Re)
+    deallocate(data_outMAS%B)
+    deallocate(data_outMAS%z0_m)
+    deallocate(data_outMAS%z0_t)
+    deallocate(data_outMAS%Rib_conv_lim)
+    deallocate(data_outMAS%Cm)
+    deallocate(data_outMAS%Ct)
+    deallocate(data_outMAS%Km)
+    deallocate(data_outMAS%Pr_t_inv)
 
 
     10 format (f8.4,2x,f8.4)
diff --git a/sfx_phys_const.f90 b/sfx_phys_const.f90
new file mode 100644
index 0000000..8c8ec1c
--- /dev/null
+++ b/sfx_phys_const.f90
@@ -0,0 +1,12 @@
+module sfx_phys_const
+    !> @brief general physics constants
+    !> @details  all in SI units
+    implicit none
+    public
+
+    real, parameter :: g = 9.81                 !> acceleration due to gravity [m/s^2]
+
+    real, parameter :: nu_air = 0.000015e0      !> kinematic viscosity of air [m^2/s]
+    real, parameter :: Pr_m = 0.71              !> molecular Prandtl number (air) [n/d]
+
+end module sfx_phys_const
-- 
GitLab