From ce4630f36dea2fd3c7a0d1d699c83f3d0c8370b3 Mon Sep 17 00:00:00 2001
From: Evgeny Mortikov <evgeny.mortikov@gmail.com>
Date: Mon, 23 Sep 2024 04:46:29 +0300
Subject: [PATCH] adding inmcm, term api and usage examples

---
 CMakeLists.txt                | 22 ++++++++++--
 api-examples/sfx_inmcm_ex.f90 | 41 +++++++++++++++++++++
 api-examples/sfx_term_ex.f90  | 41 +++++++++++++++++++++
 srcF/sfx_api_inmcm.f90        | 67 +++++++++++++++++++++++++++++++++++
 srcF/sfx_api_term.f90         | 67 +++++++++++++++++++++++++++++++++++
 5 files changed, 236 insertions(+), 2 deletions(-)
 create mode 100644 api-examples/sfx_inmcm_ex.f90
 create mode 100644 api-examples/sfx_term_ex.f90
 create mode 100644 srcF/sfx_api_inmcm.f90
 create mode 100644 srcF/sfx_api_term.f90

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 492fe28..7304bb4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,6 +6,8 @@ option(BUILD_DOC    "Build documentation"    OFF)
 option(SFX_CHECK_NAN    "Build documentation"    OFF)
 option(USE_CONFIG_PARSER "Build config parser"    ON)
 
+include(FetchContent)
+
 project(INMCM_sfx)
 enable_language(Fortran)
 
