From 006920514da9c3e65827179beafff29a77fbcf6d Mon Sep 17 00:00:00 2001 From: Micael Oliveira Date: Thu, 12 Oct 2023 10:47:29 +1100 Subject: [PATCH] Properly take into account the effect of the WW3 switches in the list of source files. Update the list of swiches. --- WW3/CMakeLists.txt | 63 +++++++------------- WW3/cmake/check_switches.cmake | 105 +++++++++++++++++++++++++++++++++ WW3/ww3_files.cmake | 36 +++++++---- 3 files changed, 148 insertions(+), 56 deletions(-) create mode 100644 WW3/cmake/check_switches.cmake diff --git a/WW3/CMakeLists.txt b/WW3/CMakeLists.txt index f1fb9f8..30d3707 100644 --- a/WW3/CMakeLists.txt +++ b/WW3/CMakeLists.txt @@ -1,40 +1,17 @@ -# Switch definitions (taken from CESM) -add_compile_definitions(W3_CESMCOUPLED) -add_compile_definitions(W3_NCO) -add_compile_definitions(W3_DIST) -add_compile_definitions(W3_MPI) -add_compile_definitions(W3_PR3) -add_compile_definitions(W3_UQ) -add_compile_definitions(W3_FLX0) -add_compile_definitions(W3_SEED) -add_compile_definitions(W3_ST4) -add_compile_definitions(W3_STAB0) -add_compile_definitions(W3_NL1) -add_compile_definitions(W3_BT1) -add_compile_definitions(W3_DB1) -add_compile_definitions(W3_MLIM) -add_compile_definitions(W3_FLD2) -add_compile_definitions(W3_TR0) -add_compile_definitions(W3_BS0) -add_compile_definitions(W3_RWND) -add_compile_definitions(W3_WNX1) -add_compile_definitions(W3_WNT1) -add_compile_definitions(W3_CRX1) -add_compile_definitions(W3_CRT1) -add_compile_definitions(W3_O0) -add_compile_definitions(W3_O1) -add_compile_definitions(W3_O2) -add_compile_definitions(W3_O3) -add_compile_definitions(W3_O4) -add_compile_definitions(W3_O5) -add_compile_definitions(W3_O6) -add_compile_definitions(W3_O7) -add_compile_definitions(W3_O14) -add_compile_definitions(W3_O15) -add_compile_definitions(W3_IS0) -add_compile_definitions(W3_REF0) -add_compile_definitions(W3_NOGRB) -add_compile_definitions(W3_IC0) +# Commom source files. Too many files to list, so include them via this file +include("ww3_files.cmake") + +# List of switches +list(APPEND switches "CESMCOUPLED" "NCO" "DIST" "MPI" "PR3" "UQ" "FLX4" "SEED" "ST6" "STAB0" "NL1" "BT1" "DB1" "MLIM" "TR0" "BS0" "RWND" "WNX1" "WNT1" "CRX1" "CRT1" "O0" "O1" "O2" "O3" "O4" "O5" "O6" "O7" "O14" "O15" "IS0" "REF0" "NOGRB" "IC0") + +# Process switches and get list of extra source files +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_switches.cmake) +check_switches("${switches}" switch_files) + +# Compile definitions +foreach(switch ${switches}) + add_compile_definitions(W3_${switch}) +endforeach() add_compile_definitions(ENDIANNESS="big_endian") @@ -42,18 +19,18 @@ set_property(SOURCE WW3/model/src/w3initmd.F90 APPEND PROPERTY COMPILE_DEFINITIONS "__WW3_SWITCHES__=\'\'" - ) +) -# Too many files to list, so include them via this file -include("ww3_files.cmake") +message(VERBOSE "WW3 common source files : ${ww3_src_files}") +message(VERBOSE "WW# switch files: ${switch_files}") ### Create target library and set PUBLIC interfaces on the library -add_fortran_library(ww3 mod STATIC ${ww3_src_files}) +add_fortran_library(ww3 mod STATIC ${ww3_src_files} ${switch_files}) target_link_libraries(ww3 PUBLIC esmf NetCDF::NetCDF_Fortran) # WW3 executables foreach(EXE ww3_grid ww3_strt ww3_ounf ww3_outf ww3_outp) - add_executable(${EXE} WW3/model/src/${EXE}.F90) - target_link_libraries(${EXE} PRIVATE ww3) + add_executable(${EXE} ${${EXE}_src_files}) + target_link_libraries(${EXE} PRIVATE ww3) endforeach() diff --git a/WW3/cmake/check_switches.cmake b/WW3/cmake/check_switches.cmake new file mode 100644 index 0000000..b88c085 --- /dev/null +++ b/WW3/cmake/check_switches.cmake @@ -0,0 +1,105 @@ +function(check_switches switches switch_files) + # Read JSON file + file(READ ${CMAKE_CURRENT_SOURCE_DIR}/WW3/model/src/cmake/switches.json json_str) + # Get length of top-level array of all switch categories + string(JSON len LENGTH ${json_str}) + # CMake's foreach RANGE is inclusive, so subtract 1 when looping + math(EXPR len "${len} - 1") + + # Loop over switch categories + set(files "") + foreach(i_category RANGE ${len}) + string(JSON category GET ${json_str} ${i_category}) + string(JSON num_options LENGTH ${category} valid-options) + + # Loop over valid options + math(EXPR num_options "${num_options} - 1") + set(n_switches_in_category 0) + foreach(j_options RANGE ${num_options}) + string(JSON valid_opt GET ${category} valid-options ${j_options} name) + + # This option is in current switch file + if(valid_opt IN_LIST switches) + math(EXPR n_switches_in_category "${n_switches_in_category} + 1") + string(JSON n_files ERROR_VARIABLE err LENGTH ${category} valid-options ${j_options} build_files) + + # Check for conflicting switches + string(JSON n_conflicts ERROR_VARIABLE err LENGTH ${category} valid-options ${j_options} conflicts) + if(n_conflicts) + math(EXPR n_conflicts "${n_conflicts} -1") + # Loop over conflcits + foreach(i_conflict RANGE ${n_conflicts}) + string(JSON conflict GET ${category} valid-options ${j_options} conflicts ${i_conflict}) + if(conflict IN_LIST switches) + message(FATAL_ERROR "Switch '${valid_opt}' and '${conflict}' conflict") + endif() + endforeach() + endif() + + # Check for required dependent switches + string(JSON n_requires ERROR_VARIABLE err LENGTH ${category} valid-options ${j_options} requires) + if(n_requires) + math(EXPR n_requires "${n_requires} - 1") + # Loop over required switches + foreach(i_requires RANGE ${n_requires}) + + string(JSON json_type TYPE ${category} valid-options ${j_options} requires ${i_requires}) + + # Can be a string or an array. String values or directly required, while if an array one of the values is required. + if(json_type STREQUAL "STRING") + string(JSON required_switch GET ${category} valid-options ${j_options} requires ${i_requires}) + if(NOT required_switch IN_LIST switches) + message(FATAL_ERROR "Switch '${valid_opt}' requires '${required_switch}' to be set") + endif() + elseif(json_type STREQUAL "ARRAY") + string(JSON n_requires_any LENGTH ${vategory} valid-options ${j_options} requries ${i_requires}) + math(EXPR n_requires_any "${n_requires_any} - 1") + + # Loop over array and check that one of the switches is present + set(found false) + set(possible_values "") + foreach(i_requires_any RANGE ${n_requires_any}) + string(JSON required_switch GET ${category} valid-options ${j_options} requires ${i_requires} ${i_requires_any}) + list(APPEND possible_values "${required_switch}") + + if(required_switch IN_LIST switches) + set(found true) + endif() + endforeach() + + if(NOT found) + message(FATAL_ERROR "Switch ${valid_opt} requires one of ${possible_values} to be set") + endif() + + endif() + endforeach() + endif() + + if(n_files) + # Loop over files associated with switch and add them to build + math(EXPR n_files "${n_files} - 1") + foreach(i_files RANGE ${n_files}) + string(JSON file GET ${category} valid-options ${j_options} build_files ${i_files}) + list(APPEND files "WW3/model/src/${file}") + endforeach() + endif() + endif() + + endforeach() + + # Check for the correct number of switches per category + string(JSON num_switches GET ${category} num_switches) + string(JSON category_name GET ${category} name) + + if(num_switches STREQUAL "one" AND NOT n_switches_in_category EQUAL 1) + message(FATAL_ERROR "No valid ${category_name} switches found, but one is required") + elseif(num_switches STREQUAL "upto1" AND n_switches_in_category GREATER 1) + message(FATAL_ERROR "Too many ${category_name} switches found (max 1)") + elseif(num_switches STREQUAL "upto2" AND n_switches_in_category GREATER 2) + message(FATAL_ERROR "Too many ${category_name} switches found (max 2)") + endif() + + endforeach() + + set(${switch_files} ${files} PARENT_SCOPE) +endfunction() diff --git a/WW3/ww3_files.cmake b/WW3/ww3_files.cmake index 34b5dcc..37d77b3 100644 --- a/WW3/ww3_files.cmake +++ b/WW3/ww3_files.cmake @@ -1,5 +1,5 @@ +# Common sources list(APPEND ww3_src_files - # Common sources WW3/model/src/constants.F90 WW3/model/src/w3adatmd.F90 WW3/model/src/w3arrymd.F90 @@ -32,7 +32,6 @@ list(APPEND ww3_src_files WW3/model/src/w3nmltrncmd.F90 WW3/model/src/w3nmluprstrmd.F90 WW3/model/src/w3odatmd.F90 - WW3/model/src/w3ounfmetamd.F90 WW3/model/src/w3parall.F90 WW3/model/src/w3partmd.F90 WW3/model/src/w3servmd.F90 @@ -58,17 +57,6 @@ list(APPEND ww3_src_files WW3/model/src/w3iogoncdmd.F90 WW3/model/src/wav_shr_flags.F90 - # Sources needed for switches - WW3/model/src/w3profsmd.F90 - WW3/model/src/w3pro3md.F90 - WW3/model/src/w3uqckmd.F90 - WW3/model/src/w3fld1md.F90 - WW3/model/src/w3fld2md.F90 - WW3/model/src/w3src4md.F90 - WW3/model/src/w3snl1md.F90 - WW3/model/src/w3sbt1md.F90 - WW3/model/src/w3sdb1md.F90 - # NUOPC cap sources WW3/model/src/wav_kind_mod.F90 WW3/model/src/wav_shr_mod.F90 @@ -76,3 +64,25 @@ list(APPEND ww3_src_files WW3/model/src/wav_comp_nuopc.F90 WW3/model/src/wav_import_export.F90 ) + +# Utilities sources +list(APPEND ww3_grid_src_files + WW3/model/src/ww3_grid.F90 +) + +list(APPEND ww3_strt_src_files + WW3/model/src/ww3_strt.F90 +) + +list(APPEND ww3_outf_src_files + WW3/model/src/ww3_outf.F90 +) + +list(APPEND ww3_ounf_src_files + WW3/model/src/ww3_ounf.F90 + WW3/model/src/w3ounfmetamd.F90 +) + +list(APPEND ww3_outp_src_files + WW3/model/src/ww3_outp.F90 +)