Skip to content

Commit

Permalink
Merge pull request #9 from ESCOMP/dev/unified_new_merge_pr4
Browse files Browse the repository at this point in the history
(Latest PR) Clean up diagnostic variables in WW3 for Langmuir turbulence parameterization
  • Loading branch information
alperaltuntas authored Jul 5, 2023
2 parents c4b1168 + 7af1188 commit a4fbf16
Show file tree
Hide file tree
Showing 14 changed files with 343 additions and 497 deletions.
322 changes: 100 additions & 222 deletions model/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,247 +1,125 @@
cmake_minimum_required(VERSION 3.12)
project(wav Fortran)

# Open switch file
file(STRINGS ${CMAKE_BINARY_DIR}/switch switch_strings)
separate_arguments(switches UNIX_COMMAND ${switch_strings})
message("Using CIME in ${CIMEROOT} with compiler ${COMPILER}")

# Put executables/libraries into a top-level bin/lib directory within the build directory
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# Include list of src files to make file more readable
# defines variables "ftn_src", "pdlib_src", "scrip_src", and "scripnc_src"
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/src_list.cmake)
# check_switches as a function for less verbosity in this CMakeLists.txt
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_switches.cmake)

check_switches("${switches}" switch_files)

add_library(ww3_lib STATIC ${ftn_src} ${switch_files})
# Create alias with same name as exported target
# so that WW3 can be usead with add_subdirectory
add_library(WW3::WW3 ALIAS ww3_lib)

