diff --git a/CMakeLists.txt b/CMakeLists.txt index fa085b59..a5c4c493 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,13 @@ ecbuild_add_option( REQUIRED_PACKAGES "OpenMP COMPONENTS Fortran" ) +ecbuild_add_option( + FEATURE LOKI + DEFAULT ON + DESCRIPTION "Use Loki source-to-source processing" + REQUIRED_PACKAGES "loki" +) + set( _PRECISIONS "" ) ecbuild_add_option( FEATURE DOUBLE_PRECISION @@ -126,6 +133,9 @@ foreach( PREC IN LISTS _PRECISIONS ) add_subdirectory(ifsrrtm ifsrrtm.${PREC}) add_subdirectory(radiation radiation.${PREC}) add_subdirectory(ifs ifs.${PREC}) + if( HAVE_LOKI ) + add_subdirectory(loki loki.${PREC}) + endif() add_subdirectory(driver driver.${PREC}) endforeach() diff --git a/driver/CMakeLists.txt b/driver/CMakeLists.txt index 3f92e260..b3be3aca 100644 --- a/driver/CMakeLists.txt +++ b/driver/CMakeLists.txt @@ -49,6 +49,32 @@ ecbuild_add_executable( driver_lib.${PREC} ) +if( TARGET ecrad_loki.${PREC} ) + # Use a different module directory here to avoid conflicts because + # ifs_blocking.F90 is built twice but its .mod file is written to + # the same module directory + set( _CMAKE_Fortran_MODULE_DIRECTORY "${CMAKE_Fortran_MODULE_DIRECTORY}" ) + get_target_property( CMAKE_Fortran_MODULE_DIRECTORY ecrad_loki.${PREC} Fortran_MODULE_DIRECTORY ) + + ecbuild_add_executable( + TARGET ecrad_loki_${PREC} + SOURCES + ecrad_ifs_driver_blocked.F90 + ifs_blocking.F90 + ecrad_driver_read_input.F90 + ecrad_driver_config.F90 + DEFINITIONS + $<$:NO_OPENMP> + LIBS + ecrad_loki.${PREC} + ecrad_base.${PREC} + $<${HAVE_OMP}:OpenMP::OpenMP_Fortran> + ) + + # Reset the module directory + set( CMAKE_Fortran_MODULE_DIRECTORY "${_CMAKE_Fortran_MODULE_DIRECTORY}" ) +endif() + # For ecrad_ifs_driver_blocked we have to disable bounds checking # (which is enabled in Debug builds) because sequence association # and values initialized to -9999 for unused arguments is used in diff --git a/ifs/CMakeLists.txt b/ifs/CMakeLists.txt index f3de0083..2d586a39 100644 --- a/ifs/CMakeLists.txt +++ b/ifs/CMakeLists.txt @@ -29,3 +29,7 @@ ecbuild_add_library( ecrad.${PREC} ecrad_base.${PREC} ) + +# Export the list of sources for Loki processing +list( TRANSFORM ifs_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/" ) +set( ifs_SOURCES ${ifs_SOURCES} PARENT_SCOPE ) diff --git a/ifsaux/CMakeLists.txt b/ifsaux/CMakeLists.txt index 8734d7b3..bbba537b 100644 --- a/ifsaux/CMakeLists.txt +++ b/ifsaux/CMakeLists.txt @@ -28,3 +28,7 @@ ecbuild_add_library( PRIVATE_LIBS ecrad_base.${PREC} ) install( TARGETS ecrad_ifsaux.${PREC} EXPORT ecrad-targets ) + +# Export the list of sources for Loki processing +list( TRANSFORM ifsaux_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/" ) +set( ifsaux_SOURCES ${ifsaux_SOURCES} PARENT_SCOPE ) diff --git a/ifsrrtm/CMakeLists.txt b/ifsrrtm/CMakeLists.txt index 92054aee..09fe06e0 100644 --- a/ifsrrtm/CMakeLists.txt +++ b/ifsrrtm/CMakeLists.txt @@ -251,3 +251,7 @@ install( DESTINATION ${ecrad_${PREC}_INSTALL_INCLUDEDIR} ) install( TARGETS ifsrrtm.${PREC} EXPORT ecrad-targets ) + +# Export the list of sources for Loki processing +list( TRANSFORM ifsrrtm_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/" ) +set( ifsrrtm_SOURCES ${ifsrrtm_SOURCES} PARENT_SCOPE ) diff --git a/loki/CMakeLists.txt b/loki/CMakeLists.txt new file mode 100644 index 00000000..dd4843c7 --- /dev/null +++ b/loki/CMakeLists.txt @@ -0,0 +1,54 @@ +# (C) Copyright 2014- ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation +# nor does it submit to any jurisdiction. + +set( CMAKE_Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" ) + +set( ecrad_loki_SOURCE_DIRS "" ) +set( target_list + ecrad_ifsaux.${PREC} + ecrad_utilities.${PREC} + ifsrrtm.${PREC} + ecrad.${PREC} + ifs.${PREC} +) + +foreach( tgt IN LISTS target_list ) + get_target_property( ${tgt}_SOURCE_DIR ${tgt} SOURCE_DIR ) + list( APPEND ecrad_loki_SOURCE_DIRS "${${tgt}_SOURCE_DIR}" ) +endforeach() + +ecbuild_add_library( + TARGET + ecrad_loki.${PREC} + SOURCES + ${ifsaux_SOURCES} + ${utilities_SOURCES} + ${ifsrrtm_SOURCES} + ${radiation_SOURCES} + ${ifs_SOURCES} + PRIVATE_INCLUDES + ${ecrad_loki_SOURCE_DIRS} + PUBLIC_INCLUDES + "$" + "$" + "$" + PRIVATE_LIBS + ecrad_base.${PREC} + NetCDF::NetCDF_Fortran + $<${HAVE_OMP}:OpenMP::OpenMP_Fortran> +) + +loki_transform_target( + TARGET ecrad_loki.${PREC} + MODE idem + CONFIG ${CMAKE_CURRENT_SOURCE_DIR}/ecrad_loki.config + PLAN ${CMAKE_CURRENT_BINARY_DIR}/ecrad_loki_plan.${PREC}.cmake + SOURCES ${ecrad_loki_SOURCE_DIRS} + NO_PLAN_SOURCEDIR +) diff --git a/loki/ecrad_loki.config b/loki/ecrad_loki.config new file mode 100644 index 00000000..a5bbc72b --- /dev/null +++ b/loki/ecrad_loki.config @@ -0,0 +1,97 @@ +# ------------------------------------------------------------------- +# Loki source transformation configurations +# ------------------------------------------------------------------- +# This file contains configurations for multiple source transformation +# pipelines and batch processing settings to apply Loki transformations +# to the ecrad source tree. + + +# Loki batch scheduler configuration +# ------------------------------------------------------------------- +# The Loki batch scheduler performs automated discovery of call trees +# from a select set of seed subroutines. Whenever it adds new +# nodes to the call tree, the following default behaviour will be +# honoured, unless it is specifically overwritten below. + +[default] +role = 'kernel' # Role to determine how to transform a routine +expand = true # Automatically expand call tree to subroutine calls +strict = true # Throw exceptions during dicovery +enable_imports = true # Chase dependencies incurred via imports + +# Ensure that we are never adding these to the tree, and thus +# do not attempt to look up the source files for these. +disable = [ + 'delta_eddington*', 'fast_expm_exchange', 'date_and_time', 'get_command', + 'rng_type', 'radiation_reverse', 'yomhook', 'netcdf', 'ec_lun', +] + +# Prune these modules from the tree to ensure they are not processed by +# transformations +ignore = ['parkind1', 'easy_netcdf'] + + +# Frontend argument overrides +# ------------------------------------------------------------------- +# Certain modules hard depend on preprocessing +[frontend_args] + +[frontend_args."radiation_random_numbers.F90"] + preprocess = true + +[frontend_args."radiation_spartacus_sw.F90"] + preprocess = true + +[frontend_args."radiation_two_stream.F90"] + preprocess = true + + +# Call tree entry points ("driver" subroutines) +# ------------------------------------------------------------------- +# +# Note that Loki differentiates between "driver" routines, which act as +# call tree roots and contain the offload and parallelisation loops, and +# "kernel" routines that only contain compute loops and are called +# from drivers or other kernels within parallel sections. +[routines] + +[routines.radiation] + role = 'driver' + expand = true + + +# Define specific transformation settings +# ------------------------------------------------------------------- +# The section configures the invididual steps of the transformation +# pipelines. Importantly, it also defines the class name and Python +# module that Transformation objects will be instatiated from. +[transformations] + +# A set of utility transformations +# ------------------------------------------------------------------- +[transformations.Idem] + classname = 'IdemTransformation' + module = 'loki.transformations' + +# Housekeeping and other transformations +# ------------------------------------------------------------------- +[transformations.Sanitise] + classname = 'SanitiseTransformation' + module = 'loki.transformations' + options = { resolve_associate_mappings = true } + +[transformations.FileWriteTransformation] + classname = 'FileWriteTransformation' + module = 'loki.transformations' + options = { include_module_var_imports = true } + + +# Full transformation pipelines +# ------------------------------------------------------------------- +# The entries below are mapped to the "mode" entry point in +# loki-transform.py. The define the set of transformation and the +# order in which they are applies to the complete call tree. +[pipelines] + +[pipelines.idem] + transformations = ['Idem'] diff --git a/radiation/CMakeLists.txt b/radiation/CMakeLists.txt index 5ece789a..89db2102 100644 --- a/radiation/CMakeLists.txt +++ b/radiation/CMakeLists.txt @@ -107,3 +107,7 @@ if( CMAKE_Fortran_COMPILER_ID MATCHES "Intel" ) set_source_files_properties( radiation_mcica_sw.F90 PROPERTIES COMPILE_OPTIONS "-vecabi=cmdtarget") set_source_files_properties( radiation_cloud_generator.F90 PROPERTIES COMPILE_OPTIONS "-vecabi=cmdtarget") endif() + +# Export the list of sources for Loki processing +list( TRANSFORM radiation_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/" ) +set( radiation_SOURCES ${radiation_SOURCES} PARENT_SCOPE ) diff --git a/test/ifs/CMakeLists.txt b/test/ifs/CMakeLists.txt index 1b82c4c8..489b3d61 100644 --- a/test/ifs/CMakeLists.txt +++ b/test/ifs/CMakeLists.txt @@ -66,17 +66,19 @@ function( add_ecrad_ifs_test ) DEPENDS config_${_PAR_NAME}_${PREC} ) - foreach( binary ecrad_${PREC} ecrad_ifs_${PREC} ecrad_ifs_blocked_${PREC} ) - - ecbuild_add_test( - TARGET ${binary}_${_PAR_NAME}_net - COMMAND ${binary} - ARGS - ${CONFIG_NET_NAM} - ${TEST_IFS_INPUT} - output_${binary}_${_PAR_NAME}_net.nc - DEPENDS config_${_PAR_NAME}_${PREC}_net - ) + foreach( binary ecrad_${PREC} ecrad_ifs_${PREC} ecrad_ifs_blocked_${PREC} ecrad_loki_${PREC} ) + + if( TARGET ${binary} ) + ecbuild_add_test( + TARGET ${binary}_${_PAR_NAME}_net + COMMAND ${binary} + ARGS + ${CONFIG_NET_NAM} + ${TEST_IFS_INPUT} + output_${binary}_${_PAR_NAME}_net.nc + DEPENDS config_${_PAR_NAME}_${PREC}_net + ) + endif() endforeach() diff --git a/utilities/CMakeLists.txt b/utilities/CMakeLists.txt index 7f70494d..3381d8e7 100644 --- a/utilities/CMakeLists.txt +++ b/utilities/CMakeLists.txt @@ -41,3 +41,7 @@ install( DESTINATION ${ecrad_${PREC}_INSTALL_INCLUDEDIR} ) install( TARGETS ecrad_utilities.${PREC} EXPORT ecrad-targets ) + +# Export the list of sources for Loki processing +list( TRANSFORM utilities_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/" ) +set( utilities_SOURCES ${utilities_SOURCES} PARENT_SCOPE )