1# Copyright (c) 2020 - 2025 David Guibert
2# Copyright (c) 2024 - 2025 Niclas Schroeter
3# Copyright (c) 2024 - 2025 Antoine Morvan
6# SPDX-License-Identifier: Apache-2.0
10set_property(GLOBAL PROPERTY ecrad_can_use_system TRUE)
11set_property(GLOBAL PROPERTY ecrad_depends netcdf cdo)
13set(ecrad_build_args "" CACHE STRING "Custom Make arguments for ecRad")
15option(ecrad_custom_profile "Use a custom Make profile" OFF)
16set(ecrad_opt_flags "" CACHE STRING "Optimization flags for custom profile")
17set(ecrad_ld_flags "" CACHE STRING "Linker flags for custom profile")
18set(ecrad_basic_flags "" CACHE STRING "Basic flags for custom profile")
20set(test_cases small medium big)
21list(TRANSFORM test_cases PREPEND "<BINARY_DIR>/" OUTPUT_VARIABLE required_dirs)
25 message(STATUS "ecrad: enabled (system installed)")
26 find_program(ECRAD_EXE ecrad REQUIRED)
28 get_filename_component(ECRAD_EXE_DIR "${ECRAD_EXE}" DIRECTORY)
29 set_if_not_present(ENV{PATH} "$ENV{PATH}" "${ECRAD_EXE_DIR}")
31 # dummy ecrad external project to get tests
32 ExternalProject_Data_Add(
37 INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${required_dirs})
39 ExternalProject_Get_Property(ecrad BINARY_DIR)
40 set(ecrad_BIN_DIR ${BINARY_DIR})
43 message(STATUS "ecrad: enabled (internally built)")
45 set(omp_simd_unsupported False)
46 if(CMAKE_Fortran_COMPILER_ID MATCHES "^LLVMFlang$")
47 message(STATUS "Enabling custom profile for LLVM")
48 set(ecrad_custom_profile True)
49 set(ecrad_opt_flags "-O3 -march=native -ffp-contract=fast -ffast-math ${ecrad_opt_flags}")
51 # In LLVM versions <= 20, OpenMP is still experimental and !$omp simd reducions are not implemented
52 if(CMAKE_Fortran_COMPILER_VERSION VERSION_LESS 21)
53 set(omp_simd_unsupported True)
58 # Check compiler to set the PROFILE argument of make command
60 if(ecrad_custom_profile)
61 set(ECRAD_COMPILER_PROFILE "custom")
62 message(STATUS "Building a custom Make profile...")
63 find_package(OpenMP REQUIRED)
64 set(custom_profile_path "${CMAKE_CURRENT_BINARY_DIR}/Makefile_include.custom")
65 set(copy_cmd "cp ${custom_profile_path} <SOURCE_DIR>")
67 file(GENERATE OUTPUT ${custom_profile_path} CONTENT "
68FC = ${CMAKE_Fortran_COMPILER}
69CC = ${CMAKE_C_COMPILER}
70OPTFLAGS = ${ecrad_opt_flags}
71LDFLAGS = ${ecrad_ld_flags}
72BASICFLAGS = ${CMAKE_Fortran_MODDIR_FLAG}../mod ${ecrad_basic_flags}
73OMPFLAG = ${OpenMP_Fortran_FLAGS}"
75 elseif(CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
76 set(ECRAD_COMPILER_PROFILE "gfortran")
77 elseif(CMAKE_Fortran_COMPILER_ID MATCHES "^Intel(LLVM)?$")
78 set(ECRAD_COMPILER_PROFILE "intel")
82 "ecrad: compiler profile not supported (${CMAKE_Fortran_COMPILER_ID}). Provide a custom profile instead!"
87 ExternalProject_Data_Add(
89 DEPENDS netcdf::Fortran ${ecrad_revision}
91 # Remove some omp directive that's supposed to be supported by an undocumented compiler.
92 # see https://github.com/ecmwf-ifs/ecrad/pull/50
93 PATCH_COMMAND ${Patch_EXECUTABLE} -p1 -i ${CMAKE_SOURCE_DIR}/projects/ecrad_omp_simd_declare.patch
94 # Remove some omp simd reduction when they are not supported
95 COMMAND $<IF:$<NOT:$<BOOL:${omp_simd_unsupported}>>,true,${Patch_EXECUTABLE} -p1 -i ${CMAKE_SOURCE_DIR}/projects/ecrad_omp_simd_reduction.patch>
97 CONFIGURE_COMMAND bash -c ${copy_cmd}
99 PATH=$ENV{PATH} CPATH=$ENV{CPATH}
100 C_INCLUDE_PATH=$ENV{C_INCLUDE_PATH}
101 LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH} LIBRARY_PATH=$ENV{LIBRARY_PATH}
102 ${CMAKE_MAKE_PROGRAM} -j 1 PROFILE=${ECRAD_COMPILER_PROFILE} FC=${CMAKE_Fortran_COMPILER} ${default_build_args} ${ecrad_build_args}
103 INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${required_dirs}
104 COMMAND ${CMAKE_COMMAND} -E make_directory <INSTALL_DIR>
105 COMMAND ${CMAKE_COMMAND} -E copy_directory <BINARY_DIR>/bin
107 COMMAND ${CMAKE_COMMAND} -E copy_directory <BINARY_DIR>/lib
111 ExternalProject_Get_Property(ecrad INSTALL_DIR)
112 set(ecrad_DIR ${INSTALL_DIR})
114 set_if_not_present(ENV{PATH} "$ENV{PATH}" "${ecrad_DIR}/bin")
115 set_if_not_present(ENV{LD_LIBRARY_PATH} "$ENV{LD_LIBRARY_PATH}"
118 ExternalProject_Get_Property(ecrad BINARY_DIR)
119 set(ecrad_BIN_DIR ${BINARY_DIR})
120 set_if_not_present(ENV{PATH} "$ENV{PATH}" "${ecrad_BIN_DIR}/bin")
123 #The large tests require inputs that are NC4 files. ecRad requires setting a parameter in the radiation_driver namelist to
124 #enable reading and writing of this file format. Additionally, the tests are repeated 5 times by adding the other parameter.
125 #For comparability's sake, the small test is also executed with this adjusted namelist.
126 set(awk_add_params "awk '/do_write_double_precision/ { print; print \"do_write_hdf5 = true,\\nnrepeat = 5,\"; next }1'")
127 set(namelist_large_files configLargeFiles.nam)
128 set(namelist_creation "${awk_add_params} config.nam > ${namelist_large_files}")
129 set(append_new_namelist "&& ${namelist_creation}")
131 #Setting up the directories' contents
132 foreach(case IN LISTS test_cases)
134 NAME ecrad-${case}-stage-in
136 env LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH} LIBRARY_PATH=$ENV{LIBRARY_PATH}
137 PATH=$ENV{PATH} $<TARGET_FILE:job_launcher> --name=ecrad-${case}-stage-in
140 bash -c "${ecrad_BIN_DIR}/bin/create_practical.sh ${append_new_namelist}"
141 WORKING_DIRECTORY ${ecrad_BIN_DIR}/${case}
148 env LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH} LIBRARY_PATH=$ENV{LIBRARY_PATH}
149 PATH=$ENV{PATH} $<TARGET_FILE:job_launcher> --name=ecrad-small
152 ${namelist_large_files} era5slice.nc control.nc
153 WORKING_DIRECTORY ${ecrad_BIN_DIR}/small
156 #The large two tests require input data from outside of ecRad.
157 ExternalData_Add_Test(offline_ecrad_medium
160 env LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH} LIBRARY_PATH=$ENV{LIBRARY_PATH}
161 PATH=$ENV{PATH} $<TARGET_FILE:job_launcher> --name=ecrad-medium
164 ${namelist_large_files} DATA{inputs/ecrad/era5sliceConcat1000.nc} control.nc
165 WORKING_DIRECTORY ${ecrad_BIN_DIR}/medium
168 ExternalData_Add_Test(offline_ecrad_big
171 env LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH} LIBRARY_PATH=$ENV{LIBRARY_PATH}
172 PATH=$ENV{PATH} $<TARGET_FILE:job_launcher> --name=ecrad-big
175 ${namelist_large_files} DATA{inputs/ecrad/era5sliceConcat2000.nc} control.nc
176 WORKING_DIRECTORY ${ecrad_BIN_DIR}/big
179 ExternalData_Add_Target(offline_ecrad_medium)
180 ExternalData_Add_Target(offline_ecrad_big)
181 add_dependencies(offline offline_ecrad_medium offline_ecrad_big)
183 foreach(case IN LISTS test_cases)
184 ExternalData_Add_Test(offline_ecrad_${case}_validation
185 NAME ecrad-${case}-validation
187 env LD_LIBRARY_PATH=$ENV{LD_LIBRARY_PATH} LIBRARY_PATH=$ENV{LIBRARY_PATH}
188 PATH=$ENV{PATH} $<TARGET_FILE:job_launcher> --name=ecrad-${case}-validation
191 cdo diff,abslim=0.001 DATA{inputs/ecrad/ref-${case}.nc} control.nc
192 WORKING_DIRECTORY ${ecrad_BIN_DIR}/${case}
194 ExternalData_Add_Target(offline_ecrad_${case}_validation)
195 add_dependencies(offline offline_ecrad_${case}_validation)
197 set_tests_properties(ecrad-${case}-stage-in PROPERTIES FIXTURES_SETUP _setup-ecrad-${case})
198 set_tests_properties(ecrad-${case} PROPERTIES FIXTURES_SETUP _run-ecrad-${case})
200 set_tests_properties(ecrad-${case} PROPERTIES FIXTURES_REQUIRED _setup-ecrad-${case})
201 set_tests_properties(ecrad-${case}-validation PROPERTIES FIXTURES_REQUIRED _run-ecrad-${case})