# Re-name library on disk to just libww3 instead of libww3_lib
set_target_properties(ww3_lib PROPERTIES OUTPUT_NAME "ww3")
set_target_properties(ww3_lib PROPERTIES Fortran_MODULE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mod")

foreach(switch ${switches})
target_compile_definitions(ww3_lib PUBLIC W3_${switch})
endforeach()

if(ENDIAN STREQUAL "BIG")
set(endianness "big_endian")
elseif(ENDIAN STREQUAL "LITTLE")
set(endianness "little_endian")
elseif(ENDIAN STREQUAL "NATIVE")
set(endianness "native")
include(${CASEROOT}/Macros.cmake)
if (MPILIB STREQUAL mpi-serial)
set(CMAKE_Fortran_COMPILER ${SFC})
set(CMAKE_C_COMPILER ${SCC})
else()
message(FATAL_ERROR "Unknown option specified by ENDIAN: ${ENDIAN}")
set(CMAKE_Fortran_COMPILER ${MPIFC})
set(CMAKE_C_COMPILER ${MPICC})
endif()

add_compile_definitions(ENDIANNESS='${endianness}')

target_include_directories(ww3_lib
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/mod>
$<INSTALL_INTERFACE:mod>)

# Set compiler flags.
if(CMAKE_Fortran_COMPILER_ID MATCHES "^(Intel)$")
set(compile_flags -no-fma -ip -g -traceback -i4 -real-size 32 -fp-model precise
-assume byterecl -fno-alias -fno-fnalias)
# -sox only works on Linux
if(LINUX)
list(APPEND compile_flags -sox)
endif()
set(compile_flags_release -O3)
# SHELL: prefix fixes CMake attempting to de-duplicate the repeated uses of 'all' in -warn, -debug, -check
# See https://cmake.org/cmake/help/latest/command/target_compile_options.html#option-de-duplication
set(compile_flags_debug -O0 "SHELL:-debug all" "SHELL:-warn all" "SHELL:-check all" -check noarg_temp_created -fp-stack-check -heap-arrays -traceback -fpe0)

if(APPLE)
# The linker on macOS does not include `common symbols` (usually module variables without a default value) by default
# Passing the -c flag includes them and fixes an error with undefined symbols
# Only ifort marks these symbols as common, compared to GCC
set(CMAKE_Fortran_ARCHIVE_FINISH "<CMAKE_RANLIB> -c <TARGET>")
set(CMAKE_C_ARCHIVE_FINISH "<CMAKE_RANLIB> -c <TARGET>")
endif()

elseif(CMAKE_Fortran_COMPILER_ID MATCHES "^(GNU)$")
set(compile_flags -g -fno-second-underscore -ffree-line-length-none)
set(compile_flags_release -O3)
set(compile_flags_debug -Wall -fcheck=all -ffpe-trap=invalid,zero,overflow -frecursive -fbacktrace)

if(${CMAKE_Fortran_COMPILER_VERSION} VERSION_GREATER_EQUAL 10)
target_compile_options(ww3_lib PUBLIC -fallow-argument-mismatch)
endif()

elseif(CMAKE_Fortran_COMPILER_ID MATCHES "PGI")
set(compile_flags -g -i4 -r4 -Kieee)
set(compile_flags_release -O3)
set(compile_flags_debug -O0 -Mbounds -Mchkfpstk -Mchkstk -Mdalign -Mdclchk -Mdepchk -Miomutex -Ktrap=fp -Mrecursive -traceback)

if(${CMAKE_Fortran_COMPILER_VERSION} VERSION_GREATER_EQUAL 10)
target_compile_options(ww3_lib PUBLIC -fallow-argument-mismatch -fallow-invalid-boz)
endif()

elseif(CMAKE_Fortran_COMPILER_ID MATCHES "Cray")
# TODO: Where do we set -homp for OpenMP compiles?
set(compile_flags -g -sdefault32 -eg)
set(compile_flags_release -O3)
set(compile_flags_debug -O0 -Rbcps -Ktrap=fp)
endif()

target_compile_options(ww3_lib PUBLIC "$<$<COMPILE_LANGUAGE:Fortran>:${compile_flags}>")
target_compile_options(ww3_lib PUBLIC "$<$<AND:$<CONFIG:Debug>,$<COMPILE_LANGUAGE:Fortran>>:${compile_flags_debug}>")
target_compile_options(ww3_lib PUBLIC "$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:Fortran>>:${compile_flags_release}>")

# Executables to always build
set(programs ww3_strt ww3_grid ww3_bound ww3_outf ww3_outp ww3_trck ww3_grib
ww3_gint gx_outf gx_outp ww3_uprstr ww3_shel ww3_prep ww3_gspl ww3_multi ww3_systrk)

# Executables to build if NetCDF is found
set(netcdf_programs ww3_ounf ww3_ounp ww3_bounc ww3_trnc ww3_prnc)

if("OASIS" IN_LIST switches)
find_package(OASIS REQUIRED)
target_link_libraries(ww3_lib PUBLIC OASIS::OASIS)
endif()

if(NETCDF)
if("netcdf" IN_LIST EXCLUDE_FIND)
# NetCDF library flags provided by compiler or wrapper script: don't search
set(NetCDF_Fortran_FOUND TRUE)
message(WARNING "Not searching for NetCDF library - please ensure correct flags are provided by your compiler/wrapper")
else()
find_package(NetCDF REQUIRED COMPONENTS Fortran)
endif()
endif()

if(NetCDF_Fortran_FOUND)
target_sources(ww3_lib PRIVATE w3ounfmetamd.F90)
if(TARGET NetCDF::NetCDF_Fortran)
# NetCDF library flags provided by compiler or wrapper script: don't add as dependency
target_link_libraries(ww3_lib PUBLIC NetCDF::NetCDF_Fortran)
endif()
list(APPEND programs ${netcdf_programs})
set(CMAKE_Fortran_FLAGS "${FFLAGS} ${CPPDEFS} -I${LIBROOT}/include -I${LIBROOT}/finclude -I${LIBROOT}/nuopc/esmf/${NINST_VALUE}/include")

#-------------------------
# Set ESMF_F90COMPILEPATHS
#-------------------------
# convert esmf.mk makefile variables to cmake variables until ESMF
# provides proper cmake package
if (DEFINED ENV{ESMFMKFILE})
message("ESMFMKFILE: $ENV{ESMFMKFILE}")
else()
message(FATAL_ERROR "ESMFMKFILE env variable is not defined")
endif()

if(UFS_CAP)
# Don't search for ESMF if target already exists (when build WW3 as UFS submodule)
if (NOT TARGET esmf)
find_package(ESMF MODULE REQUIRED)
set(ESMFMKFILE $ENV{ESMFMKFILE})
file(STRINGS ${ESMFMKFILE} esmf_mk_text)
foreach(line ${esmf_mk_text})
string(REGEX REPLACE "^[ ]+" "" line ${line}) # strip leading spaces
if (line MATCHES "^ESMF_*") # process only line starting with ESMF_
string(REGEX MATCH "^ESMF_[^=]+" esmf_name ${line})
string(REPLACE "${esmf_name}=" "" emsf_value ${line})
set(${esmf_name} "${emsf_value}")
endif()

if(UFS_CAP STREQUAL "MULTI_ESMF")
set(cap_src ${esmf_multi_cap_src})
elseif(UFS_CAP STREQUAL "NUOPC_MESH")
set(cap_src ${nuopc_mesh_cap_src})
endif()

target_sources(ww3_lib PRIVATE ${cap_src})
target_link_libraries(ww3_lib PUBLIC esmf)
# Don't build executables when building WW3 ESMF library
set(programs "")
endforeach()
string(REPLACE "-I" "" ESMF_F90COMPILEPATHS ${ESMF_F90COMPILEPATHS})
string(REPLACE " " ";" ESMF_F90COMPILEPATHS ${ESMF_F90COMPILEPATHS})
message("ESMF_F90COMPILEPATHS: ${ESMF_F90COMPILEPATHS}")

#-------------------------
# Determine switches
#-------------------------
list(APPEND switches "CESMCOUPLED" "NCO" "DIST" "MPI" "PR3" "UQ" "FLX0" "SEED" "ST4" "STAB0" "NL1" "BT1" "DB1" "MLIM" "FLD2" "TR0" "BS0" "RWND" "WNX1" "WNT1" "CRX1" "CRT1" "O0" "O1" "O2" "O3" "O4" "O5" "O6" "O7" "O14" "O15" "IS0" "REF0" "NOGRB")

# TODO: need to enamble IC4 with the unstructured implemention
if (DEFINED USE_UNSTRUCT)
list(APPEND switches "IC0" "PDLIB" "METIS")
else()
### list(APPEND switches "IC4" "OMPG" "OMPH")
list(APPEND switches "IC0")
endif()

set_property(SOURCE w3initmd.F90
APPEND
PROPERTY COMPILE_DEFINITIONS
"__WW3_SWITCHES__=\'${switch_strings}\'"
)

if("OMPG" IN_LIST switches)
find_package(OpenMP REQUIRED COMPONENTS Fortran)
target_link_libraries(ww3_lib PUBLIC OpenMP::OpenMP_Fortran)
endif()
#-------------------------
# Include list of src files to make file more readable
# defines variables "ftn_src", "nuopc_mesh_cap_src", "pdlib_src", "scrip_src", and "scripnc_src"
#-------------------------
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/src_list.cmake)

