HPCW 3.0
Loading...
Searching...
No Matches
ecrad.cmake
Go to the documentation of this file.
1# Copyright (c) 2020 - 2025 David Guibert
2# Copyright (c) 2024 - 2025 Niclas Schroeter
3# Copyright (c) 2024 - 2025 Antoine Morvan
4# All rights reserved.
5#
6# SPDX-License-Identifier: Apache-2.0
7
8include(ExternalData)
9
10set_property(GLOBAL PROPERTY ecrad_can_use_system TRUE)
11set_property(GLOBAL PROPERTY ecrad_depends netcdf cdo)
12
13set(ecrad_build_args "" CACHE STRING "Custom Make arguments for ecRad")
14
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")
19
20set(test_cases small medium big)
21list(TRANSFORM test_cases PREPEND "<BINARY_DIR>/" OUTPUT_VARIABLE required_dirs)
22
23if(ecrad_enabled)
24 if(USE_SYSTEM_ecrad)
25 message(STATUS "ecrad: enabled (system installed)")
26 find_program(ECRAD_EXE ecrad REQUIRED)
27
28 get_filename_component(ECRAD_EXE_DIR "${ECRAD_EXE}" DIRECTORY)
29 set_if_not_present(ENV{PATH} "$ENV{PATH}" "${ECRAD_EXE_DIR}")
30
31 # dummy ecrad external project to get tests
32 ExternalProject_Data_Add(
33 ecrad
34 ${ecrad_revision}
35 CONFIGURE_COMMAND ""
36 BUILD_COMMAND ""
37 INSTALL_COMMAND ${CMAKE_COMMAND} -E make_directory ${required_dirs})
38
39 ExternalProject_Get_Property(ecrad BINARY_DIR)
40 set(ecrad_BIN_DIR ${BINARY_DIR})
41
42 else()
43 message(STATUS "ecrad: enabled (internally built)")
44
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}")
50
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)
54 endif()
55 endif()
56
57
58 # Check compiler to set the PROFILE argument of make command
59 set(copy_cmd "true")
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>")
66
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}"
74 )
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")
79 else()
80 message(
81 FATAL_ERROR
82 "ecrad: compiler profile not supported (${CMAKE_Fortran_COMPILER_ID}). Provide a custom profile instead!"
83 )
84 endif()
85
86
87 ExternalProject_Data_Add(
88 ecrad
89 DEPENDS netcdf::Fortran ${ecrad_revision}
90
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>
96
97 CONFIGURE_COMMAND bash -c ${copy_cmd}
98 BUILD_COMMAND env
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
106 <INSTALL_DIR>/bin
107 COMMAND ${CMAKE_COMMAND} -E copy_directory <BINARY_DIR>/lib
108 <INSTALL_DIR>/lib
109 )
110
111 ExternalProject_Get_Property(ecrad INSTALL_DIR)
112 set(ecrad_DIR ${INSTALL_DIR})
113
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}"
116 "${ecrad_DIR}/lib")
117
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")
121 endif()
122
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}")
130
131 #Setting up the directories' contents
132 foreach(case IN LISTS test_cases)
133 add_test(
134 NAME ecrad-${case}-stage-in
135 COMMAND
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
138 --log-dir=${LOG_DIR}
139 --
140 bash -c "${ecrad_BIN_DIR}/bin/create_practical.sh ${append_new_namelist}"
141 WORKING_DIRECTORY ${ecrad_BIN_DIR}/${case}
142 )
143 endforeach()
144
145 add_test(
146 NAME ecrad-small
147 COMMAND
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
150 --log-dir=${LOG_DIR}
151 -- ecrad
152 ${namelist_large_files} era5slice.nc control.nc
153 WORKING_DIRECTORY ${ecrad_BIN_DIR}/small
154 )
155
156 #The large two tests require input data from outside of ecRad.
157 ExternalData_Add_Test(offline_ecrad_medium
158 NAME ecrad-medium
159 COMMAND
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
162 --log-dir=${LOG_DIR}
163 -- ecrad
164 ${namelist_large_files} DATA{inputs/ecrad/era5sliceConcat1000.nc} control.nc
165 WORKING_DIRECTORY ${ecrad_BIN_DIR}/medium
166 )
167
168 ExternalData_Add_Test(offline_ecrad_big
169 NAME ecrad-big
170 COMMAND
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
173 --log-dir=${LOG_DIR}
174 -- ecrad
175 ${namelist_large_files} DATA{inputs/ecrad/era5sliceConcat2000.nc} control.nc
176 WORKING_DIRECTORY ${ecrad_BIN_DIR}/big
177 )
178
179 ExternalData_Add_Target(offline_ecrad_medium)
180 ExternalData_Add_Target(offline_ecrad_big)
181 add_dependencies(offline offline_ecrad_medium offline_ecrad_big)
182
183 foreach(case IN LISTS test_cases)
184 ExternalData_Add_Test(offline_ecrad_${case}_validation
185 NAME ecrad-${case}-validation
186 COMMAND
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
189 --log-dir=${LOG_DIR}
190 --
191 cdo diff,abslim=0.001 DATA{inputs/ecrad/ref-${case}.nc} control.nc
192 WORKING_DIRECTORY ${ecrad_BIN_DIR}/${case}
193 )
194 ExternalData_Add_Target(offline_ecrad_${case}_validation)
195 add_dependencies(offline offline_ecrad_${case}_validation)
196
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})
199
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})
202 endforeach()
203
204endif(ecrad_enabled)