From c1e705f6332b4743c682a294751254b81d16c28a Mon Sep 17 00:00:00 2001
From: Evgeny Mortikov <evgeny.mortikov@gmail.com>
Date: Sun, 17 Dec 2023 04:58:11 +0300
Subject: [PATCH] major code update

---
 drag3.f90     | 624 ++++++++++++++++++++++++++++++++++----------------
 inputdata.f90 |  12 +-
 main_drag.f90 |  76 +++---
 param.f90     |  64 ++++--
 4 files changed, 515 insertions(+), 261 deletions(-)

diff --git a/drag3.f90 b/drag3.f90
index 6b20aeb..c93706f 100644
--- a/drag3.f90
+++ b/drag3.f90
@@ -1,21 +1,44 @@
     MODULE drag3
         USE param
-        USE inputdata
 
         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:: data_in
-	        real, public:: ws, dt, st, dq, cflh, z0in
+        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:: data_outdef
-	        real, public:: zl, ri, re, lnzuzt, zu, ztout, rith, cm, ch, ct, ckt
+
+        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_par
-	        integer, public :: it=10
-	    end type
 
         type, public:: data_lutyp
             integer, public :: lu_indx=1
@@ -23,18 +46,13 @@
 
     contains
 
-        ! SUBROUTINE  surf_fluxMAS(mas1_w, mas1_dt, mas1_st, mas1_dq, out, par1, lu1)
-        SUBROUTINE surf_fluxMAS(mas1_w, mas1_dt, mas1_st, mas1_dq, mas1_cflh, mas1_z0in, &
+        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,&
-                par1, lu1,numst)
+                numerics, lu1,numst)
 
-            real, dimension (numst) ::  mas1_w
-            real, dimension (numst) ::  mas1_dt
-            real, dimension (numst) ::  mas1_st
-            real, dimension (numst) ::  mas1_dq
-            real, dimension (numst) ::  mas1_cflh
-            real, dimension (numst) ::  mas1_z0in
+            type (meteoDataVecType), intent(in) :: meteo
+            type (numericsType), intent(in) :: numerics
 
             real, dimension (numst) :: masout_zl
             real, dimension (numst) :: masout_ri
@@ -48,222 +66,438 @@
             real, dimension (numst) :: masout_ct
             real, dimension (numst) :: masout_ckt
 
-            type (data_in)  in
-            type (data_outdef) out
-            type (data_par) par1
+            type (meteoDataType)  meteo_cell
+            type (sfxDataType) sfx_cell
+
             type (data_lutyp) lu1
             integer i,numst
 
-            do i=1,numst
-                in%ws=mas1_w(i)
-                in%dt=mas1_dt(i)
-                in%st=mas1_st(i)
-                in%dq=mas1_dq(i)
-                in%cflh=mas1_cflh(i)
-                in%z0in=mas1_z0in(i)
-
-                !if ((in%ws == in%ws).and.(in%dt == in%dt).and.(in%st == in%st).and.(in%dq == in%dq)) then
-                    CALL surf_flux(in, out, par1, lu1)
-                !end if
-
-                masout_zl(i)=out%zl
-                masout_ri(i)=out%ri
-                masout_re(i)=out%re
-                masout_lnzuzt(i)=out%lnzuzt
-                masout_zu(i)=out%zu
-                masout_ztout(i)=out%ztout
-                masout_rith(i)=out%rith
-                masout_cm(i)=out%cm
-                masout_ch(i)=out%ch
-                masout_ct(i)=out%ct
-                masout_ckt(i)=out%ckt
+            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_fluxMAS
+        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
 
-        SUBROUTINE  surf_flux(in, out, par, lu)
-            type (data_in) , intent(in) :: in
-            type (data_outdef) out
-            type (data_par) par
             type (data_lutyp) lu
 