if("MPI" IN_LIST switches)
find_package(MPI REQUIRED COMPONENTS Fortran)
target_link_libraries(ww3_lib PUBLIC MPI::MPI_Fortran)
endif()
list(APPEND ftn_src ${nuopc_mesh_cap_src})

# Handle PDLIB, SCRIP, SCRIPNC build files directly instead of through configuration file
if("PDLIB" IN_LIST switches)
list(APPEND ftn_src ${pdlib_src})
if("SCOTCH" IN_LIST switches)
find_package(SCOTCH REQUIRED)
target_sources(ww3_lib PRIVATE ${pdlib_src})
target_link_libraries(ww3_lib PUBLIC PTSCOTCHparmetis::PTSCOTCHparmetis)
elseif("METIS" IN_LIST switches)
find_package(ParMETIS REQUIRED)
target_sources(ww3_lib PRIVATE ${pdlib_src})
target_link_libraries(ww3_lib PUBLIC ParMETIS::ParMETIS)
#find_package(SCOTCH REQUIRED)
#target_link_libraries(ww3_lib PUBLIC PTSCOTCHparmetis::PTSCOTCHparmetis)
elseif("METIS" IN_LIST switches)
#find_package(ParMETIS REQUIRED)
#target_link_libraries(ww3_lib PUBLIC ParMETIS::ParMETIS)
else()
message(FATAL_ERROR "PDLIB requires METIS or SCOTCH library for domain decomposition")
endif()
endif()

if("SCRIP" IN_LIST switches)
target_sources(ww3_lib PRIVATE ${scrip_src})
endif()


if("SCRIPNC" IN_LIST switches OR "OASIS" IN_LIST switches OR "TRKNC" IN_LIST switches)
if(NOT NetCDF_Fortran_FOUND)
message(FATAL_ERROR "Cannot build SCRIPNC, OASIS, or TRKNC without NetCDF")
message(FATAL_ERROR "PDLIB requires METIS or SCOTCH library for domain decomposition")
endif()
endif()

