Skip to content

Commit

Permalink
Merge pull request #569 from KyleKlenk/master
Browse files Browse the repository at this point in the history
Add CMake Functionality to Summa
  • Loading branch information
wknoben authored Jun 27, 2024
2 parents 2d9f958 + 879d880 commit 70989be
Show file tree
Hide file tree
Showing 7 changed files with 335 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ Makefile-*
*.backup
# site directory from mkdocs
site/
# Compilation Files
build/cmake/cmake_build
119 changes: 119 additions & 0 deletions build/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
cmake_minimum_required(VERSION 3.21 FATAL_ERROR)
project(summa VERSION 3.2.0 LANGUAGES Fortran)

# Add options for build type
set(CMAKE_CONFIGURATION_TYPES Release Debug)

option(USE_OPENMP "Use OpenMP for parallelization" OFF)
if (USE_OPENMP)
find_package(OpenMP REQUIRED)
list(APPEND EXT_TARGETS OpenMP::OpenMP_Fortran)
endif()

# Set Default Executable Name
set(EXEC_NAME summa.exe)
set(F_MASTER "${CMAKE_CURRENT_SOURCE_DIR}/..")
set(EXEC_DIR "${F_MASTER}/bin")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${EXEC_DIR})

# Use Find files for NetCDF and OpenBLAS
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/")
LIST(APPEND CMAKE_PREFIX_PATH "${CMAKE_SOURCE_DIR}/cmake/")

# NetCDF is found with a custom FindNetCDF.cmake file
find_package(NetCDF REQUIRED)
list(APPEND EXT_TARGETS NetCDF::NetCDF)

# Attempt to find LAPACK first
find_package(LAPACK QUIET)
if(LAPACK_FOUND)
message(STATUS "Using LAPACK")
list(APPEND EXT_TARGETS ${LAPACK_LIBRARIES})
else()
# If LAPACK not found, fallback to OpenBLAS
message(STATUS "LAPACK not found, trying OpenBLAS")
set(BLA_VENDOR OpenBLAS)
find_package(OpenBLAS REQUIRED)
list(APPEND EXT_TARGETS OpenBLAS::OpenBLAS)
endif()


# Set Compiler Flags
set(FLAGS_OPT $ENV{FLAGS_OPT}) # get optional user-specified flags from environment variables
if(CMAKE_BUILD_TYPE MATCHES Debug)
message("\nSetting SUMMA Debug Options")
add_compile_definitions(DEBUG)
set(FLAGS_NOAH -g -O0 -fbacktrace -fbounds-check -ffree-form -ffree-line-length-none -fmax-errors=0 -fPIC -Wfatal-errors ${FLAGS_OPT})
set(FLAGS_ALL -g -O0 -fbacktrace -fbounds-check -ffree-line-length-none -fmax-errors=0 -fPIC -Wfatal-errors -cpp ${FLAGS_OPT})
set(FLAGS_CXX -g -O0 -fbounds-check -Wfatal-errors -std=c++17 ${FLAGS_OPT})
else()
message("\nSetting SUMMA Release Options")
set(FLAGS_NOAH -O3 -ffree-form -ffree-line-length-none -fmax-errors=0 -fPIC -Wfatal-errors ${FLAGS_OPT})
set(FLAGS_ALL -O3 -ffree-line-length-none -fmax-errors=0 -fPIC -Wfatal-errors -cpp ${FLAGS_OPT})
set(FLAGS_CXX -O3 -Wfatal-errors -std=c++17 ${FLAGS_OPT})
endif()

#=========================================================================================
# COMPILE PART 1: Define directory paths
#=========================================================================================

# Define directories that contains source code
set(DRIVER_DIR ${F_MASTER}/build/source/driver)
set(DSHARE_DIR ${F_MASTER}/build/source/dshare)
set(ENGINE_DIR ${F_MASTER}/build/source/engine)
set(HOOKUP_DIR ${F_MASTER}/build/source/hookup)
set(NETCDF_DIR ${F_MASTER}/build/source/netcdf)
set(NOAHMP_DIR ${F_MASTER}/build/source/noah-mp)

#=========================================================================================
# COMPILE PART 2: Assemble all of the SUMMA sub-routines
#=========================================================================================

# SUMMA Source Files are defined in the CMakeLists.txt file in the subdirectory
add_subdirectory(${F_MASTER}/build/source/)

#=========================================================================================
# COMPILE PART 3: Collect the subroutines into build groups depending on build type
#=========================================================================================

set(COMM_ALL ${NRPROC} ${HOOKUP} ${DATAMS} ${UTILMS})
set(SUMMA_ALL ${NETCDF} ${PRELIM} ${MODRUN} ${SOLVER} ${DRIVER})
# Add non-actor files
set(SUMMA_ALL ${SUMMA_ALL} ${PRELIM_NOT_ACTORS} ${MODRUN_NOT_ACTORS}
${SOLVER_NOT_ACTORS} ${DRIVER_NOT_ACTORS})
set(MAIN_SUMMA ${DRIVER_DIR}/summa_driver.f90)