@@ -65,7 +67,6 @@ set(SOURCES_F
     srcF/sfx_log.f90
     srcF/sfx_log_param.f90
     srcF/sfx_run.f90
-    srcF/sfx_main.f90
     srcF/sfx_phys_const.f90
     srcF/sfx_surface.f90
     srcF/sfx_most.f90
@@ -73,7 +74,11 @@ set(SOURCES_F
     srcF/sfx_sheba.f90
     srcF/sfx_sheba_param.f90
     srcF/sfx_fc_wrapper.F90
+    srcF/sfx_api_inmcm.f90
+    srcF/sfx_api_term.f90
 )
+set(MAIN_F
+        srcF/sfx_main.f90)
 
 set(HEADERS_F
     includeF/sfx_def.fi
@@ -138,19 +143,32 @@ if(USE_CXX OR INCLUDE_CUDA)
     endif(INCLUDE_CUDA)
 endif(USE_CXX OR INCLUDE_CUDA)
 
-set(SOURCES ${MEMPROC_HEADERS_CU} ${MEMPROC_SOURCES_CU} ${MEMPROC_HEADERS_CXX} ${MEMPROC_SOURCES_CXX} ${HEADERS_CU} ${SOURCES_CU} ${HEADERS_C} ${HEADERS_CXX} ${SOURCES_CXX} ${SOURCES_C} ${HEADERS_F} ${SOURCES_F})
+set(SOURCES 
+    ${MEMPROC_HEADERS_CU} ${MEMPROC_SOURCES_CU} ${MEMPROC_HEADERS_CXX} ${MEMPROC_SOURCES_CXX} 
+    ${HEADERS_CU} ${SOURCES_CU} ${HEADERS_C} ${HEADERS_CXX} ${SOURCES_CXX} ${SOURCES_C} 
+    ${HEADERS_F} ${SOURCES_F} ${MAIN_F})
+set(SOURCES_LIB 
+    ${MEMPROC_HEADERS_CU} ${MEMPROC_SOURCES_CU} ${MEMPROC_HEADERS_CXX} ${MEMPROC_SOURCES_CXX} 
+    ${HEADERS_CU} ${SOURCES_CU} ${HEADERS_CXX} 
+    ${SOURCES_CXX} ${SOURCES_C} ${HEADERS_F} ${SOURCES_F})
 
 set(CMAKE_Fortran_FLAGS " -cpp ")
 
 add_executable(sfx ${SOURCES})
+add_library(sfx_lib ${SOURCES_LIB})
 set_property(TARGET sfx PROPERTY LINKER_LANGUAGE Fortran)
 target_include_directories(sfx PUBLIC ${CMAKE_BINARY_DIR}/modules/)
 target_include_directories(sfx PUBLIC ${HEADERS_DIRS})
 
 if(USE_CONFIG_PARSER)
     target_link_libraries(sfx config_parser_F config_parser_CXX)
+    target_link_libraries(sfx_lib config_parser_F config_parser_CXX)
 endif(USE_CONFIG_PARSER)
 
+set_property(TARGET sfx_lib PROPERTY LINKER_LANGUAGE Fortran)
+set(CMAKE_Fortran_ARCHIVE_FINISH  "<CMAKE_RANLIB> -no_warning_for_no_symbols -c <TARGET>")
+target_include_directories(sfx_lib PUBLIC ${CMAKE_BINARY_DIR}/modules/)
+
 if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
     target_compile_options(sfx
         PUBLIC $<$<COMPILE_LANGUAGE:C>: -g >)
diff --git a/api-examples/sfx_inmcm_ex.f90 b/api-examples/sfx_inmcm_ex.f90
new file mode 100644
index 0000000..754fae6
--- /dev/null
+++ b/api-examples/sfx_inmcm_ex.f90
@@ -0,0 +1,41 @@
+!< @brief an example of using SFX/INMCM interface
+program sfx_inmcm_ex
+    
+    !> SFX data structures
+    use sfx_data, only: meteoDataType, sfxDataType
+    !> SFX-INMCM interface
+    use sfx_api_inmcm
+    !> actual interface of ESM model
+    use sfx_esm, only: &
+        get_surface_fluxes_esm => get_surface_fluxes, &
+        numericsType_esm => numericsType
+
+    implicit none
+
+    type(meteoDataType) :: meteo_cell
+    type(sfxDataType) :: sfx_cell
+    type(numericsType_esm) :: numerics
+
+    !> INMCM surface layer uses legacy INMCM AR arrays for input/output
+    real :: AR1(6), AR2(11)
+
+
+    ! --- setting some dummy data
+    !   *: the actual values should be supplied by model
+    AR1(1) = 10.0       ! wind speed
+    AR1(2) = 0.0        ! difference between surface and air temperature
+    AR1(3) = 273.15     ! semi-sum of surface and air temperature
+    AR1(4) = 0.0        ! difference in surface and air specific humidity
+    AR1(5) = 2.0        ! height at which fluxes are evaluated
+    AR1(6) = 1.0e-3     ! surface roughness parameter 
+
+    ! --- converting AR input to SFX format -> meteo cell
+    call inmcm_to_sfx_in_cell(meteo_cell, AR1)
+    ! --- calculating fluxes
+    call get_surface_fluxes_esm(sfx_cell, meteo_cell, numerics)
+    ! --- converting SFX cell output to AR format
+    call sfx_to_inmcm_out_cell(AR2, sfx_cell) 
+    !   *: now AR can be passed to other parts of INMCM
+    
+    stop
+end program sfx_inmcm_ex
diff --git a/api-examples/sfx_term_ex.f90 b/api-examples/sfx_term_ex.f90
new file mode 100644
index 0000000..ed5450b
--- /dev/null
+++ b/api-examples/sfx_term_ex.f90
@@ -0,0 +1,41 @@
+!< @brief an example of using SFX/TerM interface
+program sfx_term_ex
+    
+    !> SFX data structures
+    use sfx_data, only: meteoDataType, sfxDataType
+    !> SFX-TerM interface
+    use sfx_api_term
+    !> actual interface of ESM model
+    use sfx_esm, only: &
+        get_surface_fluxes_esm => get_surface_fluxes, &
+        numericsType_esm => numericsType
+
+    implicit none
+
+    type(meteoDataType) :: meteo_cell
+    type(sfxDataType) :: sfx_cell
+    type(numericsType_esm) :: numerics
+
+    !> TerM surface layer uses legacy INMCM AR arrays for input/output
+    real :: AR1(6), AR2(11)
+
+
+    ! --- setting some dummy data
+    !   *: the actual values should be supplied by model
+    AR1(1) = 10.0       ! wind speed
+    AR1(2) = 0.0        ! difference between surface and air temperature
+    AR1(3) = 273.15     ! semi-sum of surface and air temperature
+    AR1(4) = 0.0        ! difference in surface and air specific humidity
+    AR1(5) = 2.0        ! height at which fluxes are evaluated
+    AR1(6) = 1.0e-3     ! surface roughness parameter 
+
+    ! --- converting AR input to SFX format -> meteo cell
+    call term_to_sfx_in_cell(meteo_cell, AR1)
+    ! --- calculating fluxes
+    call get_surface_fluxes_esm(sfx_cell, meteo_cell, numerics)
+    ! --- converting SFX cell output to AR format
+    call sfx_to_term_out_cell(AR2, sfx_cell) 
+    !   *: now AR can be passed to other parts of TerM
+    
+    stop
+end program sfx_term_ex
diff --git a/srcF/sfx_api_inmcm.f90 b/srcF/sfx_api_inmcm.f90
new file mode 100644
index 0000000..89e551a
--- /dev/null
+++ b/srcF/sfx_api_inmcm.f90
@@ -0,0 +1,67 @@
+!> @brief sfx-inmcm coupling API 
+module sfx_api_inmcm
+
+    ! modules used
+    ! --------------------------------------------------------------------------------
+    use sfx_data
+    ! --------------------------------------------------------------------------------
+
+    ! directives list
+    ! --------------------------------------------------------------------------------
+    implicit none
+    private
+    ! --------------------------------------------------------------------------------
+
+    ! public interface
+    ! --------------------------------------------------------------------------------
+    public :: inmcm_to_sfx_in_cell, sfx_to_inmcm_out_cell
+    ! --------------------------------------------------------------------------------
+
+contains
+    
+    ! --------------------------------------------------------------------------------
+    subroutine inmcm_to_sfx_in_cell(meteo, arg)
+        !> @brief converts legacy arg [AR1 INMCM format] array to sfx meteo input
+        ! ----------------------------------------------------------------------------
+        implicit none
+        type (meteoDataType), intent(inout) :: meteo
+        real, dimension(6), intent(in)      :: arg
+        ! ----------------------------------------------------------------------------
+        
+        
+        meteo%U = arg(1)
+        meteo%dT = arg(2)
+        meteo%Tsemi = arg(3)
+        meteo%dQ = arg(4)
+        meteo%h = arg(5)
+        meteo%z0_m = arg(6)
+
+    end subroutine inmcm_to_sfx_in_cell
+    ! --------------------------------------------------------------------------------
+    
+    ! --------------------------------------------------------------------------------
+    subroutine sfx_to_inmcm_out_cell(arg, sfx)
+        !> @brief converts sfx cell output to legacy arg [AR2 INMCM format] array
+        ! ----------------------------------------------------------------------------
+        implicit none
+        type(sfxDataType), intent(in) :: sfx
+        real, dimension(11), intent(inout) :: arg
+        ! ----------------------------------------------------------------------------
+
+
+        arg(1) = sfx%zeta
+        arg(2) = sfx%Rib
+        arg(3) = sfx%Re
+        arg(4) = sfx%B
+        arg(5) = sfx%z0_m
+        arg(6) = sfx%z0_t
+        !arg(7) = 0.0       ! arg(7) is never used in legacy code
+        arg(8) = sfx%Cm
+        arg(9) = sfx%Ct
+        arg(10) = sfx%Km
+        arg(11) = sfx%Pr_t_inv
+
+    end subroutine sfx_to_inmcm_out_cell
+    ! --------------------------------------------------------------------------------
+
+end module sfx_api_inmcm
diff --git a/srcF/sfx_api_term.f90 b/srcF/sfx_api_term.f90
new file mode 100644
index 0000000..a7a08c5
--- /dev/null
+++ b/srcF/sfx_api_term.f90
@@ -0,0 +1,67 @@
+!> @brief sfx-term coupling API 
+module sfx_api_term
+
+    ! modules used
+    ! --------------------------------------------------------------------------------
+    use sfx_data
+    ! --------------------------------------------------------------------------------
+
+    ! directives list
+    ! --------------------------------------------------------------------------------
+    implicit none
+    private
+    ! --------------------------------------------------------------------------------
+
+    ! public interface
+    ! --------------------------------------------------------------------------------
+    public :: term_to_sfx_in_cell, sfx_to_term_out_cell
+    ! --------------------------------------------------------------------------------
+
+contains
+    
+    ! --------------------------------------------------------------------------------
+    subroutine term_to_sfx_in_cell(meteo, arg)
+        !> @brief converts legacy arg [AR1 INMCM format] array to sfx meteo input
+        ! ----------------------------------------------------------------------------
+        implicit none
+        type (meteoDataType), intent(inout) :: meteo
+        real, dimension(6), intent(in)      :: arg
+        ! ----------------------------------------------------------------------------
+        
+        
+        meteo%U = arg(1)
+        meteo%dT = arg(2)
+        meteo%Tsemi = arg(3)
+        meteo%dQ = arg(4)
+        meteo%h = arg(5)
+        meteo%z0_m = arg(6)
+
+    end subroutine term_to_sfx_in_cell
+    ! --------------------------------------------------------------------------------
+    
+    ! --------------------------------------------------------------------------------
+    subroutine sfx_to_term_out_cell(arg, sfx)
+        !> @brief converts sfx cell output to legacy arg [AR2 INMCM format] array
+        ! ----------------------------------------------------------------------------
+        implicit none
+        type(sfxDataType), intent(in) :: sfx
+        real, dimension(11), intent(inout) :: arg
+        ! ----------------------------------------------------------------------------
+
+
+        arg(1) = sfx%zeta
+        arg(2) = sfx%Rib
+        arg(3) = sfx%Re
+        arg(4) = sfx%B
+        arg(5) = sfx%z0_m
+        arg(6) = sfx%z0_t
+        !arg(7) = 0.0       ! arg(7) is never used in legacy code
+        arg(8) = sfx%Cm
+        arg(9) = sfx%Ct
+        arg(10) = sfx%Km
+        arg(11) = sfx%Pr_t_inv
+
+    end subroutine sfx_to_term_out_cell
+    ! --------------------------------------------------------------------------------
+
+end module sfx_api_term
-- 
GitLab