diff --git a/.github/workflows/gnu.yml b/.github/workflows/gnu.yml new file mode 100644 index 000000000..591b409c8 --- /dev/null +++ b/.github/workflows/gnu.yml @@ -0,0 +1,103 @@ +name: GNU Linux Build +on: [push, pull_request] + +env: + cache_key: gnu3 + CC: gcc-10 + FC: gfortran-10 + CXX: g++-10 + +# Split into a steup step, and a WW3 build step which +# builds multiple switches in a matrix. The setup is run once and +# the environment is cached so each build of WW3 can share the dependencies. + +jobs: + setup: + runs-on: ubuntu-20.04 + + steps: + # Cache spack, OASIS, and compiler + # No way to flush Action cache, so key may have # appended + - name: cache-env + id: cache-env + uses: actions/cache@v2 + with: + path: | + spack + ~/.spack + work_oasis3-mct + key: spack-${{ runner.os }}-${{ env.cache_key }} + + - name: checkout-ww3 + if: steps.cache-env.outputs.cache-hit != 'true' + uses: actions/checkout@v2 + with: + path: ww3 + + # Build WW3 spack environment + - name: install-dependencies-with-spack + if: steps.cache-env.outputs.cache-hit != 'true' + run: | + # Install NetCDF, ESMF, g2, etc using Spack + git clone -c feature.manyFiles=true https://github.com/spack/spack.git + source spack/share/spack/setup-env.sh + spack env create ww3-gnu ww3/model/ci/spack.yaml + spack env activate ww3-gnu + spack compiler find + spack external find m4 cmake pkgconf openssl + spack add mpich@3.4.2 + spack concretize + spack install --dirty -v + + - name: build-oasis + if: steps.cache-env.outputs.cache-hit != 'true' + run: | + source spack/share/spack/setup-env.sh + spack env activate ww3-gnu + export WWATCH3_DIR=${GITHUB_WORKSPACE}/ww3/model + cd ww3/regtests/ww3_tp2.14/input/oasis3-mct/util/make_dir + mkdir build && cd build + cmake .. + make VERBOSE=1 + cp -r ${GITHUB_WORKSPACE}/ww3/regtests/ww3_tp2.14/work_oasis3-mct ${GITHUB_WORKSPACE} + + build: + needs: setup + strategy: + matrix: + switch: [Ifremer1, NCEP_st2, NCEP_st4, ite_pdlib, NCEP_st4sbs, NCEP_glwu, OASACM, UKMO, MULTI_ESMF] + runs-on: ubuntu-20.04 + + steps: + - name: checkout-ww3 + uses: actions/checkout@v2 + with: + path: ww3 + + - name: cache-env + id: cache-env + uses: actions/cache@v2 + with: + path: | + spack + ~/.spack + work_oasis3-mct + key: spack-${{ runner.os }}-${{ env.cache_key }} + + - name: build-ww3 + run: | + source spack/share/spack/setup-env.sh + spack env activate ww3-gnu + cd ww3 + export CC=mpicc + export FC=mpif90 + export OASISDIR=${GITHUB_WORKSPACE}/work_oasis3-mct + mkdir build && cd build + if [[ ${{ matrix.switch }} == "MULTI_ESMF" ]]; then + cmake .. -DMULTI_ESMF=ON -DSWITCH=multi_esmf + else + cmake .. -DSWITCH=${{ matrix.switch }} + fi + make -j2 VERBOSE=1 + + diff --git a/.github/workflows/intel.yml b/.github/workflows/intel.yml new file mode 100644 index 000000000..3ff6f896e --- /dev/null +++ b/.github/workflows/intel.yml @@ -0,0 +1,128 @@ +name: Intel Linux Build +on: [push, pull_request] + +# Use custom shell with -l so .bash_profile is sourced which loads intel/oneapi/setvars.sh +# without having to do it in manually every step +defaults: + run: + shell: bash -leo pipefail {0} + +# Set I_MPI_CC/F90 so Intel MPI wrapper uses icc/ifort instead of gcc/gfortran +env: + cache_key: intel4 + CC: icc + FC: ifort + CXX: icpc + I_MPI_CC: icc + I_MPI_F90: ifort + +# Split into a dependency build step, and a WW3 build step which +# builds multiple switches in a matrix. The setup is run once and +# the environment is cached so each build of WW3 can share the dependencies. + +jobs: + setup: + runs-on: ubuntu-latest + + steps: + # Cache spack, OASIS, and compiler + # No way to flush Action cache, so key may have # appended + - name: cache-env + id: cache-env + uses: actions/cache@v2 + with: + path: | + spack + ~/.spack + work_oasis3-mct + /opt/intel + key: spack-${{ runner.os }}-${{ env.cache_key }} + + - name: install-intel-compilers + if: steps.cache-env.outputs.cache-hit != 'true' + run: | + wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB + sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB + echo "deb https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list + sudo apt-get update + sudo apt-get install intel-oneapi-dev-utilities intel-oneapi-mpi-devel intel-oneapi-openmp intel-oneapi-compiler-fortran intel-oneapi-compiler-dpcpp-cpp-and-cpp-classic + echo "source /opt/intel/oneapi/setvars.sh" >> ~/.bash_profile + + - name: checkout-ww3 + if: steps.cache-env.outputs.cache-hit != 'true' + uses: actions/checkout@v2 + with: + path: ww3 + + # Build WW3 spack environment + - name: install-dependencies-with-spack + if: steps.cache-env.outputs.cache-hit != 'true' + run: | + # Install NetCDF, ESMF, g2, etc using Spack + git clone -c feature.manyFiles=true https://github.com/spack/spack.git + source spack/share/spack/setup-env.sh + spack env create ww3-intel ww3/model/ci/spack.yaml + spack env activate ww3-intel + spack compiler find + spack external find m4 cmake pkgconf openssl + spack add intel-oneapi-mpi + spack concretize + spack install --dirty -v + + - name: build-oasis + if: steps.cache-env.outputs.cache-hit != 'true' + run: | + source spack/share/spack/setup-env.sh + spack env activate ww3-intel + export WWATCH3_DIR=${GITHUB_WORKSPACE}/ww3/model + cd ww3/regtests/ww3_tp2.14/input/oasis3-mct/util/make_dir + mkdir build && cd build + cmake .. + make + cp -r ${GITHUB_WORKSPACE}/ww3/regtests/ww3_tp2.14/work_oasis3-mct ${GITHUB_WORKSPACE} + + build: + needs: setup + strategy: + matrix: + switch: [Ifremer1, NCEP_st2, NCEP_st4, ite_pdlib, NCEP_st4sbs, NCEP_glwu, OASACM, UKMO, MULTI_ESMF] + runs-on: ubuntu-latest + + steps: + - name: checkout-ww3 + uses: actions/checkout@v2 + with: + path: ww3 + + - name: install-intel + run: | + echo "source /opt/intel/oneapi/setvars.sh" >> ~/.bash_profile + + - name: cache-env + id: cache-env + uses: actions/cache@v2 + with: + path: | + spack + ~/.spack + work_oasis3-mct + /opt/intel + key: spack-${{ runner.os }}-${{ env.cache_key }} + + - name: build-ww3 + run: | + source spack/share/spack/setup-env.sh + spack env activate ww3-intel + cd ww3 + export CC=mpicc + export FC=mpif90 + export OASISDIR=${GITHUB_WORKSPACE}/work_oasis3-mct + mkdir build && cd build + if [[ ${{ matrix.switch }} == "MULTI_ESMF" ]]; then + cmake .. -DMULTI_ESMF=ON -DSWITCH=multi_esmf + else + cmake .. -DSWITCH=${{ matrix.switch }} + fi + make -j2 + + diff --git a/.gitignore b/.gitignore index aa41f14b2..bf1f66796 100644 --- a/.gitignore +++ b/.gitignore @@ -169,3 +169,5 @@ model/bin/wwatch3.env */.*.swp */*/.*.swp */*/*/.*.swp +.DS_Store +build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..8daccdd8c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,46 @@ +# CMake build written by Kyle Gerheiser + +# Requires CMake 3.19 for JSON strings +cmake_minimum_required(VERSION 3.19) + +# Get VERSION from VERSION file +file(STRINGS "VERSION" pVersion) + +project( + WW3 + VERSION ${pVersion} + LANGUAGES C Fortran) + +set(MULTI_ESMF OFF CACHE BOOL "Build ww3_multi_esmf library") +set(NETCDF ON CACHE BOOL "Build NetCDF programs (requires NetCDF)") + +# Make Find modules visible to CMake +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +# Set switch file on command line when running CMake +set(SWITCH "" CACHE STRING "Switch file, either full path, relative path from location of top-level WW3/ dir, or a switch in model/bin") + +# Search for switch file as a full path or in model/bin +if(EXISTS ${SWITCH}) + set(switch_file ${SWITCH}) +else() + set(switch_file ${CMAKE_CURRENT_SOURCE_DIR}/model/bin/switch_${SWITCH}) + if(NOT EXISTS ${switch_file}) + message(FATAL_ERROR "Switch file '${switch_file}' does not exist, set switch with -DSWITCH=") + endif() +endif() + +message(STATUS "Build with switch: ${switch_file}") +# Copy switch file to build dir +configure_file(${switch_file} ${CMAKE_BINARY_DIR}/switch COPYONLY) + +# Re-configure CMake when switch changes +set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CMAKE_BINARY_DIR}/switch) + +if(NOT CMAKE_BUILD_TYPE MATCHES "^(Debug|Release|RelWithDebInfo|MinSizeRel)$") + message(STATUS "Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +add_subdirectory(model) diff --git a/VERSION b/VERSION new file mode 100644 index 000000000..9ad4d4f29 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +7.14 diff --git a/model/esmf/cmake/FindESMF.cmake b/cmake/FindESMF.cmake similarity index 56% rename from model/esmf/cmake/FindESMF.cmake rename to cmake/FindESMF.cmake index 82b648e08..5ba7003bd 100644 --- a/model/esmf/cmake/FindESMF.cmake +++ b/cmake/FindESMF.cmake @@ -11,25 +11,24 @@ # Add the ESMFMKFILE path to the cache if defined as system env variable -if (DEFINED ENV{ESMFMKFILE} AND NOT DEFINED ESMFMKFILE) +if(DEFINED ENV{ESMFMKFILE} AND NOT DEFINED ESMFMKFILE) set(ESMFMKFILE $ENV{ESMFMKFILE} CACHE FILEPATH "Path to ESMF mk file") -endif () +endif() -# Found the mk file and ESMF exists on the system -if (EXISTS ${ESMFMKFILE}) - set(ESMF_FOUND TRUE CACHE BOOL "ESMF mk file found" FORCE) - # Did not find the ESMF mk file -else() - set(ESMF_FOUND FALSE CACHE BOOL "ESMF mk file NOT found" FORCE) - # Best to warn users that without the mk file there is no way to find ESMF - if (NOT DEFINED ESMFMKFILE) - message(FATAL_ERROR "ESMFMKFILE not defined. This is the path to esmf.mk file. \ +# If it's not explicitly set try to find esmf.mk file in default locations (ESMF_ROOT, CMAKE_PREFIX_PATH, etc) +if(NOT DEFINED ESMFMKFILE) + find_path(ESMFMKFILE_PATH esmf.mk PATH_SUFFIXES lib lib64) + if(ESMFMKFILE_PATH) + set(ESMFMKFILE ${ESMFMKFILE_PATH}/esmf.mk) + message(STATUS "Found esmf.mk file ${ESMFMKFILE}") + else() + message(STATUS "ESMFMKFILE not defined. This is the path to esmf.mk file. \ Without this filepath, ESMF_FOUND will always be FALSE.") - endif () + endif() endif() # Only parse the mk file if it is found -if (ESMF_FOUND) +if(EXISTS ${ESMFMKFILE}) # Read the mk file file(STRINGS "${ESMFMKFILE}" esmfmkfile_contents) # Parse each line in the mk file @@ -37,13 +36,13 @@ if (ESMF_FOUND) # Only consider uncommented lines string(REGEX MATCH "^[^#]" def ${str}) # Line is not commented - if (def) + if(def) # Extract the variable name string(REGEX MATCH "^[^=]+" esmf_varname ${str}) # Extract the variable's value string(REGEX MATCH "=.+$" esmf_vardef ${str}) # Only for variables with a defined value - if (esmf_vardef) + if(esmf_vardef) # Get rid of the assignment string string(SUBSTRING ${esmf_vardef} 1 -1 esmf_vardef) # Remove whitespace @@ -62,7 +61,7 @@ if (ESMF_FOUND) # Promote to global scope set(${esmf_varname} ${esmf_vardef}) # Don't display by default in the GUI - mark_as_advanced (esmf_varname) + mark_as_advanced(esmf_varname) # No need to search for the current string filter break() endif() @@ -72,34 +71,65 @@ if (ESMF_FOUND) endif() endforeach() + # Construct ESMF_VERSION from ESMF_VERSION_STRING_GIT + # ESMF_VERSION_MAJOR and ESMF_VERSION_MINOR are defined in ESMFMKFILE + set(ESMF_VERSION 0) + set(ESMF_VERSION_PATCH ${ESMF_VERSION_REVISION}) + set(ESMF_BETA_RELEASE FALSE) + if(ESMF_VERSION_BETASNAPSHOT MATCHES "^('T')$") + set(ESMF_BETA_RELEASE TRUE) + string(REGEX REPLACE ".*beta_snapshot_*\([0-9]*\).*" "\\1" ESMF_BETA_SNAPSHOT "${ESMF_VERSION_STRING_GIT}") + message(STATUS "Detected ESMF Beta snapshot ${ESMF_BETA_SNAPSHOT}") + endif() + set(ESMF_VERSION "${ESMF_VERSION_MAJOR}.${ESMF_VERSION_MINOR}.${ESMF_VERSION_PATCH}") + separate_arguments(ESMF_F90COMPILEPATHS NATIVE_COMMAND ${ESMF_F90COMPILEPATHS}) - foreach (ITEM ${ESMF_F90COMPILEPATHS}) + foreach(ITEM ${ESMF_F90COMPILEPATHS}) string(REGEX REPLACE "^-I" "" ITEM "${ITEM}") list(APPEND tmp ${ITEM}) endforeach() set(ESMF_F90COMPILEPATHS ${tmp}) - add_library(esmf UNKNOWN IMPORTED) # Look for static library, if not found try dynamic library find_library(esmf_lib NAMES libesmf.a PATHS ${ESMF_LIBSDIR}) if(esmf_lib MATCHES "esmf_lib-NOTFOUND") + unset(esmf_lib) message(STATUS "Static ESMF library not found, searching for dynamic library instead") - find_library(esmf_lib NAMES esmf_fullylinked PATHS ${ESMF_LIBSDIR}) + find_library(esmf_lib NAMES esmf_fullylinked libesmf.so PATHS ${ESMF_LIBSDIR}) if(esmf_lib MATCHES "esmf_lib-NOTFOUND") - message(FATAL_ERROR "Neither the dynamic nor the static ESMF library was found") + unset(esmf_lib) + message(STATUS "Neither the dynamic nor the static ESMF library was found") else() - message(STATUS "Found ESMF library: ${esmf_lib}") + set(_library_type SHARED) endif() - set(ESMF_INTERFACE_LINK_LIBRARIES "") else() - # When linking the static library, also need the ESMF linker flags; strip any leading/trailing whitespaces - string(STRIP "${ESMF_F90ESMFLINKRPATHS} ${ESMF_F90ESMFLINKPATHS} ${ESMF_F90LINKLIBS} ${ESMF_F90LINKOPTS}" ESMF_INTERFACE_LINK_LIBRARIES) - message(STATUS "Found ESMF library: ${esmf_lib}") + set(_library_type STATIC) endif() + string(STRIP "${ESMF_F90ESMFLINKRPATHS} ${ESMF_F90ESMFLINKPATHS} ${ESMF_F90LINKPATHS} ${ESMF_F90LINKLIBS} ${ESMF_F90LINKOPTS}" ESMF_INTERFACE_LINK_LIBRARIES) + set(ESMF_LIBRARY_LOCATION ${esmf_lib}) + +else() + + message(WARNING "ESMFMKFILE ${ESMFMKFILE} does not exist") + +endif() + +## Finalize find_package +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args( + ${CMAKE_FIND_PACKAGE_NAME} + REQUIRED_VARS ESMF_LIBRARY_LOCATION + ESMF_INTERFACE_LINK_LIBRARIES + ESMF_F90COMPILEPATHS + VERSION_VAR ESMF_VERSION) + +## If ESMF is found create imported library target +if(ESMF_FOUND) + add_library(esmf ${_library_type} IMPORTED) set_target_properties(esmf PROPERTIES - IMPORTED_LOCATION ${esmf_lib} + IMPORTED_LOCATION "${ESMF_LIBRARY_LOCATION}" INTERFACE_INCLUDE_DIRECTORIES "${ESMF_F90COMPILEPATHS}" INTERFACE_LINK_LIBRARIES "${ESMF_INTERFACE_LINK_LIBRARIES}") - endif() diff --git a/cmake/FindMETIS.cmake b/cmake/FindMETIS.cmake new file mode 100644 index 000000000..c4f854db7 --- /dev/null +++ b/cmake/FindMETIS.cmake @@ -0,0 +1,18 @@ +find_library(metis_lib NAMES libmetis.a libmetis.so libmetis.dylib HINTS ENV METIS_PATH PATH_SUFFIXES lib) +find_path(metis_inc metis.h HINTS ENV METIS_PATH PATH_SUFFIXES include) + +add_library(METIS::METIS STATIC IMPORTED) + +set_target_properties(METIS::METIS PROPERTIES + IMPORTED_LOCATION "${metis_lib}" + INTERFACE_INCLUDE_DIRECTORIES "${metis_inc}") + +## Finalize find_package +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args( + ${CMAKE_FIND_PACKAGE_NAME} + REQUIRED_VARS metis_lib + metis_inc) + +message(STATUS "Found METIS: ${metis_lib}") diff --git a/model/esmf/cmake/FindNetCDF.cmake b/cmake/FindNetCDF.cmake similarity index 98% rename from model/esmf/cmake/FindNetCDF.cmake rename to cmake/FindNetCDF.cmake index 1439ae848..23f6a1e09 100644 --- a/model/esmf/cmake/FindNetCDF.cmake +++ b/cmake/FindNetCDF.cmake @@ -171,6 +171,21 @@ function(netcdf_config exec flag output_var) endif() endfunction() +## Detect additional package properties +netcdf_config(${NetCDF_C_CONFIG_EXECUTABLE} --has-parallel4 _val) +if( NOT _val MATCHES "^(yes|no)$" ) + netcdf_config(${NetCDF_C_CONFIG_EXECUTABLE} --has-parallel _val) +endif() +if( _val MATCHES "^(yes)$" ) + set(NetCDF_PARALLEL TRUE CACHE STRING "NetCDF has parallel IO capability via pnetcdf or hdf5." FORCE) +else() + set(NetCDF_PARALLEL FALSE CACHE STRING "NetCDF has no parallel IO capability." FORCE) +endif() + +if(NetCDF_PARALLEL) + find_package(MPI) +endif() + ## Find libraries for each component set( NetCDF_LIBRARIES ) foreach( _comp IN LISTS _search_components ) @@ -228,6 +243,12 @@ foreach( _comp IN LISTS _search_components ) IMPORTED_LOCATION ${NetCDF_${_comp}_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_${_comp}_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES ${NetCDF_${_comp}_LIBRARIES} ) + if( NOT _comp MATCHES "^(C)$" ) + target_link_libraries(NetCDF::NetCDF_${_comp} INTERFACE NetCDF::NetCDF_C) + endif() + if(MPI_${_comp}_FOUND) + target_link_libraries(NetCDF::NetCDF_${_comp} INTERFACE MPI::MPI_${_comp}) + endif() endif() endif() endforeach() @@ -263,17 +284,6 @@ if (NetCDF_INCLUDE_DIRS) endif() endif () -## Detect additional package properties -netcdf_config(${NetCDF_C_CONFIG_EXECUTABLE} --has-parallel4 _val) -if( NOT _val MATCHES "^(yes|no)$" ) - netcdf_config(${NetCDF_C_CONFIG_EXECUTABLE} --has-parallel _val) -endif() -if( _val MATCHES "^(yes)$" ) - set(NetCDF_PARALLEL TRUE CACHE STRING "NetCDF has parallel IO capability via pnetcdf or hdf5." FORCE) -else() - set(NetCDF_PARALLEL FALSE CACHE STRING "NetCDF has no parallel IO capability." FORCE) -endif() - ## Finalize find_package include(FindPackageHandleStandardArgs) diff --git a/cmake/FindOASIS.cmake b/cmake/FindOASIS.cmake new file mode 100644 index 000000000..8d0b6d165 --- /dev/null +++ b/cmake/FindOASIS.cmake @@ -0,0 +1,73 @@ +message(STATUS "Searching for oasis3-mct") + + +message(STATUS " Searching for libpsmile...") +find_library(psmile_lib NAMES libpsmile.MPI1.a HINTS ENV OASISDIR PATH_SUFFIXES lib) +if(psmile_lib) + message(STATUS " Found PSMILE: ${psmile_lib}") +else() + message(STATUS " psmile not found...") +endif() + + +message(STATUS " Searching for libmct...") +find_library(mct_lib NAMES libmct.a HINTS ENV OASISDIR PATH_SUFFIXES lib) +if(mct_lib) + message(STATUS " Found: ${mct_lib}") +else() + message(STATUS " mct not found...") +endif() + +message(STATUS " Searching for libmpeu...") +find_library(mpeu_lib NAMES libmpeu.a HINTS ENV OASISDIR PATH_SUFFIXES lib) +if(mpeu_lib) + message(STATUS " Found: ${mpeu_lib}") +else() + message(STATUS " mpeu not found...") +endif() + +message(STATUS " Searching for libscrip...") +find_library(scrip_lib NAMES libscrip.a HINTS ENV OASISDIR PATH_SUFFIXES lib) +if(scrip_lib) + message(STATUS " Found: ${scrip_lib}") +else() + message(STATUS " scrip not found...") +endif() + +message(STATUS " Searching for mod_oasis...") +find_path(oasis_inc mod_oasis.mod PATHS $ENV{OASISDIR}/build/lib/psmile.MPI1) +if(oasis_inc) + message(STATUS " Found: ${oasis_inc}") +else() + message(STATUS " mod_oasis not found...") +endif() + +add_library(PSMILE::PSMILE STATIC IMPORTED) +set_target_properties(PSMILE::PSMILE PROPERTIES + IMPORTED_LOCATION "${psmile_lib}" + ) + +add_library(MCT::MCT STATIC IMPORTED) +set_target_properties(MCT::MCT PROPERTIES + IMPORTED_LOCATION "${mct_lib}" + ) +target_include_directories(MCT::MCT INTERFACE ${mct_inc}) + +add_library(MPEU::MPEU STATIC IMPORTED) +set_target_properties(MPEU::MPEU PROPERTIES + IMPORTED_LOCATION "${mpeu_lib}" + ) + +add_library(SCRIP::SCRIP STATIC IMPORTED) +set_target_properties(SCRIP::SCRIP PROPERTIES + IMPORTED_LOCATION "${scrip_lib}" + ) + +add_library(OASIS::OASIS INTERFACE IMPORTED) +target_link_libraries(OASIS::OASIS INTERFACE PSMILE::PSMILE MCT::MCT MPEU::MPEU SCRIP::SCRIP) +target_include_directories(OASIS::OASIS INTERFACE ${oasis_inc}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + ${CMAKE_FIND_PACKAGE_NAME} + REQUIRED_VARS psmile_lib mct_lib mpeu_lib scrip_lib oasis_inc) diff --git a/cmake/FindParMETIS.cmake b/cmake/FindParMETIS.cmake new file mode 100644 index 000000000..d1b78b928 --- /dev/null +++ b/cmake/FindParMETIS.cmake @@ -0,0 +1,22 @@ +find_library(parmetis_lib NAMES libparmetis.a libparmetis.so libparmetis.dylib HINTS ENV METIS_PATH PATH_SUFFIXES lib) +find_path(parmetis_inc parmetis.h HINTS ENV METIS_PATH PATH_SUFFIXES include) + +find_package(METIS REQUIRED) + +add_library(ParMETIS::ParMETIS STATIC IMPORTED) + +set_target_properties(ParMETIS::ParMETIS PROPERTIES + IMPORTED_LOCATION "${parmetis_lib}" + INTERFACE_INCLUDE_DIRECTORIES "${parmetis_inc}") + +target_link_libraries(ParMETIS::ParMETIS INTERFACE METIS::METIS) + +## Finalize find_package +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args( + ${CMAKE_FIND_PACKAGE_NAME} + REQUIRED_VARS parmetis_lib + parmetis_inc) + +message(STATUS "Found ParMETIS: ${parmetis_lib}") diff --git a/cmake/WW3-package-config.cmake.in b/cmake/WW3-package-config.cmake.in new file mode 100644 index 000000000..bcb875c39 --- /dev/null +++ b/cmake/WW3-package-config.cmake.in @@ -0,0 +1,22 @@ +@PACKAGE_INIT@ + +#@PROJECT_NAME@-config.cmake +# +# Imported interface targets provided: +# * @PROJECT_NAME@::@PROJECT_NAME@_4 - real32 library target +# * @PROJECT_NAME@::@PROJECT_NAME@_d - mixed library target + +# Include targets file. This will create IMPORTED target @PROJECT_NAME@ +include("${CMAKE_CURRENT_LIST_DIR}/WW3-targets.cmake") + +include(CMakeFindDependencyMacro) + +#find_dependency(PNG) +#find_dependency(bacio) + +#get_target_property(@PROJECT_NAME@_BUILD_TYPES @PROJECT_NAME@::@PROJECT_NAME@_4 IMPORTED_CONFIGURATIONS) + +#check_required_components("WW3") + +#get_target_property(location @PROJECT_NAME@::@PROJECT_NAME@_4 LOCATION) +#message(STATUS "Found @PROJECT_NAME@: ${location} (found version \"@PROJECT_VERSION@\")") diff --git a/model/CMakeLists.txt b/model/CMakeLists.txt new file mode 100644 index 000000000..febd4f0ab --- /dev/null +++ b/model/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(src) diff --git a/model/README.md b/model/README.md new file mode 100644 index 000000000..2dcdc436e --- /dev/null +++ b/model/README.md @@ -0,0 +1,156 @@ +# CMake Build + +A CMake build is provided with WW3 to standardize and simplify the WW3 build process. CMake uses an out-of-source build which separates the build directory from the source directory. + +WW3 uses `#ifdef` directives to configure model options. These options are specified in a 'switch file' passed to CMake with `-DSWITCH=/switch/file` during the build. CMake parses the switch options and copies it into the build to determine which files to build, and what values to pass to the pre-processor. + +Switch setting configurations are stored in [switches.json](./bin/switches.json). This file is read by CMake to check the validity of input switches. + +The CMake build does not offer incremental builds. If the switch file changes, on the next `make`, CMake will re-trigger and build from scratch. + +Requires CMake 3.19+ + +## Quick Start + +``` +# Optionally set compiler and env vars to locate libraries +export CC=icc +export FC=ifort +export NetCDF_ROOT=/path/to/netcdf + +# Clone and build WW3 +git clone https://github.com/NOAA-EMC/WW3.git +cd WW3 +mkdir build && cd build +cmake .. -DSWITCH=/path/to/switch_NCEP_st2 -DCMAKE_INSTALL_PREFIX=install +make +make install +``` + +Note `cmake ..` is pointing to the directory containing the top-level CMakeLists.txt (just above the build dir in this case). The build directory can be located anywhere, and then the CMake command would be `cmake /path/to/WW3 -DSWITCH=/path/to/switch_NCEP_st2`. + + +## CMake Options + +Options can be passed to CMake with `-D