# Define version number, not working correctly
set(VERSIONFILE ${DRIVER_DIR}/summaversion.inc)
execute_process(COMMAND " ${GIT_EXECUTABLE} tag | tail -n 1" OUTPUT_VARIABLE VERSION)
execute_process(COMMAND "date" OUTPUT_VARIABLE BULTTIM)
execute_process(COMMAND " ${GIT_EXECUTABLE} describe --long --all --always | sed -e's/heads\///'" OUTPUT_VARIABLE GITBRCH)
execute_process(COMMAND " ${GIT_EXECUTABLE} rev-parse HEAD" OUTPUT_VARIABLE GITHASH)

#=========================================================================================
# COMPILE PART 4: Do the compilation
#=========================================================================================

# update version information, not working correctly
file(WRITE ${VERSIONFILE} "character(len=64), parameter :: summaVersion = '${VERSION}'\n")
file(APPEND ${VERSIONFILE} "character(len=64), parameter :: buildTime = ''\n")
file(APPEND ${VERSIONFILE} "character(len=64), parameter :: gitBranch = '${GITBRCH}'\n")
file(APPEND ${VERSIONFILE} "character(len=64), parameter :: gitHash = '${GITHASH}'")


# Build SUMMA_NOAHMP Object
add_library(SUMMA_NOAHMP OBJECT ${NOAHMP} ${NRUTIL})
target_compile_options(SUMMA_NOAHMP PRIVATE ${FLAGS_NOAH})

# Build SUMMA_COMM Object
add_library(SUMMA_COMM OBJECT ${COMM_ALL})
target_compile_options(SUMMA_COMM PRIVATE ${FLAGS_ALL})
target_link_libraries(SUMMA_COMM PUBLIC SUMMA_NOAHMP ${EXT_TARGETS}) # added flags to the link step

add_library(summa SHARED ${SUMMA_ALL})
target_compile_options(summa PRIVATE ${FLAGS_ALL})
target_link_libraries(summa PUBLIC ${EXT_TARGETS} SUMMA_NOAHMP SUMMA_COMM)

add_executable(${EXEC_NAME} ${MAIN_SUMMA})
set_property(TARGET ${EXEC_NAME} PROPERTY LINKER_LANGUAGE Fortran)
target_link_libraries(${EXEC_NAME} summa ${EXT_TARGETS})
28 changes: 28 additions & 0 deletions build/cmake/FindNetCDF.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
include(FindPackageHandleStandardArgs)

# Find the NetCDF C library and include directory
find_library(NetCDF_C_LIBRARY NAMES netcdf)
find_path(NetCDF_C_INCLUDE_DIR NAMES netcdf.h)

# Find the NetCDF Fortran library
find_library(NetCDF_F90_LIBRARY NAMES netcdff)
find_path(NetCDF_F90_INCLUDE_DIR NAMES netcdf.mod)

set (NetCDF_LIBRARIES ${NetCDF_C_LIBRARY} ${NetCDF_F90_LIBRARY})
set (NetCDF_INCLUDE_DIRS ${NetCDF_C_INCLUDE_DIR} ${NetCDF_F90_INCLUDE_DIR})

find_package_handle_standard_args(NetCDF DEFAULT_MSG
NetCDF_LIBRARIES NetCDF_INCLUDE_DIRS)

if(NetCDF_FOUND)
mark_as_advanced (NetCDF_C_LIBRARY NetCDF_C_INCLUDE_DIR NetCDF_F90_LIBRARY NetCDF_DIR)

add_library(NetCDF::NetCDF INTERFACE IMPORTED)

set_target_properties(NetCDF::NetCDF PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_INCLUDE_DIRS}"
INTERFACE_LINK_LIBRARIES "${NetCDF_LIBRARIES}")

message(STATUS "NetCDF incl for all components -- ${NetCDF_INCLUDE_DIRS}")
message(STATUS "NetCDF lib for all components -- ${NetCDF_LIBRARIES}")
endif()
14 changes: 14 additions & 0 deletions build/cmake/FindOpenBLAS.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Find the OpenBLAS library
find_library(OpenBLAS_LIBRARY NAMES openblas)

# Find the OpenBLAS include directory
find_path(OpenBLAS_INCLUDE_DIR NAMES cblas.h)

if(OpenBLAS_LIBRARY AND OpenBLAS_INCLUDE_DIR)
add_library(OpenBLAS::OpenBLAS INTERFACE IMPORTED)
set_target_properties(OpenBLAS::OpenBLAS PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${OpenBLAS_INCLUDE_DIR}"
INTERFACE_LINK_LIBRARIES "${OpenBLAS_LIBRARY}")
else()
message(FATAL_ERROR "OpenBLAS not found")
endif()
9 changes: 9 additions & 0 deletions build/cmake/compile_script.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash

# Script to compile the SUMMA model using cmake
# This will call the CMakeLists.txt file in one directory above the current
# directory, and create a directory cmake_build where all of the build files
# will be stored. This script will build Summa in parallel.

cmake -B cmake_build -S ../.
cmake --build cmake_build --target all -j
137 changes: 137 additions & 0 deletions build/source/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#===============================================================================
# List of Source Files for SUMMA
# All Variables are reachable from the parent scope
#===============================================================================

# NOAHMP modules
set(NOAHMP
${NOAHMP_DIR}/module_model_constants.F
${NOAHMP_DIR}/module_sf_noahutl.F
${NOAHMP_DIR}/module_sf_noahlsm.F
${NOAHMP_DIR}/module_sf_noahmplsm.F
CACHE INTERNAL "NOAHMP")

# Free versions of numerical recipes utilities for NOAH-MP modules
set(NRUTIL
${ENGINE_DIR}/f2008funcs.f90
${ENGINE_DIR}/nr_utility.f90
${ENGINE_DIR}/nrtype.f90
CACHE INTERNAL "NRUTIL")

# Free versions of numerical recipes procedures for SUMMA modules
set(NRPROC
${ENGINE_DIR}/expIntegral.f90
${ENGINE_DIR}/spline_int.f90
CACHE INTERNAL "NRPROC")

# Hook-up modules
set(HOOKUP
${HOOKUP_DIR}/ascii_util.f90
${HOOKUP_DIR}/summaFileManager.f90
CACHE INTERNAL "HOOKUP")

# Data modules
set(DATAMS
${DSHARE_DIR}/data_types.f90
${DSHARE_DIR}/flxMapping.f90
${DSHARE_DIR}/get_ixname.f90
${DSHARE_DIR}/globalData.f90
${DSHARE_DIR}/multiconst.f90
${DSHARE_DIR}/outpt_stat.f90
${DSHARE_DIR}/popMetadat.f90
${DSHARE_DIR}/var_lookup.f90
CACHE INTERNAL "DATAMS")

# Utility modules
set(UTILMS
${ENGINE_DIR}/matrixOper.f90
${ENGINE_DIR}/mDecisions.f90
${ENGINE_DIR}/snow_utils.f90
${ENGINE_DIR}/soil_utils.f90
${ENGINE_DIR}/time_utils.f90
${ENGINE_DIR}/updatState.f90
CACHE INTERNAL "UTILMS")

# NetCDF routines
set(NETCDF
${NETCDF_DIR}/def_output.f90
${NETCDF_DIR}/modelwrite.f90
${NETCDF_DIR}/netcdf_util.f90
${NETCDF_DIR}/read_icond.f90
CACHE INTERNAL "NETCDF")

# Preliminary modules
set(PRELIM
${ENGINE_DIR}/allocspace.f90
${ENGINE_DIR}/check_icond.f90
${ENGINE_DIR}/checkStruc.f90
${ENGINE_DIR}/childStruc.f90
${ENGINE_DIR}/convE2Temp.f90
${ENGINE_DIR}/conv_funcs.f90
${ENGINE_DIR}/ffile_info.f90
${ENGINE_DIR}/read_pinit.f90
${ENGINE_DIR}/read_attrb.f90
${ENGINE_DIR}/paramCheck.f90
${ENGINE_DIR}/pOverwrite.f90
${ENGINE_DIR}/sunGeomtry.f90
${ENGINE_DIR}/read_param.f90
CACHE INTERNAL "PRELIM")

# Model run support modules
set(MODRUN
${ENGINE_DIR}/canopySnow.f90
${ENGINE_DIR}/derivforce.f90
${ENGINE_DIR}/getVectorz.f90
${ENGINE_DIR}/indexState.f90
${ENGINE_DIR}/layerMerge.f90
${ENGINE_DIR}/layerDivide.f90
${ENGINE_DIR}/qTimeDelay.f90
${ENGINE_DIR}/snowAlbedo.f90
${ENGINE_DIR}/snwCompact.f90
${ENGINE_DIR}/tempAdjust.f90
${ENGINE_DIR}/updateVars.f90
${ENGINE_DIR}/var_derive.f90
${ENGINE_DIR}/volicePack.f90
${ENGINE_DIR}/read_force.f90
CACHE INTERNAL "MODRUN")