-            real ws, dt, dq, cflh, z0in
-	        integer it
+            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
-            real zl, ri, re, lnzuzt, zu, ztin, ri_th, cm, ch, ct, ckt
-            real z0, d3, d0max, U10m, a1, y1, cimin, f, c1, u2, h0, u3, x7, d0, d00, zt, h00, ft0, an4, an5
-            real al, Tsurf, Rib, q4, t4, u, r1, f0, f4, am, o, dd, x1, y0, x0, y10, a2ch, x10, p1, p0, h, d1, f1
-            real d, c4, c1min, c0, c, b1, an0
+
+            ! 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
 
-            ws=in%ws
-            dt=in%dt
-            Tsurf=in%st
-            dq=in%dq
-            cflh=in%cflh
-            z0in=in%z0in
-            it=par%it
-	
-            u=ws
-            t4=dt
-            q4=dq
-            h=cflh
-            z0=z0in
-
-            AN5=(Pr_t_inf_inv / Pr_t_0_inv)**4
-            D1=(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=(1.0E0-alpha_m*D1)**.25E0
-            X10=(1.0E0-alpha_h*D1)**.5E0
-            P1=2.0E0*ATAN(Y10)+ALOG((Y10-1.0E0)/(Y10+1.0E0))
-            P0=ALOG((X10-1.0E0)/(X10+1.0E0))
-
-            d3=0.0e0
-            d0max=2.0e0
-
-            if(z0 < 0.0e0) then
+
+            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)
-                d0max = 8.0e0
-                U10m=u
-                a1=0.0e0
-                y1=25.0e0
-                c1min=alog(h1/1.0e0)/kappa
-                do i=1,it
-                    f=a2-2.0e0*alog(U10m)
-                    do j=1,it
-                        c1=(f+2.0e0*alog(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=alog(1.0e0+a3*((y1/U10m)**3))/kappa
-                        c1=c1-a1
-                        c1=max(c1,c1min)
-                        y1=c1
-                    end do
-                    z0=h1*exp(-c1*kappa)
-                    z0=max(z0,0.000015e0)
-                    U10m=u*alog(h1/z0)/(alog(h/z0))
-                end do
-                h0=h/z0
-                u3=U10m/c1
+                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......
-                h0=h/z0
-                u3=u*kappa/alog(h0)
+                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
 
-            x7=u3*z0/an
-            if(x7 <= x8) then
-                d0=an1*alog(al1*x7)+an2
+            ! --- apply max restriction based on surface type
+            if (is_ocean == 1) then
+                B = min(B, B_max_ocean)
             else
-                d0=al2*(x7**0.45e0)
+                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/Tsurf
-            d0=min(d0,d0max)
-            Rib=al*h*(t4+0.61e0*Tsurf*q4)/u**2
-            d00=d0
-            zt=z0/exp(d00)
-            h00=h/zt
-            ft0=alog(h00)
-            !     ......definition of r-prim......
-            an4=d1/h0
-            an5=d1/h00
-            if (abs(d0) < 1.0e-10) an5=an4
-            an5=sqrt(1.0e0-g0*an5)
-            an4=(1.0e0-alpha_m*an4)**0.25e0
-            f0=alog((x10-1.0e0)*(an5+1.0e0)/((x10+1.0e0)*(an5-1.0e0)))/Pr_t_0_inv
-            f4=2.0e0*(atan(y10)-atan(an4))+alog((y10-1.0e0)*(an4+1.0e0)/((y10+1.0e0)*(an4-1.0e0)))
-            r1=d1*f0/(f4*f4)
-            !     ......definition of dz,ta,fu,fo,fiu,fio......
+            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,r0)
-                f=alog(h0)
-                f1=d0/f
-                a1=b4*Rib
-                a2ch=(f1+1.0e0)/Pr_t_0_inv-2.0e0*a1
-                d3=f*(sqrt(a2ch**2+4.0e0*a1*(1.0e0-a1))-a2ch)/(2.0e0*b4*(1.0e0-a1))
-                f1=b4*d3
-                f4=f+f1
-                f0=(f+d0)/Pr_t_0_inv+f1
-                o=1.0e0/Pr_t_0_inv+f1
-                am=1.0e0+f1
-            else if (Rib < r1) then
+                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'
 
-                d3=d1
-                do i=1,it+1
-                    d=d3/h0
-                    dd=d3/h00
-                    if (abs(d0) < 1.0e-10) dd=d
-                    a1=(d1/d3)**(1.0e0/3.0e0)
-                    x0=sqrt(1.0e0-g0*dd)
-                    y0=(1.0e0-alpha_m*d)**0.25e0
-                    c=alog((x0+1.0e0)/(x0-1.0e0))
-                    b1=-2.0e0*atan(y0)+alog((y0+1.0e0)/(y0-1.0e0))
-                    f=3.0e0*(1.0e0-a1)
-                    f4=f/y10+p1+b1
-                    f0=(f/x10+p0+c)/Pr_t_0_inv
-                    if (i == it+1) exit
-                    d3=Rib*f4**2/f0
-                end do
-                am=a1/y10
-                o=a1/(Pr_t_0_inv*x10)
+                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'
-                f4=alog(h0)
-                f0=ft0/Pr_t_0_inv
-                if (abs(d0) < 1.0e-10) f0=f4/Pr_t_0_inv
-                am=1.0e0
-                o=1.0e0/Pr_t_0_inv
+
+                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'
-                f1=alog(h0)
-                if (abs(d0) < 1.0e-10) ft0=f1
-                d3=Rib*Pr_t_0_inv*f1**2/ft0
-                do i=1,it+1
-                    d=d3/h0
-                    dd=d3/h00
-                    if (abs(d0) < 1.0e-10) dd=d
-                    y1=(1.0e0-alpha_m*d3)**0.25e0
-                    x1=sqrt(1.0e0-g0*d3)
-                    y0=(1.0e0-alpha_m*d)**0.25e0
-                    x0=sqrt(1.0e0-g0*dd)
-                    y0=max(y0,1.000001e0)
-                    x0=max(x0,1.000001e0)
-                    f4=alog((y1-1.0e0)*(y0+1.0e0)/((y1+1.0e0)*(y0-1.0e0)))+2.0e0*(atan(y1)-atan(y0))
-                    f0=alog((x1-1.0e0)*(x0+1.0e0)/((x1+1.0e0)*(x0-1.0e0)))/Pr_t_0_inv
-                    if (i == it + 1) exit
-                    d3=Rib*f4**2/f0
-                end do
-                am=(1.0e0-alpha_m*d3)**(-0.25e0)
-                o=1.0e0/(Pr_t_0_inv*sqrt(1.0e0-g0*d3))
+
+                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/f4
-            c0=kappa/f0
-            an4=kappa*c4*u*h/am
+            c4=kappa/psi_m
+            c0=kappa/psi_h
+            an4=kappa*c4*U*h/am
             an0=am/o
 
             !     ......exit......
-            out%zl=d3
-            out%ri=Rib
-            out%re=x7
-            out%lnzuzt=d00
-            out%zu=z0
-            out%ztout=zt
-            out%rith=r1
-            out%cm=c4
-            out%ch=c0
-            out%ct=an4
-            out%ckt=an0
+            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
diff --git a/inputdata.f90 b/inputdata.f90
index 3543420..1e9a006 100644
--- a/inputdata.f90
+++ b/inputdata.f90
@@ -2,12 +2,12 @@ module INPUTDATA
    REAl, DIMENSION (6) :: AR1
    REAl, DIMENSION (11) :: AR2
    INTEGER, PARAMETER :: TEST=1 ! probably IT before renaming
-   INTEGER nums,ioer,mk
-   REAL HFX, MFX, zL, betta
-   REAL U, T4,c0,c4, T1,H,z0h
-   REAL ws, deltaT, semisumT, D00, Z0, ZT, deltaQ
-   REAL R6,R1
-   REAL AN5, D1, Y10, X10, P1, P0
+   !INTEGER nums,ioer,mk
+   !REAL HFX, MFX, zL, betta
+   !REAL U, T4,c0,c4, T1,H,z0h
+   !REAL ws, deltaT, semisumT, D00, Z0, ZT, deltaQ
+   !REAL R6,R1
+   !REAL AN5, Y10, X10, P1, P0
 
 !C*====================================================================
 !C*     .....DEFENITION OF DRAG AND HEAT EXCHANGE COEFFICIENTS......  =
diff --git a/main_drag.f90 b/main_drag.f90
index 0d18fcf..776bee4 100644
--- a/main_drag.f90
+++ b/main_drag.f90
@@ -4,11 +4,11 @@
     USE inputdata
 	USE drag3
 
-    type (data_in):: data_in1
+    type (meteoDataType):: data_in1
        
-	type (data_outdef) :: data_outdef1
+	type (sfxDataType) :: data_outdef1
 
-	type (data_par) :: data_par1
+	type (numericsType) :: data_par1
 
 
     type (data_lutyp) :: data_lutyp1
@@ -18,15 +18,15 @@
     character(len = 50) :: filename_out
     character(len = 50) :: filename_in2
 
-    type :: datatype_inMAS1
-        real, allocatable :: mas_w(:)    !
-        real, allocatable :: mas_dt(:)
-        real, allocatable :: mas_st(:)
-        real, allocatable :: mas_dq(:)
-        real, allocatable :: mas_cflh(:)
-        real, allocatable :: mas_z0in(:)
-    end type
-    type(datatype_inMAS1) :: data_inMAS
+    !type :: datatype_inMAS1
+    !    real, allocatable :: mas_w(:)    !
+    !    real, allocatable :: mas_dt(:)
+    !    real, allocatable :: mas_st(:)
+    !    real, allocatable :: mas_dq(:)
+    !    real, allocatable :: mas_cflh(:)
+    !    real, allocatable :: mas_z0in(:)
+    !end type
+    type(meteoDataVecType) :: meteo
 
     !input
     !  mas_w - abs(wind velocity) at constant flux layer (cfl) hight (m/s)
@@ -86,19 +86,19 @@
     open (2, file=filename_out)
     numst=0
     do WHILE (ioer.eq.0)
-        read (1,*, iostat=ioer)  data_in1%ws,  data_in1%dt,  data_in1%st,  data_in1%dq
+        read (1,*, iostat=ioer)  data_in1%U,  data_in1%dT,  data_in1%Tsemi,  data_in1%dQ
         numst=numst+1
     enddo
     close (1)
     numst=numst-1
 
 
-    allocate(data_inMAS%mas_w(numst))
-    allocate(data_inMAS%mas_dt(numst))
-    allocate(data_inMAS%mas_st(numst))
-    allocate(data_inMAS%mas_dq(numst))
-    allocate(data_inMAS%mas_cflh(numst))
-    allocate(data_inMAS%mas_z0in(numst))
+    allocate(meteo%h(numst))
+    allocate(meteo%U(numst))
+    allocate(meteo%dT(numst))
+    allocate(meteo%Tsemi(numst))
+    allocate(meteo%dQ(numst))
+    allocate(meteo%z0_m(numst))
 
 
 
@@ -118,23 +118,29 @@
     open (1, file= filename_in, status ='old')
     read (11, *) cflh, z0in
     do i=1,numst
-        read (1,*) data_in1%ws,  data_in1%dt,  data_in1%st,  data_in1%dq
-        data_inMAS%mas_w(i)=data_inMAS%mas_w(i)+data_in1%ws
-        data_inMAS%mas_dt(i)=data_inMAS%mas_dt(i)+data_in1%dt
-        data_inMAS%mas_st(i)=data_inMAS%mas_st(i)+data_in1%st
-        data_inMAS%mas_dq(i)=data_inMAS%mas_dq(i)+data_in1%dq
-        data_inMAS%mas_cflh(i)=cflh
-        data_inMAS%mas_z0in(i)=z0in
+        read (1,*) data_in1%U,  data_in1%dT,  data_in1%Tsemi,  data_in1%dQ
+
+        meteo%h(i)=cflh
+        meteo%U(i) = meteo%U(i)+data_in1%U
+        meteo%dT(i) = meteo%dT(i)+data_in1%dT
+        meteo%Tsemi(i) = meteo%Tsemi(i)+data_in1%Tsemi
+        meteo%dQ(i) = meteo%dQ(i)+data_in1%dQ
+        meteo%z0_m(i)=z0in
     enddo
 
-
-    CALL surf_fluxMAS(data_inMAS%mas_w, data_inMAS%mas_dt, data_inMAS%mas_st, data_inMAS%mas_dq,&
-            data_inMAS%mas_cflh, data_inMAS%mas_z0in,&
+    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 surf_fluxMAS(meteo%mas_w, meteo%mas_dt, meteo%mas_st, meteo%mas_dq,&
+    !        meteo%mas_cflh, meteo%mas_z0in,&
+    !        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)
+
     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),&
@@ -142,12 +148,12 @@
     enddo
 
 
-    deallocate(data_inMAS%mas_w)
-    deallocate(data_inMAS%mas_dt)
-    deallocate(data_inMAS%mas_st)
-    deallocate(data_inMAS%mas_dq)
-    deallocate(data_inMAS%mas_cflh)
-    deallocate(data_inMAS%mas_z0in)
+    deallocate(meteo%h)
+    deallocate(meteo%U)
+    deallocate(meteo%dT)
+    deallocate(meteo%Tsemi)
+    deallocate(meteo%dQ)
+    deallocate(meteo%z0_m)
 
 
     deallocate(data_outMAS%masout_zl)
diff --git a/param.f90 b/param.f90
index 16cc630..4a1519e 100644
--- a/param.f90
+++ b/param.f90
@@ -2,40 +2,54 @@ module param
       implicit none
       ! acceleration due to gravity [m/s^2]
       real, parameter :: g = 9.81
-      ! molecular Prandtl number (air)
+      ! 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
+      ! inverse Prandtl (turbulent) number in neutral conditions [n/d]
       real, parameter :: Pr_t_0_inv = 1.15
-      ! inverse Prandtl (turbulent) number in free convection
+      ! inverse Prandtl (turbulent) number in free convection [n/d]
       real, parameter :: Pr_t_inf_inv = 3.5
 
-      ! stability function coeff. [= g4 & g10 in deprecated code]
+      ! 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
 
-      real, parameter ::  b4=4.7e0
-      real, parameter ::  alfam=.0144e0
-      real, parameter ::  betam=.111e0
-      real, parameter ::  an=.000015e0
-      real, parameter ::  h1=10.0e0
-      real, parameter ::  x8=16.3e0
-      real, parameter ::  an1=5.0e0/6.0e0
-      real, parameter ::  an2=.45e0
-      real, parameter ::  al1=kappa*Pr_m
-      real, parameter ::  g0=1.2
-      real, parameter ::  al2=(.14e0*(30.0e0**an2))*(Pr_m**.8e0)
-      real, parameter ::  a2=alog(h1*(g/alfam))
-      real, parameter ::  a3=betam*an*a2
-      real, parameter ::  r0=.9e0/b4
-!C*      real, parameter ::  AN5=(A6/A0)**4
-!C*      real, parameter ::  D1=(2.0E0*G10-AN5*G4-SQRT((AN5*G4)**2+4.0E0*AN5*G10*(G10-G4)))/(2.0E0*G10**2)
-!C*      real, parameter ::  Y10=(1.0E0-G4*D1)**.25E0
-!C*      real, parameter ::  X10=(1.0E0-G10*D1)**.5E0
-!C*      real, parameter ::  P1=2.0E0*ATAN(Y10)+ALOG((Y10-1.0E0)/(Y10+1.0E0))
-!C*      real, parameter ::  P0=ALOG((X10-1.0E0)/(X10+1.0E0))
-      
 !      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
-- 
GitLab