From 1262b184f5a1228b96fb82a6556ce895834e8190 Mon Sep 17 00:00:00 2001
From: Evgeny Mortikov <evgeny.mortikov@gmail.com>
Date: Mon, 23 Sep 2024 05:01:47 +0300
Subject: [PATCH] adding surface thermal roughness module

---
 CMakeLists.txt                 |   1 +
 srcF/sfx_surface.f90           |   1 +
 srcF/sfx_thermal_roughness.f90 | 141 +++++++++++++++++++++++++++++++++
 3 files changed, 143 insertions(+)
 create mode 100644 srcF/sfx_thermal_roughness.f90

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7304bb4..277b8a6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,6 +69,7 @@ set(SOURCES_F
     srcF/sfx_run.f90
     srcF/sfx_phys_const.f90
     srcF/sfx_surface.f90
+    srcF/sfx_thermal_roughness.f90
     srcF/sfx_most.f90
     srcF/sfx_most_param.f90
     srcF/sfx_sheba.f90
diff --git a/srcF/sfx_surface.f90 b/srcF/sfx_surface.f90
index 79ebca9..8b808f5 100644
--- a/srcF/sfx_surface.f90
+++ b/srcF/sfx_surface.f90
@@ -132,6 +132,7 @@ contains
         surface_param%B_max_land = B_max_land
     end subroutine set_c_struct_sfx_surface_param_values
 #endif
+
     ! charnock roughness definition
     ! --------------------------------------------------------------------------------
     subroutine get_charnock_roughness(z0_m, u_dyn0, U, h, maxiters)
diff --git a/srcF/sfx_thermal_roughness.f90 b/srcF/sfx_thermal_roughness.f90
new file mode 100644
index 0000000..04755f7
--- /dev/null
+++ b/srcF/sfx_thermal_roughness.f90
@@ -0,0 +1,141 @@
+module sfx_thermal_roughness
+    !< @brief surface thermal roughness parameterizations
+
+    ! modules used
+    ! --------------------------------------------------------------------------------
+    use sfx_phys_const
+    use sfx_surface
+    ! --------------------------------------------------------------------------------
+
+    ! directives list
+    ! --------------------------------------------------------------------------------
+    implicit none
+    ! --------------------------------------------------------------------------------
+
+    ! public interface
+    ! --------------------------------------------------------------------------------
+    public :: get_thermal_roughness_kl
+    public :: get_thermal_roughness_cz
+    public :: get_thermal_roughness_zi
+    public :: get_thermal_roughness_ca
+    ! --------------------------------------------------------------------------------
+
+    ! --------------------------------------------------------------------------------
+    real, parameter, private :: kappa = 0.40         !< von Karman constant [n/d]
+    ! --------------------------------------------------------------------------------
+
+contains
+
+
+    ! thermal roughness definition by (Kazakov, Lykosov)
+    ! --------------------------------------------------------------------------------
+    subroutine get_thermal_roughness_kl(z0_t, B, &
+            z0_m, Re, surface_type)
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: z0_t               !< thermal roughness [m]
+        real, intent(out) :: B                  !< = log(z0_m / z0_t) [n/d]
+
+        real, intent(in) :: z0_m                !< aerodynamic roughness [m]
+        real, intent(in) :: Re                  !< roughness Reynolds number [n/d]
+        integer, intent(in) :: surface_type     !< = [ocean] || [land] || [lake]
+        ! ----------------------------------------------------------------------------
+
+        ! --- local variables
+        ! ----------------------------------------------------------------------------
+
+        !--- define B = log(z0_m / z0_t)
+        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)
+        else if (surface_type == surface_lake) then
+            B = min(B, B_max_lake)
+        else if (surface_type == surface_land) then
+            B = min(B, B_max_land)
+        end if
+
+        ! --- define roughness [thermal]
+        z0_t = z0_m / exp(B)
+
+    end subroutine
+    ! --------------------------------------------------------------------------------
+
+    ! thermal roughness definition by (Chen, F., Zhang, Y., 2009)
+    ! --------------------------------------------------------------------------------
+    subroutine get_thermal_roughness_cz(z0_t, B, &
+            z0_m, Re, surface_type)
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: z0_t               !< thermal roughness [m]
+        real, intent(out) :: B                  !< = log(z0_m / z0_t) [n/d]
+
+        real, intent(in) :: z0_m                !< aerodynamic roughness [m]
+        real, intent(in) :: Re                  !< roughness Reynolds number [n/d]
+        integer, intent(in) :: surface_type     !< = [ocean] || [land] || [lake]
+
+        ! --- local variables
+        ! ----------------------------------------------------------------------------
+
+        !--- define B = log(z0_m / z0_t)
+        B = (kappa * 10.0**(-0.4 * z0_m / 0.07)) * (Re**0.45)
+
+        ! --- define roughness [thermal]
+        z0_t = z0_m / exp(B)
+
+    end subroutine
+    ! --------------------------------------------------------------------------------
+    
+    ! thermal roughness definition by (Zilitinkevich, S., 1995)
+    ! --------------------------------------------------------------------------------
+    subroutine get_thermal_roughness_zi(z0_t, B, &
+            z0_m, Re, surface_type)
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: z0_t               !< thermal roughness [m]
+        real, intent(out) :: B                  !< = log(z0_m / z0_t) [n/d]
+
+        real, intent(in) :: z0_m                !< aerodynamic roughness [m]
+        real, intent(in) :: Re                  !< roughness Reynolds number [n/d]
+        integer, intent(in) :: surface_type     !< = [ocean] || [land] || [lake]
+
+        ! --- local variables
+        ! ----------------------------------------------------------------------------
+
+        !--- define B = log(z0_m / z0_t)
+        B = 0.1 * kappa * (Re**0.5)
+
+        ! --- define roughness [thermal]
+        z0_t = z0_m / exp(B)
+
+    end subroutine
+    ! --------------------------------------------------------------------------------
+    
+    ! thermal roughness definition by (Cahill, A.T., Parlange, M.B., Albertson, J.D., 1997)
+    ! --------------------------------------------------------------------------------
+    subroutine get_thermal_roughness_ca(z0_t, B, &
+            z0_m, Re, surface_type)
+        ! ----------------------------------------------------------------------------
+        real, intent(out) :: z0_t               !< thermal roughness [m]
+        real, intent(out) :: B                  !< = log(z0_m / z0_t) [n/d]
+
+        real, intent(in) :: z0_m                !< aerodynamic roughness [m]
+        real, intent(in) :: Re                  !< roughness Reynolds number [n/d]
+        integer, intent(in) :: surface_type     !< = [ocean] || [land] || [lake]
+
+        ! --- local variables
+        ! ----------------------------------------------------------------------------
+
+        !--- define B = log(z0_m / z0_t)
+        B = 2.46 * (Re**0.25) - 3.8
+
+        ! --- define roughness [thermal]
+        z0_t = z0_m / exp(B)
+
+    end subroutine
+    ! --------------------------------------------------------------------------------
+
+end module sfx_thermal_roughness
-- 
GitLab