# Solver main modules
set(SOLVER
${ENGINE_DIR}/bigAquifer.f90
${ENGINE_DIR}/computFlux.f90
${ENGINE_DIR}/computJacob.f90
${ENGINE_DIR}/computResid.f90
${ENGINE_DIR}/coupled_em.f90
${ENGINE_DIR}/diagn_evar.f90
${ENGINE_DIR}/eval8summa.f90
${ENGINE_DIR}/groundwatr.f90
${ENGINE_DIR}/opSplittin.f90
${ENGINE_DIR}/snowLiqFlx.f90
${ENGINE_DIR}/soilLiqFlx.f90
${ENGINE_DIR}/ssdNrgFlux.f90
${ENGINE_DIR}/stomResist.f90
${ENGINE_DIR}/systemSolv.f90
${ENGINE_DIR}/summaSolve.f90
${ENGINE_DIR}/varSubstep.f90
${ENGINE_DIR}/vegLiqFlux.f90
${ENGINE_DIR}/vegNrgFlux.f90
${ENGINE_DIR}/vegPhenlgy.f90
${ENGINE_DIR}/vegSWavRad.f90
${ENGINE_DIR}/run_oneGRU.f90
${ENGINE_DIR}/run_oneHRU.f90
CACHE INTERNAL "SOLVER")

# Driver support modules
set(DRIVER
${DRIVER_DIR}/summa_type.f90
${DRIVER_DIR}/summa_setup.f90
${DRIVER_DIR}/summa_restart.f90
${DRIVER_DIR}/summa_alarms.f90
${DRIVER_DIR}/summa_globalData.f90
${DRIVER_DIR}/summa_util.f90
${DRIVER_DIR}/summa_defineOutput.f90
${DRIVER_DIR}/summa_init.f90
${DRIVER_DIR}/summa_forcing.f90
${DRIVER_DIR}/summa_modelRun.f90
${DRIVER_DIR}/summa_writeOutput.f90
CACHE INTERNAL "DRIVER")
27 changes: 26 additions & 1 deletion docs/installation/SUMMA_installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

We have successfully installed SUMMA on a number of Unix-like (\*nix) operating systems, including Linux and Darwin (Mac OS X). Since we do a lot of our development on OS X, we have a [separate page](SUMMA_on_OS_X.md) on how to install the necessary tools and libraries on that platform. If you do not want to deal with installing programs and libraries and just want to run SUMMA, then we also have a SUMMA release that uses [Docker](https://www.docker.com). Details can be found on our [SUMMA using Docker](SUMMA_docker.md) page. If you plan to use Docker, then you can skip the rest of this page.

## Dependencies
To compile SUMMA, you will need:

* a Fortran compiler. We have successfully used the intel Fortran compiler (`ifort`, version 17.x) and the GNU Fortran compiler (`gfortran`, version 6 or higher), the latter of which is freely available. Since we do not use any compiler-specific extensions, you should be able to compile SUMMA with other Fortran compilers as well.
Expand Down Expand Up @@ -30,7 +31,11 @@ To compile SUMMA, you will need:
* [Git Workflow for SUMMA](../development/SUMMA_git_workflow.md)
* [SUMMA Coding Conventions](../development/SUMMA_coding_conventions.md)

Once you have all the above, you can compile SUMMA using the following steps:
## Compilation
To compile SUMMA there are two methods, each of which is described in detail below. The first method uses a `Makefile` and is the traditional way to compile SUMMA. The second method uses `CMake` and enables parallelization for faster builds.

### Makefile
Once you have all the above, you can compile SUMMA using the following steps for using the `Makefile`:

1. Navigate to your local copy of the SUMMA directory and go to the `build` subdirectory;

Expand Down Expand Up @@ -125,4 +130,24 @@ Lapack and blas libraries are loaded with library argument `-mkl`.

If you get this far then SUMMA is installed correctly and functional.

## CMake

Most users will be able to compile SUMMA using the following steps, even on Digital Alliance of Canada machines (loaded modules usually automatically set the necessary CMake variables):
```bash
cd summa/build/cmake
./compile_script.sh
```
If the compilation is successful, you will see the help output from running `summa.exe` in `summa/bin/` as shown in the Makefile instructions above.

If you encounter issues with dependencies, it is most likely because they are installed in a non-standard location. If this is the case, you can set the `CMAKE_PREFIX_PATH` variable in the `compile_script.sh` script to the location of the dependencies. For example, if the NetCDF libraries are installed in `/home/some_user/netcdf`, you would modify the `compile_script.sh` script as follows:
```bash
#!/bin/bash

export CMAKE_PREFIX_PATH="$CMAKE_PREFIX_PATH:/home/some_user/netcdf"

cmake -B cmake_build -S ../.
cmake --build cmake_build --target all -j
```


Continue reading [SUMMA configuration](../configuration/SUMMA_configuration.md) to learn more about how to configure SUMMA for your application. We strongly recommend that you get the [test applications](SUMMA_test_cases.md) to help you get started.

0 comments on commit 70989be

Please sign in to comment.