if("SCRIPNC" IN_LIST switches)
target_sources(ww3_lib PRIVATE ${scrip_src} ${scripnc_src})
endif()

if("NCEP2" IN_LIST switches)
find_package(g2 REQUIRED)
find_package(bacio REQUIRED)
find_package(w3emc REQUIRED)
target_link_libraries(ww3_lib PUBLIC g2::g2_4 bacio::bacio_4 w3emc::w3emc_4)
endif()

if("TIDE" IN_LIST switches)
list(APPEND programs ww3_prtide)
endif()
#-------------------------
# Determine switch specific files
# Include check_switches as a function for less verbosity in this CMakeLists.txt
#-------------------------
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/check_switches.cmake)
check_switches("${switches}" switch_files)

# Executables are not needed when building ww3_multi_esmf library
foreach(program ${programs})
add_executable(${program} ${program}.F90)
target_link_libraries(${program} PRIVATE ww3_lib)
message(STATUS "----status of source files-----")
message(STATUS "list of always source files is : ${ftn_src}")
message(STATUS "list of switch files is : ${switch_files}")

#-------------------------
# Now check in SourceMods to see if the file should be used instead
#-------------------------
list(APPEND srcfiles ${ftn_src} ${switch_files})
foreach(file ${srcfiles} )
if(EXISTS "${CASEROOT}/SourceMods/src.ww3dev/${file}")
message("Using ${file} from ${CASEROOT}/SourceMods/src.ww3dev")
list(REMOVE_ITEM srcfiles ${file})
list(APPEND srcfiles "${CASEROOT}/SourceMods/src.ww3dev/${file}")
message(STATUS "Using ${file} from ${CASEROOT}/SourceMods/src.ww3dev")
endif()
endforeach()

install(
TARGETS ${programs} ww3_lib
EXPORT WW3Exports
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)

install(FILES ${CMAKE_BINARY_DIR}/switch DESTINATION ${CMAKE_INSTALL_PREFIX})
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod DESTINATION ${CMAKE_INSTALL_PREFIX})

#-------------------------
# Determine target library wav
#-------------------------
add_library(wav ${srcfiles})
target_include_directories (wav PRIVATE ${ESMF_F90COMPILEPATHS})

export(EXPORT WW3Exports
NAMESPACE WW3::
FILE WW3-targets.cmake
#-------------------------
# Determine compile definitions for wav
#-------------------------
foreach(switch ${switches})
target_compile_definitions(wav PUBLIC W3_${switch})
endforeach()
add_compile_definitions(ENDIANNESS="big_endian")
set_property(SOURCE w3initmd.F90
APPEND
PROPERTY COMPILE_DEFINITIONS
"__WW3_SWITCHES__=\'\'"
)

### Package config
include(CMakePackageConfigHelpers)
set(CONFIG_INSTALL_DESTINATION lib/cmake/WW3)
message("CMAKE_CURRENT_BINARY_DIR is ${CMAKE_CURRENT_BINARY_DIR}")
message("PROJECT_BINARY_DIR is ${PROJECT_BINARY_DIR}")

configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/WW3-package-config.cmake.in
${CMAKE_BINARY_DIR}/WW3-config.cmake
INSTALL_DESTINATION ${CONFIG_INSTALL_DESTINATION})

install(FILES ${CMAKE_BINARY_DIR}/WW3-config.cmake
DESTINATION ${CONFIG_INSTALL_DESTINATION})

write_basic_package_version_file(${CMAKE_BINARY_DIR}/WW3-config-version.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion)

install(FILES ${CMAKE_BINARY_DIR}/WW3-config-version.cmake
DESTINATION ${CONFIG_INSTALL_DESTINATION})
# Executables to always build
add_executable(ww3_grid ww3_grid.F90)
target_link_libraries(ww3_grid PRIVATE wav)

install(EXPORT WW3Exports
NAMESPACE WW3::
FILE WW3-targets.cmake
DESTINATION ${CONFIG_INSTALL_DESTINATION})
install(TARGETS wav)
Loading

0 comments on commit a4fbf16

Please sign in to comment.