From 5cead2a5e8a975d3618087552cb815fd8511a662 Mon Sep 17 00:00:00 2001 From: Jamie Bresch Date: Mon, 12 Jul 2021 14:57:19 -0600 Subject: [PATCH] JEDI development --- .gitignore | 1 + CMakeLists.txt | 297 +++++++++++++++ cmake/Modules/FindGPTL.cmake | 175 +++++++++ cmake/Modules/FindNetCDF.cmake | 343 ++++++++++++++++++ cmake/Modules/FindPIO.cmake | 181 +++++++++ cmake/Modules/FindPnetCDF.cmake | 174 +++++++++ cmake/PackageConfig.cmake.in | 115 ++++++ src/core_atmosphere/CMakeLists.txt | 159 ++++++++ src/core_atmosphere/Registry.xml | 152 ++++++-- .../diagnostics/Registry_convective.xml | 12 + .../diagnostics/convective_diagnostics.F | 66 +++- src/core_atmosphere/mpas_atm_core.F | 4 + src/core_atmosphere/mpas_atm_core_interface.F | 2 +- .../physics/mpas_atmphys_landuse.F | 6 +- .../physics/physics_wrf/module_mp_thompson.F | 74 ++-- .../utils/atmphys_build_tables_thompson.F | 76 ++-- src/core_init_atmosphere/CMakeLists.txt | 44 +++ src/core_init_atmosphere/Registry.xml | 4 + .../mpas_init_atm_cases.F | 5 +- .../mpas_init_atm_read_met.F | 11 +- src/core_sw/CMakeLists.txt | 29 ++ src/core_test/CMakeLists.txt | 29 ++ src/driver/mpas_subdriver.F | 15 +- src/external/esmf_time_f90/CMakeLists.txt | 34 ++ src/external/ezxml/CMakeLists.txt | 8 + src/framework/CMakeLists.txt | 55 +++ src/framework/mpas_dmpar.F | 205 +++++++++++ src/operators/CMakeLists.txt | 24 ++ src/tools/input_gen/CMakeLists.txt | 6 + src/tools/registry/CMakeLists.txt | 17 + src/tools/registry/gen_inc.c | 47 ++- 31 files changed, 2247 insertions(+), 123 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 cmake/Modules/FindGPTL.cmake create mode 100644 cmake/Modules/FindNetCDF.cmake create mode 100644 cmake/Modules/FindPIO.cmake create mode 100644 cmake/Modules/FindPnetCDF.cmake create mode 100644 cmake/PackageConfig.cmake.in create mode 100644 src/core_atmosphere/CMakeLists.txt create mode 100644 src/core_init_atmosphere/CMakeLists.txt create mode 100644 src/core_sw/CMakeLists.txt create mode 100644 src/core_test/CMakeLists.txt create mode 100644 src/external/esmf_time_f90/CMakeLists.txt create mode 100644 src/external/ezxml/CMakeLists.txt create mode 100644 src/framework/CMakeLists.txt create mode 100644 src/operators/CMakeLists.txt create mode 100644 src/tools/input_gen/CMakeLists.txt create mode 100644 src/tools/registry/CMakeLists.txt diff --git a/.gitignore b/.gitignore index c0852c1bdb..2ac7e56eb0 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ restart_timestamp # Text files (For statistical output from ocean model) *.txt +!CMakeLists.txt # Directories with individual .gitignore files are: # src/external (Externals might have a different compilation method) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..84ce79b116 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,297 @@ +## MPAS-Model +cmake_minimum_required(VERSION 3.12) +project(MPAS LANGUAGES C Fortran VERSION 7.0 DESCRIPTION "MPAS - Model for Prediction Across Scales") + +### Global Configuration + +list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) +set(CMAKE_DIRECTORY_LABELS ${PROJECT_NAME}) +include(GNUInstallDirs) + +# Options +set(MPAS_ALL_CORES atmosphere init_atmosphere landice ocean seaice sw test) +set(MPAS_CORES atmosphere CACHE STRING "MPAS cores to build. Options: ${MPAS_ALL_CORES}") +if(MPAS_CORES MATCHES " ") #Convert strings separated with spaces to CMake list separated with ';' + string(REPLACE " " ";" MPAS_CORES ${MPAS_CORES}) + set(MPAS_CORES ${MPAS_CORES} CACHE STRING "MPAS cores to build. Options: ${MPAS_ALL_CORES}" FORCE) +endif() +option(MPAS_DOUBLE_PRECISION "Use double precision 64-bit Floating point." TRUE) +option(MPAS_PROFILE "Enable GPTL profiling" OFF) +option(MPAS_OPENMP "Enable OpenMP" OFF) +option(BUILD_SHARED_LIBS "Build shared libraries" ON) + +message(STATUS "[OPTION] MPAS_CORES: ${MPAS_CORES}") +message(STATUS "[OPTION] MPAS_DOUBLE_PRECISION: ${MPAS_DOUBLE_PRECISION}") +message(STATUS "[OPTION] MPAS_PROFILE: ${MPAS_PROFILE}") +message(STATUS "[OPTION] MPAS_OPENMP: ${MPAS_OPENMP}") +message(STATUS "[OPTION] BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}") + +# Build product output locations +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + +# Set default build type to RelWithDebInfo +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting default build type to Release. Specify CMAKE_BUILD_TYPE to override.") + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "CMake Build type" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +# Detect MPAS git version +if(NOT MPAS_GIT_VERSION) + find_package(Git QUIET) + if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --dirty + WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" + OUTPUT_VARIABLE _mpas_git_version + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + else() + set(_mpas_git_version "Unknown") + endif() + set(MPAS_GIT_VERSION ${_mpas_git_version} CACHE STRING "MPAS-Model git version") +endif() + +### Dependencies +find_package(OpenMP COMPONENTS Fortran) +find_package(MPI REQUIRED COMPONENTS Fortran) +find_package(NetCDF REQUIRED COMPONENTS Fortran) +find_package(PnetCDF REQUIRED COMPONENTS Fortran) +find_package(PIO REQUIRED COMPONENTS Fortran C) +if(MPAS_PROFILE) + find_package(GPTL REQUIRED) +endif() + +# Find C pre-processor +if(CMAKE_C_COMPILER_ID MATCHES GNU) + find_program(CPP_EXECUTABLE NAMES cpp REQUIRED) + set(CPP_EXTRA_FLAGS -traditional) +elseif(CMAKE_C_COMPILER_ID MATCHES "(Apple)?Clang" ) + find_program(CPP_EXECUTABLE NAMES cpp REQUIRED) +else() + message(STATUS "Unknown compiler: ${CMAKE_C_COMPILER_ID}") + set(CPP_EXECUTABLE ${CMAKE_C_COMPILER}) +endif() + +### Macros: Common target configuration + +## +# mpas_fortran_target( ) +# +# Fortran configuration and options common to all MPAS Fortran targets +# +# * Installs common Fortan modules to a per-compiler-version directory +# * General Fortran formatting and configuration options +# * Per-compiler configuration and options +# * MPAS_DOUBLE_PRECISION related flags +# +# Args: +# - The name of the target to prepare +# +macro(mpas_fortran_target _tgt) + # Fortran modules include path + set_target_properties(${_tgt} PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/${MPAS_MODULE_DIR}) + target_include_directories(${_tgt} INTERFACE $ + $) + #Relocatable, portable, runtime dynamic linking + set_target_properties(${_tgt} PROPERTIES INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}") + + # Global Fortran configuration + set_target_properties(${_tgt} PROPERTIES Fortran_FORMAT FREE) + target_compile_definitions(${_tgt} PRIVATE _MPI=1) + target_compile_definitions(${_tgt} PRIVATE USE_PIO2=1) + + # Enable OpenMP support + if(MPAS_OPENMP) + target_link_libraries(${_tgt} PUBLIC OpenMP::OpenMP_Fortran) + endif() + + # Compiler-specific options and flags + if(CMAKE_Fortran_COMPILER_ID MATCHES GNU) + target_compile_options(${_tgt} PRIVATE $<$:-ffree-line-length-none>) + target_compile_options(${_tgt} PUBLIC $<$:-fconvert=big-endian>) + if(CMAKE_Fortran_COMPILER_VERSION VERSION_GREATER_EQUAL 10) + target_compile_options(${_tgt} PRIVATE $<$:-fallow-argument-mismatch>) + target_compile_options(${_tgt} PRIVATE $<$:-fallow-invalid-boz>) + endif() + if(MPAS_DOUBLE_PRECISION) + target_compile_options(${_tgt} PRIVATE $<$:-fdefault-real-8> $<$:-fdefault-double-8>) + endif() + elseif(CMAKE_Fortran_COMPILER_ID MATCHES Intel) + target_compile_options(${_tgt} PUBLIC $<$:-convert big_endian>) + target_compile_options(${_tgt} PUBLIC $<$:-align array64byte>) + if(MPAS_DOUBLE_PRECISION) + target_compile_options(${_tgt} PRIVATE $<$:-real-size 64>) + endif() + endif() +endmacro() + +## +# mpas_core_target(CORE TARGET INCLUDE ) +# +# Common configuration and properties for `MPAS::core::` targets. +# * Calls mpas_fortran_target() for common Fortran target configuration. +# * Installs Fortran modules to a per-core directory and adds target include directories +# appropriate for build and install trees. +# * XML Processing, parsing and generation of includes, namelists and streams +# * Each core uses a core-specific parser executable +# * Links to MPAS::framework and MPAS::operators +# * Exports MPAS::core:: target alias for use by external dependencies +# * Installs core libraries modules and generated files. +# +# Args: +# CORE - Name of core +# TARGET - Name of core_target (without namespace) +# INCLUDES - List of generated include files +# +macro(mpas_core_target) + cmake_parse_arguments(_ARG "" "CORE;TARGET" "INCLUDES" ${ARGN}) + + mpas_fortran_target(${_ARG_TARGET}) + + set_property(TARGET ${_ARG_TARGET} APPEND PROPERTY SOURCES ${MPAS_SUBDRIVER_SRC}) + + string(TOUPPER "${_ARG_TARGET}" _TGT) + set_target_properties(${_ARG_TARGET} PROPERTIES OUTPUT_NAME mpas_${_ARG_CORE}) + + #Fortran modules output location + set(CORE_MODULE_DIR ${MPAS_MODULE_DIR}/${_ARG_TARGET}) + set_target_properties(${_ARG_TARGET} PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/${CORE_MODULE_DIR}) + target_include_directories(${_ARG_TARGET} INTERFACE $ + $) + + #MPAS Specific option + target_compile_definitions(${_ARG_TARGET} PRIVATE ${_TGT}=1) + + #Generated includes are included from either ./inc/ or ./ so we create a symlink in the build directory + #To handle the inc/ variety (sw, test, seaice) uniformly with the ./ variety (atmosphere, init_atmosphere) + add_custom_target(${_ARG_CORE}_include_link ALL + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/inc) + add_dependencies(${_ARG_TARGET} ${_ARG_CORE}_include_link) + target_include_directories(${_ARG_TARGET} PUBLIC $) + + #Core-independent library dependencies + target_link_libraries(${_ARG_TARGET} PUBLIC ${PROJECT_NAME}::framework) + target_link_libraries(${_ARG_TARGET} PUBLIC ${PROJECT_NAME}::operators) + + #Define alias for external use + add_library(${PROJECT_NAME}::core::${_ARG_CORE} ALIAS ${_ARG_TARGET}) + + #Create main executable + add_executable(mpas_${_ARG_CORE} ${MPAS_MAIN_SRC}) + mpas_fortran_target(mpas_${_ARG_CORE}) + target_link_libraries(mpas_${_ARG_CORE} PUBLIC ${PROJECT_NAME}::core::${_ARG_CORE}) + + #Per-core generated output and tables directory location + set(CORE_DATADIR ${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${_ARG_TARGET}) + file(MAKE_DIRECTORY ${CORE_DATADIR}) + + #Process registry and generate includes, namelists, and streams + add_custom_command(OUTPUT Registry_processed.xml + COMMAND ${CPP_EXECUTABLE} -E -P ${CPP_EXTRA_FLAGS} ${CMAKE_CURRENT_SOURCE_DIR}/Registry.xml > Registry_processed.xml + COMMENT "CORE ${_ARG_CORE}: Pre-Process Registry" + DEPENDS Registry.xml) + add_custom_command(OUTPUT ${_ARG_INCLUDES} + COMMAND mpas_parse_${_ARG_CORE} Registry_processed.xml + COMMENT "CORE ${_ARG_CORE}: Parse Registry" + DEPENDS mpas_parse_${_ARG_CORE} Registry_processed.xml) + add_custom_command(OUTPUT namelist.${_ARG_CORE} + WORKING_DIRECTORY ${CORE_DATADIR} + COMMAND mpas_namelist_gen ${CMAKE_CURRENT_BINARY_DIR}/Registry_processed.xml namelist.${_ARG_CORE} in_defaults=true + COMMENT "CORE ${_ARG_CORE}: Generate Namelist" + DEPENDS mpas_namelist_gen Registry_processed.xml) + add_custom_command(OUTPUT streams.${_ARG_CORE} + WORKING_DIRECTORY ${CORE_DATADIR} + COMMAND mpas_streams_gen ${CMAKE_CURRENT_BINARY_DIR}/Registry_processed.xml streams.${_ARG_CORE} stream_list.${_ARG_CORE}. listed + COMMENT "CORE ${_ARG_CORE}: Generate Streams" + DEPENDS mpas_streams_gen Registry_processed.xml) + add_custom_target(gen_${_ARG_CORE} DEPENDS ${_ARG_INCLUDES} namelist.${_ARG_CORE} streams.${_ARG_CORE}) + add_dependencies(${_ARG_TARGET} gen_${_ARG_CORE}) + + #Install data and target library and executable + install(DIRECTORY ${CORE_DATADIR}/ DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/${_ARG_TARGET} + FILES_MATCHING PATTERN "namelist.*" PATTERN "streams.*" PATTERN "stream_list.*" ) + install(TARGETS ${_ARG_TARGET} EXPORT ${PROJECT_NAME}ExportsCore + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS mpas_${_ARG_CORE} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) +endmacro() + + +## Common Variables + +# Fortran module output directory for build interface +set(MPAS_MODULE_DIR ${PROJECT_NAME}/module/${CMAKE_Fortran_COMPILER_ID}/${CMAKE_Fortran_COMPILER_VERSION}) +# Install Fortran module directory +install(DIRECTORY ${CMAKE_BINARY_DIR}/${MPAS_MODULE_DIR}/ DESTINATION ${CMAKE_INSTALL_LIBDIR}/${MPAS_MODULE_DIR}/) + +# Location of common subdriver module compiled by each cores +set(MPAS_MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/driver/mpas.F) +set(MPAS_SUBDRIVER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/driver/mpas_subdriver.F) + +## Create targets +add_subdirectory(src/external/ezxml) # Target: MPAS::external::ezxml +add_subdirectory(src/external/esmf_time_f90) # Target: MPAS::external::esmf_time +add_subdirectory(src/tools/input_gen) # Targets: namelist_gen, streams_gen +add_subdirectory(src/tools/registry) # Targets: mpas_parse_ +add_subdirectory(src/framework) # Target: MPAS::framework +add_subdirectory(src/operators) # Target: MPAS::operators + +foreach(_core IN LISTS MPAS_CORES) + add_subdirectory(src/core_${_core}) # Target: MPAS::core:: +endforeach() + +### Package config +include(CMakePackageConfigHelpers) + +# Build-tree target exports +export(EXPORT ${PROJECT_NAME}ExportsExternal NAMESPACE ${PROJECT_NAME}::external:: FILE ${PROJECT_NAME}-targets-external.cmake) +export(EXPORT ${PROJECT_NAME}Exports NAMESPACE ${PROJECT_NAME}:: FILE ${PROJECT_NAME}-targets.cmake) +export(EXPORT ${PROJECT_NAME}ExportsCore NAMESPACE ${PROJECT_NAME}::core:: FILE ${PROJECT_NAME}-targets-core.cmake) + +# CMake Config file install location +set(CONFIG_INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}) +# Install MPAS-supplied Find.cmake modules for use by downstream CMake dependencies +install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules DESTINATION ${CONFIG_INSTALL_DESTINATION}) + +## -config.cmake: build-tree +# Variables to export for use from build-tree +set(BINDIR ${CMAKE_BINARY_DIR}/bin) +set(CORE_DATADIR_ROOT ${CMAKE_BINARY_DIR}/${PROJECT_NAME}) +set(CMAKE_MODULE_INSTALL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) +string(TOLOWER ${PROJECT_NAME} _project_name_lower) +configure_package_config_file(cmake/PackageConfig.cmake.in ${_project_name_lower}-config.cmake + INSTALL_DESTINATION . + INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR} + PATH_VARS BINDIR CORE_DATADIR_ROOT CMAKE_MODULE_INSTALL_PATH) + +## -config.cmake: install-tree +# Variables to export for use from install-tree +set(BINDIR ${CMAKE_INSTALL_BINDIR}) +set(CORE_DATADIR_ROOT ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}) +set(CMAKE_MODULE_INSTALL_PATH ${CONFIG_INSTALL_DESTINATION}/Modules) +configure_package_config_file(cmake/PackageConfig.cmake.in install/${_project_name_lower}-config.cmake + INSTALL_DESTINATION ${CONFIG_INSTALL_DESTINATION} + PATH_VARS BINDIR CORE_DATADIR_ROOT CMAKE_MODULE_INSTALL_PATH) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/install/${_project_name_lower}-config.cmake + DESTINATION ${CONFIG_INSTALL_DESTINATION}) + +## -config-version.cmake +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/${_project_name_lower}-config-version.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${_project_name_lower}-config-version.cmake + DESTINATION ${CONFIG_INSTALL_DESTINATION}) + +## package-targets.cmake and package-targets-.cmake +install(EXPORT ${PROJECT_NAME}ExportsExternal NAMESPACE ${PROJECT_NAME}::external:: + FILE ${_project_name_lower}-targets-external.cmake + DESTINATION ${CONFIG_INSTALL_DESTINATION}) +install(EXPORT ${PROJECT_NAME}Exports NAMESPACE ${PROJECT_NAME}:: + FILE ${_project_name_lower}-targets.cmake + DESTINATION ${CONFIG_INSTALL_DESTINATION}) +install(EXPORT ${PROJECT_NAME}ExportsCore NAMESPACE ${PROJECT_NAME}::core:: + FILE ${_project_name_lower}-targets-core.cmake + DESTINATION ${CONFIG_INSTALL_DESTINATION}) diff --git a/cmake/Modules/FindGPTL.cmake b/cmake/Modules/FindGPTL.cmake new file mode 100644 index 0000000000..8e8014c337 --- /dev/null +++ b/cmake/Modules/FindGPTL.cmake @@ -0,0 +1,175 @@ +# FindGPTL.cmake +# +# Copyright UCAR 2020 +# +# Find the GPTL: General Purpose Timing Library (https://jmrosinski.github.io/GPTL/) +# +# This find module sets the following variables and targets: +# +# Variables: +# GPTL_FOUND - True if GPTL was found +# GPTL_VERSION_STRING - Version of installed GPTL +# GPTL_BIN_DIR - GPTL binary directory +# GPTL_HAS_PKG_CONFIG - GPTL was found with installed `gptl.pc` and pkg-config. This indicates full support +# for compiler and linker flags as exported by GPTL. +# Targets: +# GPTL::GPTL - Imported interface target to pass to target_link_libraries() +# +# NOTE: This find modules uses `pkg-config` to locate GPTL and glean the appropriate flags, directories, +# and link dependency ordering. For this to work, both a `pkg-config` executable and a `gptl.pc` +# config file need to be found. +# * To find the `pkg-config` executable, ensure it is on your PATH. +# * For non-standard locations the official CMake FindPkgConfig uses Cmake variable `PKG_CONFIG_EXECUTABLE` +# or environment variable `PKG_CONFIG`. See: https://cmake.org/cmake/help/latest/module/FindPkgConfig.html +# * To find `gptl.pc` ensure it is on the (colon-separated) directories listed in standard pkg-config +# environment variable `PKG_CONFIG_PATH`. +# * See: https://linux.die.net/man/1/pkg-config +# * A working GPTL pkg-config install can be confirmed on the command line, e.g., +# ``` +# $ pkg-config --modversion gptl +# 8.0.2 +# ``` +# To set a non-standard location for GPTL, ensure the correct `gptl.pc` pkg config file is found first +# on the environment's `PKG_CONFIG_PATH`. This can be checked with the pkg-config executable, e.g., +# ``` +# $ pkg-config --variable=prefix gptl +# /usr/local +# ``` +# Only when pkg-config is not supported or available, GPTL will be searched by the standard CMake search procedures. +# Set environment or CMake variable GPTL_ROOT to control this search. The GPTL_ROOT variable will have no effect +# if GPTL_HAS_PKG_CONFIG=True. +# + +find_package(PkgConfig QUIET) +if(PKG_CONFIG_FOUND) + message(DEBUG "[FindGPTL] Using PKG_CONFIG_EXECUTABLE:${PKG_CONFIG_EXECUTABLE}") +endif() + +#Helper: +#check_pkg_config(ret_var pcname pcflags...) +# Check if pcname is known to pkg-config +# Returns: +# Boolean: true if ${pcname}.pc file is found by pkg-config). +# Args: +# ret_var: return variable name. +# pcname: pkg-config name to look for (.pc file) +function(check_pkg_config ret_var pcname) + if(NOT PKG_CONFIG_FOUND OR NOT EXISTS ${PKG_CONFIG_EXECUTABLE}) + set(${ret_var} False PARENT_SCOPE) + else() + execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --exists ${pcname} RESULT_VARIABLE _found) + if(_found EQUAL 0) + set(${ret_var} True PARENT_SCOPE) + else() + set(${ret_var} False PARENT_SCOPE) + endif() + endif() +endfunction() + +#Helper: +#get_pkg_config(ret_var pcname pcflags...) +# Get the output of pkg-config +# Args: +# ret_var: return variable name +# pcname: pkg-config name to look for (.pc file) +# pcflags: pkg-config flags to pass +function(get_pkg_config ret_var pcname pcflags) + execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} ${ARGN} ${pcname} ${pcflags} OUTPUT_VARIABLE _out RESULT_VARIABLE _ret OUTPUT_STRIP_TRAILING_WHITESPACE) + if(_ret EQUAL 0) + separate_arguments(_out) + set(${ret_var} ${_out} PARENT_SCOPE) + else() + set(${ret_var} "" PARENT_SCOPE) + endif() +endfunction() + +check_pkg_config(GPTL_HAS_PKG_CONFIG gptl) +if(GPTL_HAS_PKG_CONFIG) + #Use pkg-config to find the prefix, flags, directories, executables, and libraries + get_pkg_config(GPTL_VERSION_STRING gptl --modversion) + get_pkg_config(GPTL_PREFIX gptl --variable=prefix) + get_pkg_config(GPTL_INCLUDE_DIR gptl --cflags-only-I) + if(EXISTS GPTL_INCLUDE_DIR) + string(REGEX REPLACE "-I([^ ]+)" "\\1;" GPTL_INCLUDE_DIR ${GPTL_INCLUDE_DIR}) #Remove -I + else() + find_path(GPTL_INCLUDE_DIR NAMES gptl.h PATH_SUFFIXES include include/gptl PATHS ${GPTL_PREFIX} NO_DEFAULT_PATH) + endif() + find_path(GPTL_MODULE_DIR NAMES gptl.mod PATH_SUFFIXES include include/gptl module module/gptl PATHS ${GPTL_PREFIX} NO_DEFAULT_PATH) + get_pkg_config(GPTL_COMPILE_OPTIONS gptl --cflags-only-other) + get_pkg_config(GPTL_LINK_LIBRARIES gptl --libs-only-l) + get_pkg_config(GPTL_LINK_DIRECTORIES gptl --libs-only-L) + if(GPTL_LINK_DIRECTORIES) + string(REGEX REPLACE "-L([^ ]+)" "\\1;" GPTL_LINK_DIRECTORIES ${GPTL_LINK_DIRECTORIES}) #Remove -L + endif() + get_pkg_config(GPTL_LINK_OPTIONS gptl --libs-only-other) + find_library(GPTL_LIBRARY NAMES gptl PATH_SUFFIXES lib lib64 PATHS ${GPTL_PREFIX} NO_DEFAULT_PATH) + find_path(GPTL_BIN_DIR NAMES gptl_avail PATH_SUFFIXES bin PATHS ${GPTL_PREFIX} NO_DEFAULT_PATH) +else() + #Attempt to find GPTL without pkg-config as last resort. + message(WARNING "\ +FindGPTL: The `pkg-config` executable was not found. Ensure it is on your path or set \ +environment variable PKG_CONFIG to your pkg-config executable. \ +Attempting to find GPTL without pkg-config support may cause some required compiler and linker options to be unset.") + + find_path(GPTL_INCLUDE_DIR NAMES gptl.h PATH_SUFFIXES include include/gptl) + find_path(GPTL_MODULE_DIR NAMES gptl.mod PATH_SUFFIXES include include/gptl module module/gptl) + find_library(GPTL_LIBRARY NAMES gptl PATH_SUFFIXES lib lib64) + find_path(GPTL_BIN_DIR NAMES gptl_avail PATH_SUFFIXES bin) +endif() + +#Hide non-documented cache variables reserved for internal/advanced usage +mark_as_advanced( GPTL_INCLUDE_DIR + GPTL_MODULE_DIR + GPTL_LIBRARY ) + +#Debugging output +message(DEBUG "[FindGPTL] GPTL_FOUND: ${GPTL_FOUND}") +message(DEBUG "[FindGPTL] GPTL_VERSION_STRING: ${GPTL_VERSION_STRING}") +message(DEBUG "[FindGPTL] GPTL_HAS_PKG_CONFIG: ${GPTL_HAS_PKG_CONFIG}") +message(DEBUG "[FindGPTL] GPTL_PREFIX: ${GPTL_PREFIX}") +message(DEBUG "[FindGPTL] GPTL_BIN_DIR: ${GPTL_BIN_DIR}") +message(DEBUG "[FindGPTL] GPTL_INCLUDE_DIR: ${GPTL_INCLUDE_DIR}") +message(DEBUG "[FindGPTL] GPTL_MODULE_DIR: ${GPTL_MODULE_DIR}") +message(DEBUG "[FindGPTL] GPTL_LIBRARY: ${GPTL_LIBRARY}") +message(DEBUG "[FindGPTL] GPTL_LINK_LIBRARIES: ${GPTL_LINK_LIBRARIES}") +message(DEBUG "[FindGPTL] GPTL_LINK_DIRECTORIES: ${GPTL_LINK_DIRECTORIES}") +message(DEBUG "[FindGPTL] GPTL_LINK_OPTIONS: ${GPTL_LINK_OPTIONS}") + +#Check package has been found correctly +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + GPTL + REQUIRED_VARS + GPTL_LIBRARY + GPTL_INCLUDE_DIR + GPTL_MODULE_DIR + GPTL_BIN_DIR + VERSION_VAR + GPTL_VERSION_STRING +) + +#Create GPTL::GPTL imported interface target +if(GPTL_FOUND AND NOT TARGET GPTL::GPTL) + add_library(GPTL::GPTL INTERFACE IMPORTED) + set_property(TARGET GPTL::GPTL PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${GPTL_INCLUDE_DIR}) + if(GPTL_MODULE_DIR) + set_property(TARGET GPTL::GPTL APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${GPTL_MODULE_DIR}) + endif() + if(GPTL_COMPILE_OPTIONS) + set_property(TARGET GPTL::GPTL PROPERTY INTERFACE_COMPILE_OPTIONS ${GPTL_COMPILE_OPTIONS}) + endif() + if(GPTL_LINK_DIRECTORIES) + set_property(TARGET GPTL::GPTL PROPERTY INTERFACE_LINK_DIRECTORIES ${GPTL_LINK_DIRECTORIES}) + endif() + if(GPTL_LINK_OPTIONS) + set_property(TARGET GPTL::GPTL PROPERTY INTERFACE_LINK_OPTIONS ${GPTL_LINK_OPTIONS}) + endif() + if(GPTL_LINK_LIBRARIES) + set_property(TARGET GPTL::GPTL PROPERTY INTERFACE_LINK_LIBRARIES ${GPTL_LINK_LIBRARIES}) + else() + set_property(TARGET GPTL::GPTL PROPERTY INTERFACE_LINK_LIBRARIES ${GPTL_LIBRARY}) + get_filename_component(_lib_dir ${GPTL_LIBRARY} DIRECTORY) + set_property(TARGET GPTL::GPTL APPEND PROPERTY INTERFACE_LINK_DIRECTORIES ${_lib_dir}) + unset(_lib_dir) + endif() +endif() diff --git a/cmake/Modules/FindNetCDF.cmake b/cmake/Modules/FindNetCDF.cmake new file mode 100644 index 0000000000..f2fc6ac514 --- /dev/null +++ b/cmake/Modules/FindNetCDF.cmake @@ -0,0 +1,343 @@ +# (C) Copyright 2017-2020 UCAR +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# +# (C) Copyright 2011- ECMWF. +# +# This software is licensed under the terms of the Apache Licence Version 2.0 +# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. +# In applying this licence, ECMWF does not waive the privileges and immunities +# granted to it by virtue of its status as an intergovernmental organisation nor +# does it submit to any jurisdiction. +# +# Try to find NetCDF includes and library. +# Supports static and shared libaries and allows each component to be found in sepearte prefixes. +# +# This module defines +# +# - NetCDF_FOUND - System has NetCDF +# - NetCDF_INCLUDE_DIRS - the NetCDF include directories +# - NetCDF_VERSION - the version of NetCDF +# - NetCDF_CONFIG_EXECUTABLE - the netcdf-config executable if found +# - NetCDF_PARALLEL - Boolean True if NetCDF4 has parallel IO support via hdf5 and/or pnetcdf +# - NetCDF_HAS_PNETCDF - Boolean True if NetCDF4 has pnetcdf support +# +# Deprecated Defines +# - NetCDF_LIBRARIES - [Deprecated] Use NetCDF::NetCDF_ targets instead. +# +# +# Following components are available: +# +# - C - C interface to NetCDF (netcdf) +# - CXX - CXX4 interface to NetCDF (netcdf_c++4) +# - Fortran - Fortran interface to NetCDF (netcdff) +# +# For each component the following are defined: +# +# - NetCDF__FOUND - whether the component is found +# - NetCDF__LIBRARIES - the libraries for the component +# - NetCDF__LIBRARY_SHARED - Boolean is true if libraries for component are shared +# - NetCDF__INCLUDE_DIRS - the include directories for specified component +# - NetCDF::NetCDF_ - target of component to be used with target_link_libraries() +# +# The following paths will be searched in order if set in CMake (first priority) or environment (second priority) +# +# - NetCDF_ROOT - root of NetCDF installation +# - NetCDF_PATH - root of NetCDF installation +# +# The search process begins with locating NetCDF Include headers. If these are in a non-standard location, +# set one of the following CMake or environment variables to point to the location: +# +# - NetCDF_INCLUDE_DIR or NetCDF_${comp}_INCLUDE_DIR +# - NetCDF_INCLUDE_DIRS or NetCDF_${comp}_INCLUDE_DIR +# +# Notes: +# +# - Use "NetCDF::NetCDF_" targets only. NetCDF_LIBRARIES exists for backwards compatibility and should not be used. +# - These targets have all the knowledge of include directories and library search directories, and a single +# call to target_link_libraries will provide all these transitive properties to your target. Normally all that is +# needed to build and link against NetCDF is, e.g.: +# target_link_libraries(my_c_tgt PUBLIC NetCDF::NetCDF_C) +# - "NetCDF" is always the preferred naming for this package, its targets, variables, and environment variables +# - For compatibility, some variables are also set/checked using alternate names NetCDF4, NETCDF, or NETCDF4 +# - Environments relying on these older environment variable names should move to using a "NetCDF_ROOT" environment variable +# - Preferred component capitalization follows the CMake LANGUAGES variables: i.e., C, Fortran, CXX +# - For compatibility, alternate capitalizations are supported but should not be used. +# - If no components are defined, all components will be searched +# + +list( APPEND _possible_components C CXX Fortran ) + +## Include names for each component +set( NetCDF_C_INCLUDE_NAME netcdf.h ) +set( NetCDF_CXX_INCLUDE_NAME netcdf ) +set( NetCDF_Fortran_INCLUDE_NAME netcdf.mod ) + +## Library names for each component +set( NetCDF_C_LIBRARY_NAME netcdf ) +set( NetCDF_CXX_LIBRARY_NAME netcdf_c++4 ) +set( NetCDF_Fortran_LIBRARY_NAME netcdff ) + +## Enumerate search components +foreach( _comp ${_possible_components} ) + string( TOUPPER "${_comp}" _COMP ) + set( _arg_${_COMP} ${_comp} ) + set( _name_${_COMP} ${_comp} ) +endforeach() + +set( _search_components C) +foreach( _comp ${${CMAKE_FIND_PACKAGE_NAME}_FIND_COMPONENTS} ) + string( TOUPPER "${_comp}" _COMP ) + set( _arg_${_COMP} ${_comp} ) + list( APPEND _search_components ${_name_${_COMP}} ) + if( NOT _name_${_COMP} ) + message(SEND_ERROR "Find${CMAKE_FIND_PACKAGE_NAME}: COMPONENT ${_comp} is not a valid component. Valid components: ${_possible_components}" ) + endif() +endforeach() +list( REMOVE_DUPLICATES _search_components ) + +## Search hints for finding include directories and libraries +foreach( _comp IN ITEMS "_" "_C_" "_Fortran_" "_CXX_" ) + foreach( _name IN ITEMS NetCDF4 NetCDF NETCDF4 NETCDF ) + foreach( _var IN ITEMS ROOT PATH ) + list(APPEND _search_hints ${${_name}${_comp}${_var}} $ENV{${_name}${_comp}${_var}} ) + list(APPEND _include_search_hints + ${${_name}${_comp}INCLUDE_DIR} $ENV{${_name}${_comp}INCLUDE_DIR} + ${${_name}${_comp}INCLUDE_DIRS} $ENV{${_name}${_comp}INCLUDE_DIRS} ) + endforeach() + endforeach() +endforeach() +#Old-school HPC module env variable names +foreach( _name IN ITEMS NetCDF4 NetCDF NETCDF4 NETCDF ) + foreach( _comp IN ITEMS "_C" "_Fortran" "_CXX" ) + list(APPEND _search_hints ${${_name}} $ENV{${_name}}) + list(APPEND _search_hints ${${_name}${_comp}} $ENV{${_name}${_comp}}) + endforeach() +endforeach() + +## Find headers for each component +set(NetCDF_INCLUDE_DIRS) +set(_new_search_components) +foreach( _comp IN LISTS _search_components ) + if(NOT ${PROJECT_NAME}_NetCDF_${_comp}_FOUND) + list(APPEND _new_search_components ${_comp}) + endif() + find_file(NetCDF_${_comp}_INCLUDE_FILE + NAMES ${NetCDF_${_comp}_INCLUDE_NAME} + DOC "NetCDF ${_comp} include directory" + HINTS ${_include_search_hints} ${_search_hints} + PATH_SUFFIXES include include/netcdf + ) + mark_as_advanced(NetCDF_${_comp}_INCLUDE_FILE) + message(DEBUG "NetCDF_${_comp}_INCLUDE_FILE: ${NetCDF_${_comp}_INCLUDE_FILE}") + if( NetCDF_${_comp}_INCLUDE_FILE ) + get_filename_component(NetCDF_${_comp}_INCLUDE_FILE ${NetCDF_${_comp}_INCLUDE_FILE} ABSOLUTE) + get_filename_component(NetCDF_${_comp}_INCLUDE_DIR ${NetCDF_${_comp}_INCLUDE_FILE} DIRECTORY) + list(APPEND NetCDF_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIR}) + endif() +endforeach() +if(NetCDF_INCLUDE_DIRS) + list(REMOVE_DUPLICATES NetCDF_INCLUDE_DIRS) +endif() +set(NetCDF_INCLUDE_DIRS "${NetCDF_INCLUDE_DIRS}" CACHE STRING "NetCDF Include directory paths" FORCE) + +## Find n*-config executables for search components +foreach( _comp IN LISTS _search_components ) + if( _comp MATCHES "^(C)$" ) + set(_conf "c") + elseif( _comp MATCHES "^(Fortran)$" ) + set(_conf "f") + elseif( _comp MATCHES "^(CXX)$" ) + set(_conf "cxx4") + endif() + find_program( NetCDF_${_comp}_CONFIG_EXECUTABLE + NAMES n${_conf}-config + HINTS ${NetCDF_INCLUDE_DIRS} ${_include_search_hints} ${_search_hints} + PATH_SUFFIXES bin Bin ../bin ../../bin + DOC "NetCDF n${_conf}-config helper" ) + message(DEBUG "NetCDF_${_comp}_CONFIG_EXECUTABLE: ${NetCDF_${_comp}_CONFIG_EXECUTABLE}") +endforeach() + +set(_C_libs_flag --libs) +set(_Fortran_libs_flag --flibs) +set(_CXX_libs_flag --libs) +set(_C_includes_flag --includedir) +set(_Fortran_includes_flag --includedir) +set(_CXX_includes_flag --includedir) +function(netcdf_config exec flag output_var) + set(${output_var} False PARENT_SCOPE) + if( exec ) + execute_process( COMMAND ${exec} ${flag} RESULT_VARIABLE _ret OUTPUT_VARIABLE _val) + if( _ret EQUAL 0 ) + string( STRIP ${_val} _val ) + set( ${output_var} ${_val} PARENT_SCOPE ) + endif() + endif() +endfunction() + +## Find libraries for each component +set( NetCDF_LIBRARIES ) +foreach( _comp IN LISTS _search_components ) + string( TOUPPER "${_comp}" _COMP ) + + find_library( NetCDF_${_comp}_LIBRARY + NAMES ${NetCDF_${_comp}_LIBRARY_NAME} + DOC "NetCDF ${_comp} library" + HINTS ${NetCDF_${_comp}_INCLUDE_DIRS} ${_search_hints} + PATH_SUFFIXES lib64 lib ../lib64 ../lib ../../lib64 ../../lib ) + mark_as_advanced( NetCDF_${_comp}_LIBRARY ) + get_filename_component(NetCDF_${_comp}_LIBRARY ${NetCDF_${_comp}_LIBRARY} ABSOLUTE) + set(NetCDF_${_comp}_LIBRARY ${NetCDF_${_comp}_LIBRARY} CACHE STRING "NetCDF ${_comp} library" FORCE) + message(DEBUG "NetCDF_${_comp}_LIBRARY: ${NetCDF_${_comp}_LIBRARY}") + + + if( NetCDF_${_comp}_LIBRARY ) + if( NetCDF_${_comp}_LIBRARY MATCHES ".a$" ) + set( NetCDF_${_comp}_LIBRARY_SHARED FALSE ) + set( _library_type STATIC) + else() + if( NOT ${NetCDF_${_comp}_LIBRARY} IN_LIST NetCDF_LIBRARIES ) + list( APPEND NetCDF_LIBRARIES ${NetCDF_${_comp}_LIBRARY} ) + message(DEBUG "Adding new netcdf library [${_comp}]: ${NetCDF_${_comp}_LIBRARY}") + endif() + set( NetCDF_${_comp}_LIBRARY_SHARED TRUE ) + set( _library_type SHARED) + endif() + endif() + + #Use nc-config to set per-component LIBRARIES variable if possible + netcdf_config( ${NetCDF_${_comp}_CONFIG_EXECUTABLE} ${_${_comp}_libs_flag} _val ) + if( _val ) + set( NetCDF_${_comp}_LIBRARIES ${_val} ) + if(NOT NetCDF_${_comp}_LIBRARY_SHARED AND NOT NetCDF_${_comp}_FOUND) #Static targets should use nc_config to get a proper link line with all necessary static targets. + list( APPEND NetCDF_LIBRARIES ${NetCDF_${_comp}_LIBRARIES} ) + endif() + else() + set( NetCDF_${_comp}_LIBRARIES ${NetCDF_${_comp}_LIBRARY} ) + if(NOT NetCDF_${_comp}_LIBRARY_SHARED) + message(SEND_ERROR "Unable to properly find NetCDF. Found static libraries at: ${NetCDF_${_comp}_LIBRARY} but could not run nc-config: ${NetCDF_CONFIG_EXECUTABLE}") + endif() + endif() + + #Use nc-config to set per-component INCLUDE_DIRS variable if possible + netcdf_config( ${NetCDF_${_comp}_CONFIG_EXECUTABLE} ${_${_comp}_includes_flag} _val ) + if( _val ) + string( REPLACE " " ";" _val ${_val} ) + set( NetCDF_${_comp}_INCLUDE_DIRS ${_val} ) + else() + set( NetCDF_${_comp}_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIR} ) + endif() + + if( NetCDF_${_comp}_LIBRARIES AND NetCDF_${_comp}_INCLUDE_DIRS ) + set( ${CMAKE_FIND_PACKAGE_NAME}_${_arg_${_COMP}}_FOUND TRUE ) + if (NOT TARGET NetCDF::NetCDF_${_comp}) + add_library(NetCDF::NetCDF_${_comp} ${_library_type} IMPORTED) + set_target_properties(NetCDF::NetCDF_${_comp} PROPERTIES + IMPORTED_LOCATION ${NetCDF_${_comp}_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_${_comp}_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES ${NetCDF_${_comp}_LIBRARIES} ) + endif() + endif() +endforeach() +set(NetCDF_LIBRARIES "${NetCDF_LIBRARIES}" CACHE STRING "NetCDF library targets" FORCE) + +## Find version via netcdf-config if possible +if (NetCDF_INCLUDE_DIRS) + if( NetCDF_C_CONFIG_EXECUTABLE ) + netcdf_config( ${NetCDF_C_CONFIG_EXECUTABLE} --version _vers ) + if( _vers ) + string(REGEX REPLACE ".* ((([0-9]+)\\.)+([0-9]+)).*" "\\1" NetCDF_VERSION "${_vers}" ) + endif() + else() + foreach( _dir IN LISTS NetCDF_INCLUDE_DIRS) + if( EXISTS "${_dir}/netcdf_meta.h" ) + file(STRINGS "${_dir}/netcdf_meta.h" _netcdf_version_lines + REGEX "#define[ \t]+NC_VERSION_(MAJOR|MINOR|PATCH|NOTE)") + string(REGEX REPLACE ".*NC_VERSION_MAJOR *\([0-9]*\).*" "\\1" _netcdf_version_major "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_MINOR *\([0-9]*\).*" "\\1" _netcdf_version_minor "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_PATCH *\([0-9]*\).*" "\\1" _netcdf_version_patch "${_netcdf_version_lines}") + string(REGEX REPLACE ".*NC_VERSION_NOTE *\"\([^\"]*\)\".*" "\\1" _netcdf_version_note "${_netcdf_version_lines}") + set(NetCDF_VERSION "${_netcdf_version_major}.${_netcdf_version_minor}.${_netcdf_version_patch}${_netcdf_version_note}") + unset(_netcdf_version_major) + unset(_netcdf_version_minor) + unset(_netcdf_version_patch) + unset(_netcdf_version_note) + unset(_netcdf_version_lines) + endif() + endforeach() + 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) + +if(NOT NetCDF_FOUND OR _new_search_components) + find_package_handle_standard_args( ${CMAKE_FIND_PACKAGE_NAME} + REQUIRED_VARS NetCDF_INCLUDE_DIRS NetCDF_LIBRARIES + VERSION_VAR NetCDF_VERSION + HANDLE_COMPONENTS ) +endif() + +foreach( _comp IN LISTS _search_components ) + if( NetCDF_${_comp}_FOUND ) + #Record found components to avoid duplication in NetCDF_LIBRARIES for static libraries + set(NetCDF_${_comp}_FOUND ${NetCDF_${_comp}_FOUND} CACHE BOOL "NetCDF ${_comp} Found" FORCE) + #Set a per-package, per-component found variable to communicate between multiple calls to find_package() + set(${PROJECT_NAME}_NetCDF_${_comp}_FOUND True) + endif() +endforeach() + +if( ${CMAKE_FIND_PACKAGE_NAME}_FOUND AND NOT ${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY AND _new_search_components) + message( STATUS "Find${CMAKE_FIND_PACKAGE_NAME} [${CMAKE_CURRENT_LIST_DIR}/FindNetCDF.cmake]:" ) + message( STATUS " - NetCDF_VERSION [${NetCDF_VERSION}]") + message( STATUS " - NetCDF_PARALLEL [${NetCDF_PARALLEL}]") + foreach( _comp IN LISTS _new_search_components ) + string( TOUPPER "${_comp}" _COMP ) + message( STATUS " - NetCDF_${_comp}_CONFIG_EXECUTABLE [${NetCDF_${_comp}_CONFIG_EXECUTABLE}]") + if( ${CMAKE_FIND_PACKAGE_NAME}_${_arg_${_COMP}}_FOUND ) + get_filename_component(_root ${NetCDF_${_comp}_INCLUDE_DIR}/.. ABSOLUTE) + if( NetCDF_${_comp}_LIBRARY_SHARED ) + message( STATUS " - NetCDF::NetCDF_${_comp} [SHARED] [Root: ${_root}] Lib: ${NetCDF_${_comp}_LIBRARY} ") + else() + message( STATUS " - NetCDF::NetCDF_${_comp} [STATIC] [Root: ${_root}] Lib: ${NetCDF_${_comp}_LIBRARY} ") + endif() + endif() + endforeach() +endif() + +foreach( _prefix NetCDF NetCDF4 NETCDF NETCDF4 ${CMAKE_FIND_PACKAGE_NAME} ) + set( ${_prefix}_INCLUDE_DIRS ${NetCDF_INCLUDE_DIRS} ) + set( ${_prefix}_LIBRARIES ${NetCDF_LIBRARIES}) + set( ${_prefix}_VERSION ${NetCDF_VERSION} ) + set( ${_prefix}_FOUND ${${CMAKE_FIND_PACKAGE_NAME}_FOUND} ) + set( ${_prefix}_CONFIG_EXECUTABLE ${NetCDF_CONFIG_EXECUTABLE} ) + set( ${_prefix}_PARALLEL ${NetCDF_PARALLEL} ) + + foreach( _comp ${_search_components} ) + string( TOUPPER "${_comp}" _COMP ) + set( _arg_comp ${_arg_${_COMP}} ) + set( ${_prefix}_${_comp}_FOUND ${${CMAKE_FIND_PACKAGE_NAME}_${_arg_comp}_FOUND} ) + set( ${_prefix}_${_COMP}_FOUND ${${CMAKE_FIND_PACKAGE_NAME}_${_arg_comp}_FOUND} ) + set( ${_prefix}_${_arg_comp}_FOUND ${${CMAKE_FIND_PACKAGE_NAME}_${_arg_comp}_FOUND} ) + + set( ${_prefix}_${_comp}_LIBRARIES ${NetCDF_${_comp}_LIBRARIES} ) + set( ${_prefix}_${_COMP}_LIBRARIES ${NetCDF_${_comp}_LIBRARIES} ) + set( ${_prefix}_${_arg_comp}_LIBRARIES ${NetCDF_${_comp}_LIBRARIES} ) + + set( ${_prefix}_${_comp}_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIRS} ) + set( ${_prefix}_${_COMP}_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIRS} ) + set( ${_prefix}_${_arg_comp}_INCLUDE_DIRS ${NetCDF_${_comp}_INCLUDE_DIRS} ) + endforeach() +endforeach() diff --git a/cmake/Modules/FindPIO.cmake b/cmake/Modules/FindPIO.cmake new file mode 100644 index 0000000000..4988264c46 --- /dev/null +++ b/cmake/Modules/FindPIO.cmake @@ -0,0 +1,181 @@ +# FindPIO.cmake +# +# Copyright UCAR 2020 +# +# Find PIO: A high-level Parallel I/O Library for structured grid applications +# https://github.com/NCAR/ParallelIO +# +# Components available for query: +# C - Has C support +# Fortran - Has Fortran support +# STATIC - Has static targets for supported LANG +# SHARED - Has shared targets for supported LANG +# +# Variables provided: +# PIO_FOUND - True if PIO was found +# PIO_VERSION - Version of installed PIO +# +# Targets provided: +# PIO::PIO_Fortran_STATIC - Fortran interface target for static libraries +# PIO::PIO_Fortran_SHARED - Fortran interface target for shared libraries +# PIO::PIO_Fortran - Fortran interface target alias to shared libraries if available else static libraries +# PIO::PIO_C_STATIC - C interface target for static libraries +# PIO::PIO_C_SHARED - C interface target for shared libraries +# PIO::PIO_C - C interface target alias to shared libraries if available else static libraries +# +# To control finding of this package, set PIO_ROOT environment variable to the full path to the prefix +# under which PIO was installed (e.g., /usr/local) +# + +## Find libraries and paths, and determine found components +find_path(PIO_INCLUDE_DIR NAMES pio.h HINTS "${PIO_PREFIX}" PATH_SUFFIXES include include/pio) +if(PIO_INCLUDE_DIR) + string(REGEX REPLACE "/include(/.+)?" "" PIO_PREFIX ${PIO_INCLUDE_DIR}) + set(PIO_PREFIX ${PIO_PREFIX} CACHE STRING "") + find_path(PIO_MODULE_DIR NAMES pio.mod PATHS "${PIO_PREFIX}" + PATH_SUFFIXES include include/pio lib/pio/module module module/pio NO_DEFAULT_PATH) + if(APPLE) + set(_SHARED_LIB_EXT .dylib) + else() + set(_SHARED_LIB_EXT .so) + endif() + find_library(PIO_C_STATIC_LIB libpioc.a PATHS "${PIO_PREFIX}" PATH_SUFFIXES lib lib64 NO_DEFAULT_PATH) + find_library(PIO_C_SHARED_LIB libpioc${_SHARED_LIB_EXT} PATHS "${PIO_PREFIX}" PATH_SUFFIXES lib lib64 NO_DEFAULT_PATH) + find_library(PIO_Fortran_STATIC_LIB libpiof.a PATHS "${PIO_PREFIX}" PATH_SUFFIXES lib lib64 NO_DEFAULT_PATH) + find_library(PIO_Fortran_SHARED_LIB libpiof${_SHARED_LIB_EXT} PATHS "${PIO_PREFIX}" PATH_SUFFIXES lib lib64 NO_DEFAULT_PATH) + unset(_SHARED_LIB_EXT) + + #Check for Fortran components + if(PIO_MODULE_DIR) + if(PIO_Fortran_STATIC_LIB) + set(PIO_Fortran_STATIC_FOUND 1) + endif() + if(PIO_Fortran_SHARED_LIB) + set(PIO_Fortran_SHARED_FOUND 1) + endif() + if(PIO_Fortran_STATIC_FOUND OR PIO_Fortran_SHARED_FOUND) + set(PIO_Fortran_FOUND 1) + endif() + endif() + #Check for C components + if(PIO_C_STATIC_LIB) + set(PIO_C_STATIC_FOUND 1) + endif() + if(PIO_C_SHARED_LIB) + set(PIO_C_SHARED_FOUND 1) + endif() + if(PIO_C_STATIC_FOUND OR PIO_C_SHARED_FOUND) + set(PIO_C_FOUND 1) + endif() + if(PIO_C_SHARED_FOUND AND (NOT PIO_Fortran_FOUND OR PIO_Fortran_SHARED_FOUND)) + set(PIO_SHARED_FOUND 1) + endif() + if(PIO_C_STATIC_FOUND AND (NOT PIO_Fortran_FOUND OR PIO_Fortran_STATIC_FOUND)) + set(PIO_STATIC_FOUND 1) + endif() +endif() + +## Debugging output +message(DEBUG "[FindPIO] PIO_INCLUDE_DIR: ${PIO_INCLUDE_DIR}") +message(DEBUG "[FindPIO] PIO_PREFIX: ${PIO_PREFIX}") +message(DEBUG "[FindPIO] PIO_MODULE_DIR: ${PIO_MODULE_DIR}") +message(DEBUG "[FindPIO] PIO_Fortran_STATIC_LIB: ${PIO_Fortran_STATIC_LIB}") +message(DEBUG "[FindPIO] PIO_Fortran_SHARED_LIB: ${PIO_Fortran_SHARED_LIB}") +message(DEBUG "[FindPIO] PIO_C_STATIC_LIB: ${PIO_C_STATIC_LIB}") +message(DEBUG "[FindPIO] PIO_C_SHARED_LIB: ${PIO_C_SHARED_LIB}") +message(DEBUG "[FindPIO] PIO_Fortran_FOUND: ${PIO_Fortran_FOUND}") +message(DEBUG "[FindPIO] PIO_C_FOUND: ${PIO_C_FOUND}") +message(DEBUG "[FindPIO] PIO_SHARED_FOUND: ${PIO_SHARED_FOUND}") +message(DEBUG "[FindPIO] PIO_STATIC_FOUND: ${PIO_STATIC_FOUND}") + +## Check package has been found correctly +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + PIO + REQUIRED_VARS + PIO_PREFIX + PIO_INCLUDE_DIR + HANDLE_COMPONENTS +) +message(DEBUG "[FindPIO] PIO_FOUND: ${PIO_FOUND}") + +## Create targets +set(_new_components) + + +# PIO::PIO_Fortran_STATIC imported interface target +if(PIO_Fortran_FOUND AND PIO_STATIC_FOUND AND NOT TARGET PIO::PIO_Fortran_STATIC) + add_library(PIO::PIO_Fortran_STATIC INTERFACE IMPORTED) + set_target_properties(PIO::PIO_Fortran_STATIC PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${PIO_INCLUDE_DIR} + INTERFACE_LINK_LIBRARIES ${PIO_Fortran_STATIC_LIB} + IMPORTED_GLOBAL True ) + if(PIO_MODULE_DIR AND NOT PIO_MODULE_DIR STREQUAL PIO_INCLUDE_DIR ) + set_property(TARGET PIO::PIO_Fortran_STATIC APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PIO_MODULE_DIR}) + endif() + target_link_libraries(PIO::PIO_Fortran_STATIC INTERFACE NetCDF::NetCDF_C) + set(_new_components 1) +endif() + +# PIO::PIO_Fortran_SHARED imported interface target +if(PIO_Fortran_FOUND AND PIO_SHARED_FOUND AND NOT TARGET PIO::PIO_Fortran_SHARED) + add_library(PIO::PIO_Fortran_SHARED INTERFACE IMPORTED) + set_target_properties(PIO::PIO_Fortran_SHARED PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${PIO_INCLUDE_DIR} + INTERFACE_LINK_LIBRARIES ${PIO_Fortran_SHARED_LIB} + IMPORTED_GLOBAL True ) + if(PIO_MODULE_DIR AND NOT PIO_MODULE_DIR STREQUAL PIO_INCLUDE_DIR ) + set_property(TARGET PIO::PIO_Fortran_SHARED APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PIO_MODULE_DIR}) + endif() + set(_new_components 1) +endif() + +# PIO::PIO_C_STATIC imported interface target +if(PIO_C_FOUND AND PIO_STATIC_FOUND AND NOT TARGET PIO::PIO_C_STATIC) + add_library(PIO::PIO_C_STATIC INTERFACE IMPORTED) + set_target_properties(PIO::PIO_C_STATIC PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${PIO_INCLUDE_DIR} + INTERFACE_LINK_LIBRARIES ${PIO_C_STATIC_LIB} + IMPORTED_GLOBAL True ) + target_link_libraries(PIO::PIO_C_STATIC INTERFACE NetCDF::NetCDF_C) + set(_new_components 1) +endif() + +# PIO::PIO_C_SHARED imported interface target +if(PIO_C_FOUND AND PIO_SHARED_FOUND AND NOT TARGET PIO::PIO_C_SHARED) + add_library(PIO::PIO_C_SHARED INTERFACE IMPORTED) + set_target_properties(PIO::PIO_C_SHARED PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${PIO_INCLUDE_DIR} + INTERFACE_LINK_LIBRARIES ${PIO_C_SHARED_LIB} + IMPORTED_GLOBAL True ) + set(_new_components 1) +endif() + +# PIO::PIO_Fortran - Shared libraries if available, static otherwise +if(TARGET PIO::PIO_Fortran_SHARED) + add_library(PIO::PIO_Fortran ALIAS PIO::PIO_Fortran_SHARED) +elseif(TARGET PIO::PIO_Fortran_STATIC) + add_library(PIO::PIO_Fortran ALIAS PIO::PIO_Fortran_STATIC) +endif() + +# PIO::PIO_C - Shared libraries if available, static otherwise +if(TARGET PIO::PIO_C_SHARED) + add_library(PIO::PIO_C ALIAS PIO::PIO_C_SHARED) +elseif(TARGET PIO::PIO_C_STATIC) + add_library(PIO::PIO_C ALIAS PIO::PIO_C_STATIC) +endif() + +## Print status +if(${CMAKE_FIND_PACKAGE_NAME}_FOUND AND NOT ${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY AND _new_components) + message( STATUS "Find${CMAKE_FIND_PACKAGE_NAME}:" ) + message( STATUS " - ${CMAKE_FIND_PACKAGE_NAME}_PREFIX [${${CMAKE_FIND_PACKAGE_NAME}_PREFIX}]") + set(_found_comps) + foreach( _comp IN ITEMS Fortran C STATIC SHARED ) + if( ${CMAKE_FIND_PACKAGE_NAME}_${_comp}_FOUND ) + list(APPEND _found_comps ${_comp}) + endif() + endforeach() + message( STATUS " - ${CMAKE_FIND_PACKAGE_NAME} Components Found: ${_found_comps}") + unset(_found_comps) +endif() +unset(_new_components) diff --git a/cmake/Modules/FindPnetCDF.cmake b/cmake/Modules/FindPnetCDF.cmake new file mode 100644 index 0000000000..91a076ba57 --- /dev/null +++ b/cmake/Modules/FindPnetCDF.cmake @@ -0,0 +1,174 @@ +# FindPnetCDF.cmake +# +# Copyright UCAR 2020 +# +# Find PnetCDF: A Parallel I/O Library for NetCDF File Access +# https://parallel-netcdf.github.io/ +# +# Components available for query: +# C - Has C support +# CXX - Has CXX support +# Fortran - Has Fortran support +# NetCDF4 - Has NetCDF4 output support +# GPTL - Has profiling support with GPTL enabled +# Threads - Has thread safety enabled +# +# Variables provided: +# PnetCDF_FOUND - True if PnetCDFL was found +# PnetCDF_CONFIG_EXE - pnetcdf-config executable if found +# PnetCDF_VERSION - Version of installed PnetCDF +# PnetCDF_BIN_DIR - PnetCDF binary directory +# PnetCDF_DEBUG - True if PnetCDF is built in debug mode +# +# Targets provided: +# PnetCDF::PnetCDF_Fortran - Fortran interface target +# PnetCDF::PnetCDF_C - C interface target +# PnetCDF::PnetCDF_CXX - CXX interface target +# +# Functions provided: +# pnetcdf_get_config(ret_var flags) - Call `pnetcdf-config` with flags and set ret_var with output on execution success. +# +# +# This module requires the `pnetcdf-config` executable to detect the directories and compiler and linker flags +# necessary for the PnetCDF::PnetCDF target. To control where PnetCDF is found: +# * Option 1: Set an environment or cmake variable `PnetCDF_ROOT` to the install prefix for PnetCDF (e.g. /usr/local) +# * Option 2: Set an environment or cmake variable `PnetCDF_CONFIG_EXE` to the full path to the `pnetcdf-config` +# (e.g., /usr/local/bin/pnetcdf-config) +# + +find_program(PnetCDF_CONFIG_EXE NAMES pnetcdf-config PATH_SUFFIXES bin bin64 PATHS + $ENV{PnetCDF_CONFIG_EXE} ${PnetCDF_ROOT} $ENV{PnetCDF_ROOT} ${PNETCDF_ROOT} $ENV{PNETCDF_ROOT}) +message(DEBUG "[FindPnetCDF] Using PnetCDF_CONFIG_EXE:${PnetCDF_CONFIG_EXE}") + +# pnetcdf_get_config(ret_var flags...) +# Get the output of pnetcdf-config +# Args: +# ret_var: return variable name +# flags: flags to pass to pnetcdf-config +function(pnetcdf_get_config ret_var pcflags) + execute_process(COMMAND ${PnetCDF_CONFIG_EXE} ${pcflags} OUTPUT_VARIABLE _out RESULT_VARIABLE _ret OUTPUT_STRIP_TRAILING_WHITESPACE) + if(_ret EQUAL 0) + separate_arguments(_out) + set(${ret_var} ${_out} PARENT_SCOPE) + else() + set(${ret_var} "" PARENT_SCOPE) + endif() +endfunction() + +## Find libraries and paths, and determine found components +if(EXISTS ${PnetCDF_CONFIG_EXE}) + #Use pnetcdf-config to find the prefix, flags, directories, executables, and libraries + pnetcdf_get_config(PnetCDF_VERSION --version) + string(REGEX MATCH "([0-9.]+)" PnetCDF_VERSION "${PnetCDF_VERSION}") #Match only version actual number + + pnetcdf_get_config(PnetCDF_PREFIX --prefix) + pnetcdf_get_config(PnetCDF_CXX_FOUND --has-c++) + pnetcdf_get_config(PnetCDF_Fortran_FOUND --has-fortran) + pnetcdf_get_config(PnetCDF_NetCDF4_FOUND --netcdf4) + pnetcdf_get_config(PnetCDF_GPTL_FOUND --profiling) + pnetcdf_get_config(PnetCDF_Threads_FOUND --thread-safe) + pnetcdf_get_config(PnetCDF_DEBUG --debug) + pnetcdf_get_config(PnetCDF_INCLUDE_DIR --includedir) + pnetcdf_get_config(PnetCDF_LIB_DIR --libdir) + + #Translate boolean variables from pnetcdf-config enabled/disabled to True/False + foreach(_var IN ITEMS PnetCDF_CXX_FOUND PnetCDF_Fortran_FOUND PnetCDF_NetCDF4_FOUND PnetCDF_GPTL_FOUND PnetCDF_Threads_FOUND PnetCDF_DEBUG) + if( ${_var} MATCHES "(enabled)|([Yy][Ee][Ss])") + set(${_var} True) + else() + set(${_var} False) + endif() + endforeach() + + find_path(PnetCDF_MODULE_DIR NAMES pnetcdf.mod HINTS ${PnetCDF_PREFIX} ${PnetCDF_INCLUDE_DIR} + PATH_SUFFIXES include include/pnetcdf module module/pnetcdf lib/pnetcdf/module NO_DEFAULT_PATH) + if(PnetCDF_Fortran_FOUND AND NOT EXISTS ${PnetCDF_MODULE_DIR}) + message(WARNING "[PnetCDF] pnetcdf-config --has-fortran=yes, but could not find pnetcdf.mod. Set PnetCDF_MODULE_DIR to path containing pnetcdf.mod") + set(PnetCDF_Fortran_FOUND NO) + endif() + + if(PnetCDF_INCLUDE_DIR AND PnetCDF_LIB_DIR) + set(PnetCDF_C_FOUND True) + endif() + + find_path(PnetCDF_BIN_DIR NAMES pnetcdf-config PATH_SUFFIXES bin PATHS ${PnetCDF_PREFIX} NO_DEFAULT_PATH) + find_library(PnetCDF_LIBRARY NAMES pnetcdf PATH_SUFFIXES lib lib64 PATHS ${PnetCDF_PREFIX} NO_DEFAULT_PATH) + #Hide non-documented cache variables reserved for internal/advanced usage + mark_as_advanced( PnetCDF_MODULE_DIR PnetCDF_LIBRARY ) +endif() + +## Debugging output +message(DEBUG "[FindPnetCDF] PnetCDF_CONFIG_EXE: ${PnetCDF_CONFIG_EXE}") +message(DEBUG "[FindPnetCDF] PnetCDF_VERSION: ${PnetCDF_VERSION}") +message(DEBUG "[FindPnetCDF] PnetCDF_C_FOUND: ${PnetCDF_C_FOUND}") +message(DEBUG "[FindPnetCDF] PnetCDF_CXX_FOUND: ${PnetCDF_CXX_FOUND}") +message(DEBUG "[FindPnetCDF] PnetCDF_Fortran_FOUND: ${PnetCDF_Fortran_FOUND}") +message(DEBUG "[FindPnetCDF] PnetCDF_NetCDF4_FOUND: ${PnetCDF_NetCDF4_FOUND}") +message(DEBUG "[FindPnetCDF] PnetCDF_GPTL_FOUND: ${PnetCDF_GPTL_FOUND}") +message(DEBUG "[FindPnetCDF] PnetCDF_Threads_FOUND: ${PnetCDF_Threads_FOUND}") +message(DEBUG "[FindPnetCDF] PnetCDF_DEBUG: ${PnetCDF_DEBUG}") +message(DEBUG "[FindPnetCDF] PnetCDF_PREFIX: ${PnetCDF_PREFIX}") +message(DEBUG "[FindPnetCDF] PnetCDF_BIN_DIR: ${PnetCDF_BIN_DIR}") +message(DEBUG "[FindPnetCDF] PnetCDF_INCLUDE_DIR: ${PnetCDF_INCLUDE_DIR}") +message(DEBUG "[FindPnetCDF] PnetCDF_MODULE_DIR: ${PnetCDF_MODULE_DIR}") +message(DEBUG "[FindPnetCDF] PnetCDF_LIB_DIR: ${PnetCDF_LIB_DIR}") + +## Check package has been found correctly +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + PnetCDF + REQUIRED_VARS + PnetCDF_CONFIG_EXE + PnetCDF_PREFIX + VERSION_VAR + PnetCDF_VERSION + HANDLE_COMPONENTS +) +message(DEBUG "[FindPnetCDF] PnetCDF_FOUND: ${PnetCDF_FOUND}") + +## Create targets +set(_new_components) + +# PnetCDF::PnetCDF_Fortran imported interface target +if(PnetCDF_Fortran_FOUND AND NOT TARGET PnetCDF::PnetCDF_Fortran) + add_library(PnetCDF::PnetCDF_Fortran INTERFACE IMPORTED) + set_target_properties(PnetCDF::PnetCDF_Fortran PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${PnetCDF_INCLUDE_DIR} + INTERFACE_LINK_DIRECTORIES ${PnetCDF_LIB_DIR}) + if(PnetCDF_MODULE_DIR AND NOT PnetCDF_MODULE_DIR STREQUAL PnetCDF_INCLUDE_DIR ) + set_property(TARGET PnetCDF::PnetCDF_Fortran APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${PnetCDF_MODULE_DIR}) + endif() + set(_new_components 1) + target_link_libraries(PnetCDF::PnetCDF_Fortran INTERFACE -lpnetcdf) +endif() + +# PnetCDF::PnetCDF_C imported interface target +if(PnetCDF_C_FOUND AND NOT TARGET PnetCDF::PnetCDF_C) + add_library(PnetCDF::PnetCDF_C INTERFACE IMPORTED) + set_target_properties(PnetCDF::PnetCDF_C PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${PnetCDF_INCLUDE_DIR} + INTERFACE_LINK_DIRECTORIES ${PnetCDF_LIB_DIR}) + set(_new_components 1) +endif() + +# PnetCDF::PnetCDF_CXX imported interface target +if(PnetCDF_CXX_FOUND AND NOT TARGET PnetCDF::PnetCDF_CXX) + add_library(PnetCDF::PnetCDF_CXX INTERFACE IMPORTED) + set_target_properties(PnetCDF::PnetCDF_CXX PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${PnetCDF_INCLUDE_DIR} + INTERFACE_LINK_DIRECTORIES ${PnetCDF_LIB_DIR}) + set(_new_components 1) +endif() + +## Print status +if(${CMAKE_FIND_PACKAGE_NAME}_FOUND AND NOT ${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY AND _new_components) + message( STATUS "Find${CMAKE_FIND_PACKAGE_NAME}:" ) + message( STATUS " - ${CMAKE_FIND_PACKAGE_NAME}_VERSION [${${CMAKE_FIND_PACKAGE_NAME}_VERSION}]") + message( STATUS " - ${CMAKE_FIND_PACKAGE_NAME}_PREFIX [${${CMAKE_FIND_PACKAGE_NAME}_PREFIX}]") + set(_found_comps) + foreach( _comp IN ITEMS Fortran C CXX NetCDF4 GPTL Threads ) + if( ${CMAKE_FIND_PACKAGE_NAME}_${_comp}_FOUND ) + list(APPEND _found_comps ${_comp}) + endif() + endforeach() + message( STATUS " - ${CMAKE_FIND_PACKAGE_NAME} Components Found: ${_found_comps}") + unset(_found_comps) +endif() +unset(_new_components) diff --git a/cmake/PackageConfig.cmake.in b/cmake/PackageConfig.cmake.in new file mode 100644 index 0000000000..e48a2b9f67 --- /dev/null +++ b/cmake/PackageConfig.cmake.in @@ -0,0 +1,115 @@ +@PACKAGE_INIT@ + +# @PROJECT_NAME@-config.cmake +# +# Valid Find COMPONENTS: +# * SHARED - Require shared libraries. +# * STATIC - Require static libraries. +# * DOUBLE_PRECISION - Find double precision libraries +# * PROFILE - True if GPTL profiling is enabled +# * OpenMP - True if OpenMP support is enabled +# * core_atmosphere - Find atmosphere core +# * core_init_atmosphere - Find init_atmosphere core +# * core_ocean - Find ocean core +# * core_landice - Find landice core +# * core_seaice - Find seaice core +# * core_sw - Find sw core +# * core_test - Find test core +# +# +# Output variables set: +# * @PROJECT_NAME@_VERSION - Version of install package +# * @PROJECT_NAME@_MODULES_Fortran_COMPILER_ID - Compiler used to generate Fortran Modules +# * @PROJECT_NAME@_MODULES_Fortran_COMPILER_VERSION - Compiler version used to generate Fortran Modules +# * @PROJECT_NAME@_CORE__DATADIR - Location for data files for core (namelist, streams, data tables, etc.) +# * @PROJECT_NAME@_BINDIR - Location for installed auxiliary binaries. +# + +# Imported interface targets provided: +# * @PROJECT_NAME@::core:: - Core targets +# * @PROJECT_NAME@::operators - Operators library target +# * @PROJECT_NAME@::framework - Framework library target +# * @PROJECT_NAME@::external::esmf - exmf_time library target +# * @PROJECT_NAME@::external::ezxml - ezxml library target +# + +# * @PROJECT_NAME@::@PROJECT_NAME@_shared - shared library target: + +#Include targets file. This will create IMPORTED target @PROJECT_NAME@ +string(TOLOWER @PROJECT_NAME@ _project_name_lower) +if(NOT TARGET @PROJECT_NAME@::framework) + include("${CMAKE_CURRENT_LIST_DIR}/${_project_name_lower}-targets-external.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/${_project_name_lower}-targets.cmake") + include("${CMAKE_CURRENT_LIST_DIR}/${_project_name_lower}-targets-core.cmake") +endif() + +set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@) + +#Export Fortran compiler version and check module compatibility +set(@PROJECT_NAME@_MODULES_Fortran_COMPILER_ID @CMAKE_Fortran_COMPILER_ID@) +set(@PROJECT_NAME@_MODULES_Fortran_COMPILER_VERSION @CMAKE_Fortran_COMPILER_VERSION@) +if(NOT @PROJECT_NAME@_MODULES_Fortran_COMPILER_ID STREQUAL CMAKE_Fortran_COMPILER_ID + OR NOT @PROJECT_NAME@_MODULES_Fortran_COMPILER_VERSION VERSION_EQUAL CMAKE_Fortran_COMPILER_VERSION) + message(SEND_ERROR "Package @PROJECT_NAME@ provides Fortran modules built with " + "${@PROJECT_NAME@_MODULES_Fortran_COMPILER_ID}-${@PROJECT_NAME@_MODULES_Fortran_COMPILER_VERSION} " + "but this build for ${PROJECT_NAME} uses incompatible compiler ${CMAKE_Fortran_COMPILER_ID}-${CMAKE_Fortran_COMPILER_VERSION}") +endif() + +set_and_check(@PROJECT_NAME@_BINDIR @PACKAGE_BINDIR@) +set_and_check(@PROJECT_NAME@_CMAKE_MODULE_PATH @PACKAGE_CMAKE_MODULE_INSTALL_PATH@) +set(CMAKE_MODULE_PATH ${@PROJECT_NAME@_CMAKE_MODULE_PATH} ${CMAKE_MODULE_PATH}) + +include(CMakeFindDependencyMacro) +if(@OpenMP_Fortran_FOUND@) #OpenMP_Fortran_FOUND + if(NOT OpenMP_Fortran_FOUND) + find_package(OpenMP REQUIRED COMPONENTS Fortran) + endif() + set(@PROJECT_NAME@_OpenMP_FOUND True) +endif() +if(NOT MPI_Fortran_FOUND) + find_package(MPI REQUIRED COMPONENTS Fortran) +endif() +if(NOT NetCDF_Fortran_FOUND) + find_package(NetCDF REQUIRED COMPONENTS Fortran) +endif() +find_package(PnetCDF REQUIRED COMPONENTS Fortran) +find_package(PIO REQUIRED COMPONENTS Fortran C) +if(@MPAS_PROFILE@) #MPAS_PROFILE + if(NOT GPTL_FOUND) + find_dependency(GPTL REQUIRED) + endif() + set(@PROJECT_NAME@_PROFILE_FOUND) +endif() + +if(@BUILD_SHARED_LIBS@) #BUILD_SHARED_LIBS + set(@PROJECT_NAME@_SHARED_FOUND True) +else() + set(@PROJECT_NAME@_STATIC_FOUND True) +endif() +if(@MPAS_DOUBLE_PRECISION@) #MPAS_DOUBLE_PRECISION + set(@PROJECT_NAME@_DOUBLE_PRECISION_FOUND True) +endif() +set(MPAS_CORES @MPAS_CORES@) +foreach(_core IN LISTS MPAS_CORES) + string(TOUPPER ${_core} _CORE) + set_and_check(@PROJECT_NAME@_CORE_${_CORE}_DATADIR @PACKAGE_CORE_DATADIR_ROOT@/core_${_core}) + set(@PROJECT_NAME@_core_${_core}_FOUND True) +endforeach() + +check_required_components("@PROJECT_NAME@") + +## Print status +if(NOT @PROJECT_NAME@_FIND_QUIETLY) + #Get list of all found components for printing + set(_found_components) + set(_all_components SHARED STATIC PROFILE OpenMP DOUBLE_PRECISION core_atmosphere core_init_atmosphere core_landice core_ocean core_sw core_test) + foreach(_cmp IN LISTS _all_components) + if(@PROJECT_NAME@_${_cmp}_FOUND) + list(APPEND _found_components ${_cmp}) + endif() + endforeach() + + message(STATUS "Found @PROJECT_NAME@: (version: \"@PROJECT_VERSION@\") (components: ${_found_components})") + unset(_found_components) + unset(_all_components) +endif() diff --git a/src/core_atmosphere/CMakeLists.txt b/src/core_atmosphere/CMakeLists.txt new file mode 100644 index 0000000000..8dc94c4192 --- /dev/null +++ b/src/core_atmosphere/CMakeLists.txt @@ -0,0 +1,159 @@ + +## Source files +# physics/ +set(_atm_core_physics_srcs + mpas_atmphys_camrad_init.F + mpas_atmphys_constants.F + mpas_atmphys_control.F + mpas_atmphys_date_time.F + mpas_atmphys_driver.F + mpas_atmphys_driver_cloudiness.F + mpas_atmphys_driver_convection.F + mpas_atmphys_driver_gwdo.F + mpas_atmphys_driver_lsm.F + mpas_atmphys_driver_microphysics.F + mpas_atmphys_driver_oml.F + mpas_atmphys_driver_pbl.F + mpas_atmphys_driver_radiation_lw.F + mpas_atmphys_driver_radiation_sw.F + mpas_atmphys_driver_sfclayer.F + mpas_atmphys_finalize.F + mpas_atmphys_functions.F + mpas_atmphys_init.F + mpas_atmphys_init_microphysics.F + mpas_atmphys_interface.F + mpas_atmphys_landuse.F + mpas_atmphys_lsm_noahinit.F + mpas_atmphys_manager.F + mpas_atmphys_o3climatology.F + mpas_atmphys_packages.F + mpas_atmphys_rrtmg_lwinit.F + mpas_atmphys_rrtmg_swinit.F + mpas_atmphys_todynamics.F + mpas_atmphys_update.F + mpas_atmphys_update_surface.F + mpas_atmphys_utilities.F + mpas_atmphys_vars.F) +list(TRANSFORM _atm_core_physics_srcs PREPEND physics/) + +## Unused +# physics/physics_wrf/ +set(_atm_core_physics_wrf_srcs + libmassv.F + module_bl_gwdo.F + module_bl_mynn.F + module_bl_ysu.F + module_cam_error_function.F + module_cam_shr_kind_mod.F + module_cam_support.F + module_cu_gf.mpas.F + module_cu_kfeta.F + module_cu_ntiedtke.F + module_cu_tiedtke.F + module_mp_kessler.F + module_mp_radar.F + module_mp_thompson.F + module_mp_thompson_cldfra3.F + module_mp_wsm6.F + module_ra_cam.F + module_ra_cam_support.F + module_ra_rrtmg_lw.F + module_ra_rrtmg_sw.F + module_ra_rrtmg_vinterp.F + module_sf_bem.F + module_sf_bep.F + module_sf_bep_bem.F + module_sf_mynn.F + module_sf_noah_seaice.F + module_sf_noah_seaice_drv.F + module_sf_noahdrv.F + module_sf_noahlsm.F + module_sf_noahlsm_glacial_only.F + module_sf_oml.F + module_sf_sfcdiags.F + module_sf_sfclay.F + module_sf_urban.F) +list(TRANSFORM _atm_core_physics_wrf_srcs PREPEND physics/physics_wrf/) + +# diagnostics/ +set(_atm_core_diagnostics_srcs + convective_diagnostics.F + isobaric_diagnostics.F + mpas_atm_diagnostic_template.F + mpas_atm_diagnostics_manager.F + mpas_atm_diagnostics_utils.F + pv_diagnostics.F + soundings.F) +list(TRANSFORM _atm_core_diagnostics_srcs PREPEND diagnostics/) + +# dynamics/ +set(_atm_core_dynamics_srcs + mpas_atm_boundaries.F + mpas_atm_iau.F + mpas_atm_time_integration.F) +list(TRANSFORM _atm_core_dynamics_srcs PREPEND dynamics/) + +# utils/ +set(_atm_core_utils_srcs + atmphys_build_tables_thompson.F + build_tables.F) +list(TRANSFORM _atm_core_utils_srcs PREPEND utils/) + +# core_atosphere +set(_atm_core_srcs + mpas_atm_core.F + mpas_atm_core_interface.F + mpas_atm_dimensions.F + mpas_atm_threading.F) + +## Generated includes +set(atm_core_inc + block_dimension_routines.inc + core_variables.inc + define_packages.inc + domain_variables.inc + namelist_call.inc + namelist_defines.inc + setup_immutable_streams.inc + structs_and_variables.inc) + + +add_library(core_atmosphere ${_atm_core_srcs} + ${_atm_core_physics_srcs} + ${_atm_core_physics_wrf_srcs} + ${_atm_core_diagnostics_srcs} + ${_atm_core_dynamics_srcs}) + +mpas_core_target(CORE atmosphere TARGET core_atmosphere INCLUDES ${atm_core_inc}) + +target_compile_definitions(core_atmosphere PRIVATE DO_PHYSICS=1) +target_compile_definitions(core_atmosphere PRIVATE mpas=1) + +#Get physics_wrf tables from MPAS-Data +include(FetchContent) +if(${PROJECT_VERSION} VERSION_GREATER_EQUAL 7.0) + set(MPAS_DATA_GIT_TAG v${PROJECT_VERSION}) +else() + set(MPAS_DATA_GIT_TAG master) +endif() + +FetchContent_Declare(mpas_data + GIT_REPOSITORY https://github.com/MPAS-Dev/MPAS-Data.git + GIT_TAG ${MPAS_DATA_GIT_TAG} + GIT_PROGRESS True + GIT_SHALLOW True) +FetchContent_Populate(mpas_data) +set(_physics_wrf_datadir ${mpas_data_SOURCE_DIR}/atmosphere/physics_wrf/files) +file(GLOB _physics_wrf_data RELATIVE ${_physics_wrf_datadir} "${_physics_wrf_datadir}/*") +file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${PROJECT_NAME}/core_atmosphere) +foreach(_datafile IN LISTS _physics_wrf_data) + execute_process( COMMAND ${CMAKE_COMMAND} -E create_symlink ${_physics_wrf_datadir}/${_datafile} + ${CMAKE_BINARY_DIR}/${PROJECT_NAME}/core_atmosphere/${_datafile}) +endforeach() +install(DIRECTORY ${_physics_wrf_datadir}/ DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROJECT_NAME}/core_atmosphere) + +add_executable(mpas_atmosphere_build_tables ${_atm_core_utils_srcs}) +target_link_libraries(mpas_atmosphere_build_tables PUBLIC core_atmosphere) +mpas_fortran_target(mpas_atmosphere_build_tables) +install(TARGETS mpas_atmosphere_build_tables EXPORT ${PROJECT_NAME}ExportsCore + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/core_atmosphere/Registry.xml b/src/core_atmosphere/Registry.xml index e57e37e3cc..ef7192f2d2 100644 --- a/src/core_atmosphere/Registry.xml +++ b/src/core_atmosphere/Registry.xml @@ -395,9 +395,10 @@ - @@ -467,29 +468,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + - - - - - - + + + + + + + + + + @@ -506,19 +547,11 @@ + + - - - - - - - - - - @@ -1117,6 +1150,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1565,6 +1665,14 @@ + + + + diff --git a/src/core_atmosphere/diagnostics/Registry_convective.xml b/src/core_atmosphere/diagnostics/Registry_convective.xml index 59ad1c2f58..0f12102927 100644 --- a/src/core_atmosphere/diagnostics/Registry_convective.xml +++ b/src/core_atmosphere/diagnostics/Registry_convective.xml @@ -55,5 +55,17 @@ + + + + + + + + diff --git a/src/core_atmosphere/diagnostics/convective_diagnostics.F b/src/core_atmosphere/diagnostics/convective_diagnostics.F index 9554113e4e..16b8b5d578 100644 --- a/src/core_atmosphere/diagnostics/convective_diagnostics.F +++ b/src/core_atmosphere/diagnostics/convective_diagnostics.F @@ -14,6 +14,7 @@ module convective_diagnostics type (MPAS_pool_type), pointer :: mesh type (MPAS_pool_type), pointer :: state type (MPAS_pool_type), pointer :: diag + type (MPAS_pool_type), pointer :: diag_physics type (MPAS_clock_type), pointer :: clock @@ -34,6 +35,12 @@ module convective_diagnostics logical :: is_needed_w_max logical :: is_needed_lml_wsp_max + ! options for UKMO total cloud cover (subroutine r2_calc_total_cloud_cover) + integer, parameter :: ip_cloud_mix_max = 1 + integer, parameter :: ip_cloud_mix_random = 2 + integer, parameter :: ip_cloud_column_max = 3 + integer, parameter :: ip_cloud_triple = 4 + integer, parameter :: ip_cloud_clear = 5 contains @@ -65,6 +72,7 @@ subroutine convective_diagnostics_setup(all_pools, simulation_clock) call mpas_pool_get_subpool(all_pools, 'mesh', mesh) call mpas_pool_get_subpool(all_pools, 'state', state) call mpas_pool_get_subpool(all_pools, 'diag', diag) + call mpas_pool_get_subpool(all_pools, 'diag_physics', diag_physics) clock => simulation_clock @@ -250,6 +258,10 @@ subroutine convective_diagnostics_compute() real (kind=RKIND), dimension(:), pointer :: umeridional_6km real (kind=RKIND), dimension(:), pointer :: temperature_surface real (kind=RKIND), dimension(:), pointer :: dewpoint_surface + real (kind=RKIND), dimension(:), pointer :: cldfrac_low_UPP + real (kind=RKIND), dimension(:), pointer :: cldfrac_mid_UPP + real (kind=RKIND), dimension(:), pointer :: cldfrac_high_UPP + real (kind=RKIND), dimension(:), pointer :: cldfrac_tot_UPP ! Other fields used in the computation of convective diagnostics ! defined above @@ -263,6 +275,7 @@ subroutine convective_diagnostics_compute() real (kind=RKIND), dimension(:,:), pointer :: pressure_base real (kind=RKIND), dimension(:,:,:), pointer :: scalars integer, pointer :: index_qv + real (kind=RKIND), dimension(:,:), pointer :: cldfrac real (kind=RKIND), parameter :: dev_motion = 7.5, z_bunker_bot = 0., z_bunker_top = 6000. real (kind=RKIND) :: u_storm, v_storm, u_srh_bot, v_srh_bot, u_srh_top, v_srh_top @@ -276,8 +289,19 @@ subroutine convective_diagnostics_compute() real (kind=RKIND) :: evp + ! levels for low/mid/high cloud fraction - UPP method + real (kind=RKIND), parameter :: ptop_low = 64200.0, ptop_mid = 35000.0, ptop_high = 15000.0 + + ! levels for low/mid/high cloud fraction - UKMO method + real (kind=RKIND), parameter :: ptop_low_ = 80000.0, ptop_mid_ = 50000.0, ptop_high_ = 15000.0 + real (kind=RKIND), parameter :: thresh_cld = 0.0627 + real (kind=RKIND), parameter :: msgval = -999.0 + + real (kind=RKIND), dimension(:,:), allocatable :: cldfrac2 + logical :: need_cape, need_cin, need_lcl, need_lfc, need_srh_01km, need_srh_03km, need_uzonal_sfc, need_uzonal_1km, & need_uzonal_6km, need_umerid_sfc, need_umerid_1km, need_umerid_6km, need_tsfc, need_tdsfc + logical :: need_cldfrac_UPP logical :: need_any_diags need_any_diags = .false. @@ -310,6 +334,11 @@ subroutine convective_diagnostics_compute() need_any_diags = need_any_diags .or. need_tsfc need_tdsfc = MPAS_field_will_be_written('dewpoint_surface') need_any_diags = need_any_diags .or. need_tdsfc + need_cldfrac_UPP = MPAS_field_will_be_written('cldfrac_low_UPP') + need_cldfrac_UPP = MPAS_field_will_be_written('cldfrac_mid_UPP') .or. need_cldfrac_UPP + need_cldfrac_UPP = MPAS_field_will_be_written('cldfrac_high_UPP') .or. need_cldfrac_UPP + need_cldfrac_UPP = MPAS_field_will_be_written('cldfrac_tot_UPP') .or. need_cldfrac_UPP + need_any_diags = need_any_diags .or. need_cldfrac_UPP if (need_any_diags) then @@ -332,6 +361,12 @@ subroutine convective_diagnostics_compute() call mpas_pool_get_array(diag, 'umeridional_6km', umeridional_6km) call mpas_pool_get_array(diag, 'temperature_surface', temperature_surface) call mpas_pool_get_array(diag, 'dewpoint_surface', dewpoint_surface) + if ( need_cldfrac_UPP ) then + call mpas_pool_get_array(diag, 'cldfrac_low_UPP', cldfrac_low_UPP) + call mpas_pool_get_array(diag, 'cldfrac_mid_UPP', cldfrac_mid_UPP) + call mpas_pool_get_array(diag, 'cldfrac_high_UPP', cldfrac_high_UPP) + call mpas_pool_get_array(diag, 'cldfrac_tot_UPP', cldfrac_tot_UPP) + end if call mpas_pool_get_array(mesh, 'zgrid', height) call mpas_pool_get_array(diag, 'uReconstructMeridional', umeridional) @@ -342,6 +377,15 @@ subroutine convective_diagnostics_compute() call mpas_pool_get_array(diag, 'relhum', relhum) call mpas_pool_get_array(diag, 'pressure_base', pressure_base) call mpas_pool_get_array(diag, 'pressure_p', pressure_p) + if ( need_cldfrac_UPP) then + call mpas_pool_get_array(diag_physics, 'cldfrac', cldfrac) + ! do we impose 0.0/1.0 limit to cldfrac here? + do iCell = 1, nCells + do k = 1, nVertLevels + cldfrac(k,iCell) = max(min(cldfrac(k,iCell),1.0),0.0) + end do + end do + end if call mpas_pool_get_dimension(state, 'index_qv', index_qv) @@ -471,6 +515,26 @@ subroutine convective_diagnostics_compute() end do end if + if ( need_cldfrac_UPP ) then + do iCell = 1, nCellsSolve + cldfrac_low_UPP (iCell) = 0.0 + cldfrac_mid_UPP (iCell) = 0.0 + cldfrac_high_UPP(iCell) = 0.0 + cldfrac_tot_UPP (iCell) = 0.0 + p_in(1:nVertLevels) = pressure_p(1:nVertLevels,iCell) + pressure_base(1:nVertLevels,iCell) + do k = 1, nVertLevels + if ( p_in(k) >= ptop_low ) then + cldfrac_low_UPP(iCell) = max(cldfrac_low_UPP(iCell), cldfrac(k,iCell)) + else if ( p_in(k) < ptop_low .and. p_in(k) >= ptop_mid ) then + cldfrac_mid_UPP(iCell) = max(cldfrac_mid_UPP(iCell), cldfrac(k,iCell)) + else if ( p_in(k) < ptop_mid .and. p_in(k) >= ptop_high ) then + cldfrac_high_UPP(iCell) = max(cldfrac_high_UPP(iCell), cldfrac(k,iCell)) + end if + cldfrac_tot_UPP(iCell) = max(cldfrac_tot_UPP(iCell), cldfrac(k,iCell)) + end do + end do + end if + deallocate(temperature) deallocate(dewpoint) @@ -1093,7 +1157,5 @@ real (kind=RKIND) function getthe(p,t,td,q) end function getthe !----------------------------------------------------------------------- -!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc -!----------------------------------------------------------------------- end module convective_diagnostics diff --git a/src/core_atmosphere/mpas_atm_core.F b/src/core_atmosphere/mpas_atm_core.F index b7f79d8484..b5a4639da9 100644 --- a/src/core_atmosphere/mpas_atm_core.F +++ b/src/core_atmosphere/mpas_atm_core.F @@ -91,13 +91,16 @@ function atm_core_init(domain, startTimeStamp) result(ierr) if (config_do_restart) then call MPAS_stream_mgr_read(domain % streamManager, streamID='restart', ierr=ierr) else + call MPAS_stream_mgr_read(domain % streamManager, streamID='static', whence=MPAS_STREAM_NEAREST, ierr=ierr) call MPAS_stream_mgr_read(domain % streamManager, streamID='input', ierr=ierr) end if + if (ierr /= MPAS_STREAM_MGR_NOERR) then call mpas_log_write('********************************************************************************', messageType=MPAS_LOG_ERR) call mpas_log_write('Error reading initial conditions', messageType=MPAS_LOG_ERR) call mpas_log_write('********************************************************************************', messageType=MPAS_LOG_CRIT) end if + call MPAS_stream_mgr_reset_alarms(domain % streamManager, streamID='static', direction=MPAS_STREAM_INPUT, ierr=ierr) call MPAS_stream_mgr_reset_alarms(domain % streamManager, streamID='input', direction=MPAS_STREAM_INPUT, ierr=ierr) call MPAS_stream_mgr_reset_alarms(domain % streamManager, streamID='restart', direction=MPAS_STREAM_INPUT, ierr=ierr) @@ -287,6 +290,7 @@ subroutine atm_mpas_init_block(dminfo, stream_manager, block, mesh, dt) real (kind=RKIND), dimension(:,:), pointer :: u, uReconstructX, uReconstructY, uReconstructZ, uReconstructZonal, uReconstructMeridional real (kind=RKIND), dimension(:), pointer :: meshScalingDel2, meshScalingDel4 + real (kind=RKIND), dimension(:), pointer :: meshScalingRegionalCell, meshScalingRegionalEdge real (kind=RKIND), dimension(:), pointer :: areaCell, invAreaCell real (kind=RKIND), dimension(:), pointer :: dvEdge, invDvEdge real (kind=RKIND), dimension(:), pointer :: dcEdge, invDcEdge diff --git a/src/core_atmosphere/mpas_atm_core_interface.F b/src/core_atmosphere/mpas_atm_core_interface.F index 437502430e..c17a272b15 100644 --- a/src/core_atmosphere/mpas_atm_core_interface.F +++ b/src/core_atmosphere/mpas_atm_core_interface.F @@ -314,7 +314,7 @@ function atm_get_mesh_stream(configs, stream) result(ierr) else if (config_do_restart) then write(stream,'(a)') 'restart' else - write(stream,'(a)') 'input' + write(stream,'(a)') 'static' end if end function atm_get_mesh_stream diff --git a/src/core_atmosphere/physics/mpas_atmphys_landuse.F b/src/core_atmosphere/physics/mpas_atmphys_landuse.F index 779b85a4f9..309e79c289 100644 --- a/src/core_atmosphere/physics/mpas_atmphys_landuse.F +++ b/src/core_atmosphere/physics/mpas_atmphys_landuse.F @@ -95,7 +95,7 @@ subroutine landuse_init_forMPAS(dminfo,julday,mesh,configs,diag_physics,sfc_inpu integer,intent(in):: julday !local pointers: - logical,pointer:: config_do_restart, & + logical,pointer:: config_do_restart, config_do_DAcycling, & config_frac_seaice, & config_sfc_albedo @@ -133,6 +133,7 @@ subroutine landuse_init_forMPAS(dminfo,julday,mesh,configs,diag_physics,sfc_inpu !call mpas_log_write('--- enter subroutine landuse_init_forMPAS:') call mpas_pool_get_config(configs,'config_do_restart' ,config_do_restart ) + call mpas_pool_get_config(configs,'config_do_DAcycling' ,config_do_DAcycling ) call mpas_pool_get_config(configs,'config_frac_seaice',config_frac_seaice) call mpas_pool_get_config(configs,'config_sfc_albedo' ,config_sfc_albedo ) @@ -252,8 +253,9 @@ subroutine landuse_init_forMPAS(dminfo,julday,mesh,configs,diag_physics,sfc_inpu !call mpas_log_write('--- isice =$i',intArgs=(/isice/)) !call mpas_log_write('--- iswater =$i',intArgs=(/iswater/)) !call mpas_log_write('--- isurban =$i',intArgs=(/isurban/)) - if(config_do_restart) then + if(config_do_restart .or. config_do_DAcycling) then call mpas_log_write('--- config_do_restart =$l', logicArgs=(/config_do_restart/)) + call mpas_log_write('--- config_do_DAcycling =$l', logicArgs=(/config_do_DAcycling/)) call mpas_log_write('--- skip the end of landuse_init_forMPAS') return endif diff --git a/src/core_atmosphere/physics/physics_wrf/module_mp_thompson.F b/src/core_atmosphere/physics/physics_wrf/module_mp_thompson.F index a2d28456b7..66acfe688a 100644 --- a/src/core_atmosphere/physics/physics_wrf/module_mp_thompson.F +++ b/src/core_atmosphere/physics/physics_wrf/module_mp_thompson.F @@ -411,6 +411,7 @@ MODULE module_mp_thompson !================================================================================================================= subroutine thompson_init(l_mp_tables) + use mpas_io_units, only : mpas_new_unit, mpas_release_unit implicit none !================================================================================================================= @@ -421,6 +422,7 @@ subroutine thompson_init(l_mp_tables) integer:: i,j,k,l,m,n integer:: istat logical:: micro_init + integer:: mp_unit !..Allocate space for lookup tables (J. Michalakes 2009Jun08). micro_init = .FALSE. @@ -833,18 +835,19 @@ subroutine thompson_init(l_mp_tables) call table_dropEvap !..Rain collecting graupel & graupel collecting rain. - open(unit=11,file='MP_THOMPSON_QRacrQG_DATA.DBL',form='UNFORMATTED',status='OLD',action='READ', & + call mpas_new_unit(mp_unit, unformatted = .true.) + open(unit=mp_unit,file='MP_THOMPSON_QRacrQG_DATA.DBL',form='UNFORMATTED',status='OLD',action='READ', & iostat = istat) if(istat /= open_OK) & call physics_error_fatal('subroutine thompson_init: ' // & 'failure opening MP_THOMPSON_QRacrQG.DBL') - read(11) tcg_racg - read(11) tmr_racg - read(11) tcr_gacr - read(11) tmg_gacr - read(11) tnr_racg - read(11) tnr_gacr - close(unit=11) + read(mp_unit) tcg_racg + read(mp_unit) tmr_racg + read(mp_unit) tcr_gacr + read(mp_unit) tmg_gacr + read(mp_unit) tnr_racg + read(mp_unit) tnr_gacr + close(unit=mp_unit) ! write(0,*) '--- end read MP_THOMPSON_QRacrQG.DBL' ! write(0,*) 'max tcg_racg =',maxval(tcg_racg) ! write(0,*) 'min tcg_racg =',minval(tcg_racg) @@ -860,24 +863,24 @@ subroutine thompson_init(l_mp_tables) ! write(0,*) 'min tnr_gacr =',minval(tnr_gacr) !..Rain collecting snow & snow collecting rain. - open(unit=11,file='MP_THOMPSON_QRacrQS_DATA.DBL',form='UNFORMATTED',status='OLD',action='READ', & + open(unit=mp_unit,file='MP_THOMPSON_QRacrQS_DATA.DBL',form='UNFORMATTED',status='OLD',action='READ', & iostat=istat) if(istat /= open_OK) & call physics_error_fatal('subroutine thompson_init: ' // & 'failure opening MP_THOMPSON_QRacrQS.DBL') - read(11) tcs_racs1 - read(11) tmr_racs1 - read(11) tcs_racs2 - read(11) tmr_racs2 - read(11) tcr_sacr1 - read(11) tms_sacr1 - read(11) tcr_sacr2 - read(11) tms_sacr2 - read(11) tnr_racs1 - read(11) tnr_racs2 - read(11) tnr_sacr1 - read(11) tnr_sacr2 - close(unit=11) + read(mp_unit) tcs_racs1 + read(mp_unit) tmr_racs1 + read(mp_unit) tcs_racs2 + read(mp_unit) tmr_racs2 + read(mp_unit) tcr_sacr1 + read(mp_unit) tms_sacr1 + read(mp_unit) tcr_sacr2 + read(mp_unit) tms_sacr2 + read(mp_unit) tnr_racs1 + read(mp_unit) tnr_racs2 + read(mp_unit) tnr_sacr1 + read(mp_unit) tnr_sacr2 + close(unit=mp_unit) ! write(0,*) '--- end read MP_THOMPSON_QRacrQS.DBL' ! write(0,*) 'max tcs_racs1 =',maxval(tcs_racs1) ! write(0,*) 'min tcs_racs1 =',minval(tcs_racs1) @@ -905,18 +908,18 @@ subroutine thompson_init(l_mp_tables) ! write(0,*) 'min tnr_sacr2 =',minval(tnr_sacr2) !..Cloud water and rain freezing (Bigg, 1953). - open(unit=11,file='MP_THOMPSON_freezeH2O_DATA.DBL',form='UNFORMATTED',status='OLD',action='READ', & + open(unit=mp_unit,file='MP_THOMPSON_freezeH2O_DATA.DBL',form='UNFORMATTED',status='OLD',action='READ', & iostat=istat) if(istat /= open_OK) & call physics_error_fatal('subroutine thompson_init: ' // & 'failure opening MP_THOMPSON_freezeH2O.DBL') - read(11) tpi_qrfz - read(11) tni_qrfz - read(11) tpg_qrfz - read(11) tnr_qrfz - read(11) tpi_qcfz - read(11) tni_qcfz - close(unit=11) + read(mp_unit) tpi_qrfz + read(mp_unit) tni_qrfz + read(mp_unit) tpg_qrfz + read(mp_unit) tnr_qrfz + read(mp_unit) tpi_qcfz + read(mp_unit) tni_qcfz + close(unit=mp_unit) ! write(0,*) '--- end read MP_THOMPSON_freezeH2O.DBL:' ! write(0,*) 'max tpi_qrfz =',maxval(tpi_qrfz) ! write(0,*) 'min tpi_qrfz =',minval(tpi_qrfz) @@ -932,15 +935,16 @@ subroutine thompson_init(l_mp_tables) ! write(0,*) 'min tni_qcfz =',minval(tni_qcfz) !..Conversion of some ice mass into snow category. - open(unit=11,file='MP_THOMPSON_QIautQS_DATA.DBL',form='UNFORMATTED',status='OLD',action='READ', & + open(unit=mp_unit,file='MP_THOMPSON_QIautQS_DATA.DBL',form='UNFORMATTED',status='OLD',action='READ', & iostat=istat) if(istat /= open_OK) & call physics_error_fatal('subroutine thompson_init: ' // & 'failure opening MP_THOMPSON_QIautQS.DBL') - read(11) tpi_ide - read(11) tps_iaus - read(11) tni_iaus - close(unit=11) + read(mp_unit) tpi_ide + read(mp_unit) tps_iaus + read(mp_unit) tni_iaus + close(unit=mp_unit) + call mpas_release_unit(mp_unit) ! write(0,*) '--- end read MP_THOMPSON_QIautQS.DBL ' ! write(0,*) 'max tps_iaus =',maxval(tps_iaus) ! write(0,*) 'min tps_iaus =',minval(tps_iaus) diff --git a/src/core_atmosphere/utils/atmphys_build_tables_thompson.F b/src/core_atmosphere/utils/atmphys_build_tables_thompson.F index 83ac7b9014..981dee90ea 100644 --- a/src/core_atmosphere/utils/atmphys_build_tables_thompson.F +++ b/src/core_atmosphere/utils/atmphys_build_tables_thompson.F @@ -25,85 +25,91 @@ module atmphys_build_tables_thompson subroutine build_tables_thompson !================================================================================================================= + use mpas_io_units, only : mpas_new_unit, mpas_release_unit + !local variables: logical, parameter:: l_mp_tables = .false. integer:: istatus + integer:: mp_unit !----------------------------------------------------------------------------------------------------------------- !--- partial initialization before building the look-up tables: call thompson_init(l_mp_tables) + call mpas_new_unit(mp_unit, unformatted = .true.) + !--- building look-up table for rain collecting graupel: write(0,*) write(0,*) '--- building MP_THOMPSON_QRacrQG_DATA.DBL' - open(unit=11,file='MP_THOMPSON_QRacrQG_DATA.DBL',form='unformatted',status='new',iostat=istatus) + open(unit=mp_unit,file='MP_THOMPSON_QRacrQG_DATA.DBL',form='unformatted',status='new',iostat=istatus) if (istatus /= 0) then call print_parallel_mesg('MP_THOMPSON_QRacrQG_DATA.DBL') return end if call qr_acr_qg - write(11) tcg_racg - write(11) tmr_racg - write(11) tcr_gacr - write(11) tmg_gacr - write(11) tnr_racg - write(11) tnr_gacr - close(unit=11) + write(mp_unit) tcg_racg + write(mp_unit) tmr_racg + write(mp_unit) tcr_gacr + write(mp_unit) tmg_gacr + write(mp_unit) tnr_racg + write(mp_unit) tnr_gacr + close(unit=mp_unit) !--- building look-up table for rain collecting snow: write(0,*) write(0,*) '--- building MP_THOMPSON_QRacrQS_DATA.DBL' - open(unit=11,file='MP_THOMPSON_QRacrQS_DATA.DBL',form='unformatted',status='new',iostat=istatus) + open(unit=mp_unit,file='MP_THOMPSON_QRacrQS_DATA.DBL',form='unformatted',status='new',iostat=istatus) if (istatus /= 0) then call print_parallel_mesg('MP_THOMPSON_QRacrQS_DATA.DBL') return end if call qr_acr_qs - write(11)tcs_racs1 - write(11)tmr_racs1 - write(11)tcs_racs2 - write(11)tmr_racs2 - write(11)tcr_sacr1 - write(11)tms_sacr1 - write(11)tcr_sacr2 - write(11)tms_sacr2 - write(11)tnr_racs1 - write(11)tnr_racs2 - write(11)tnr_sacr1 - write(11)tnr_sacr2 - close(unit=11) + write(mp_unit)tcs_racs1 + write(mp_unit)tmr_racs1 + write(mp_unit)tcs_racs2 + write(mp_unit)tmr_racs2 + write(mp_unit)tcr_sacr1 + write(mp_unit)tms_sacr1 + write(mp_unit)tcr_sacr2 + write(mp_unit)tms_sacr2 + write(mp_unit)tnr_racs1 + write(mp_unit)tnr_racs2 + write(mp_unit)tnr_sacr1 + write(mp_unit)tnr_sacr2 + close(unit=mp_unit) !--- building look-up table for freezing of cloud droplets: write(0,*) write(0,*) '--- building MP_THOMPSON_freezeH2O_DATA.DBL' - open(unit=11,file='MP_THOMPSON_freezeH2O_DATA.DBL',form='unformatted',status='new',iostat=istatus) + open(unit=mp_unit,file='MP_THOMPSON_freezeH2O_DATA.DBL',form='unformatted',status='new',iostat=istatus) if (istatus /= 0) then call print_parallel_mesg('MP_THOMPSON_freezeH2O_DATA.DBL') return end if call freezeH2O - write(11) tpi_qrfz - write(11) tni_qrfz - write(11) tpg_qrfz - write(11) tnr_qrfz - write(11) tpi_qcfz - write(11) tni_qcfz - close(unit=11) + write(mp_unit) tpi_qrfz + write(mp_unit) tni_qrfz + write(mp_unit) tpg_qrfz + write(mp_unit) tnr_qrfz + write(mp_unit) tpi_qcfz + write(mp_unit) tni_qcfz + close(unit=mp_unit) !--- building look-up table for autoconversion of cloud ice to snow: write(0,*) write(0,*) '--- building MP_THOMPSON_QIautQS_DATA.DBL' - open(unit=11,file='MP_THOMPSON_QIautQS_DATA.DBL',form='unformatted',status='new',iostat=istatus) + open(unit=mp_unit,file='MP_THOMPSON_QIautQS_DATA.DBL',form='unformatted',status='new',iostat=istatus) if (istatus /= 0) then call print_parallel_mesg('MP_THOMPSON_QIautQS_DATA.DBL') return end if call qi_aut_qs - write(11) tpi_ide - write(11) tps_iaus - write(11) tni_iaus - close(unit=11) + write(mp_unit) tpi_ide + write(mp_unit) tps_iaus + write(mp_unit) tni_iaus + close(unit=mp_unit) + call mpas_release_unit(mp_unit) write(0,*) write(0,*) 'Finished building all tables.' diff --git a/src/core_init_atmosphere/CMakeLists.txt b/src/core_init_atmosphere/CMakeLists.txt new file mode 100644 index 0000000000..815d7db291 --- /dev/null +++ b/src/core_init_atmosphere/CMakeLists.txt @@ -0,0 +1,44 @@ +# MPAS/src/core_init_atmosphere +# +# Targets +# MPAS::core::init_atmosphere + +## Generated includes +set(init_atm_core_inc + block_dimension_routines.inc + core_variables.inc + define_packages.inc + domain_variables.inc + namelist_call.inc + namelist_defines.inc + setup_immutable_streams.inc + structs_and_variables.inc) + +## core_init_atosphere +set(init_atm_core_srcs + mpas_atm_advection.F + mpas_atmphys_constants.F + mpas_atmphys_date_time.F + mpas_atmphys_functions.F + mpas_atmphys_initialize_real.F + mpas_atmphys_utilities.F + mpas_geotile_manager.F + mpas_init_atm_bitarray.F + mpas_init_atm_cases.F + mpas_init_atm_core.F + mpas_init_atm_core_interface.F + mpas_init_atm_gwd.F + mpas_init_atm_hinterp.F + mpas_init_atm_llxy.F + mpas_init_atm_queue.F + mpas_init_atm_read_met.F + mpas_init_atm_static.F + mpas_init_atm_surface.F + mpas_init_atm_vinterp.F + mpas_kd_tree.F + mpas_parse_geoindex.F + mpas_stack.F + read_geogrid.c) + +add_library(core_init_atmosphere ${init_atm_core_srcs}) +mpas_core_target(CORE init_atmosphere TARGET core_init_atmosphere INCLUDES ${init_atm_core_inc}) diff --git a/src/core_init_atmosphere/Registry.xml b/src/core_init_atmosphere/Registry.xml index 515b881d01..90dad39fdc 100644 --- a/src/core_init_atmosphere/Registry.xml +++ b/src/core_init_atmosphere/Registry.xml @@ -555,6 +555,10 @@ + + + + diff --git a/src/core_init_atmosphere/mpas_init_atm_cases.F b/src/core_init_atmosphere/mpas_init_atm_cases.F index e08d55e48e..1fb7c73045 100644 --- a/src/core_init_atmosphere/mpas_init_atm_cases.F +++ b/src/core_init_atmosphere/mpas_init_atm_cases.F @@ -4498,7 +4498,7 @@ subroutine init_atm_case_gfs(block, mesh, nCells, nEdges, nVertLevels, fg, state if (allocated(maskslab)) deallocate(maskslab) ! Freeze really cold ocean - where (sst < 271.0 .and. landmask == 0) xice = 1.0 + !where (sst < 271.0 .and. landmask == 0) xice = 1.0 ! Limit XICE to values between 0 and 1. Although the input meteorological field is between 0. ! and 1., interpolation to the MPAS grid can yield values of XiCE less than 0. and greater @@ -4758,7 +4758,8 @@ subroutine init_atm_case_gfs(block, mesh, nCells, nEdges, nVertLevels, fg, state t(k,iCell) = t(k,iCell) * (p0 / pressure(k,iCell)) ** (rgas / cp) ! RHO_ZZ - rho_zz(k,iCell) = pressure(k,iCell) / rgas / (p(k,iCell) * t(k,iCell)) + rho_zz(k,iCell) = pressure(k,iCell) / rgas / & + (p(k,iCell) * t(k,iCell) * (1.0 + (rvord - 1.0) * scalars(index_qv,k,iCell))) rho_zz(k,iCell) = rho_zz(k,iCell) / (1.0 + scalars(index_qv,k,iCell)) end do end do diff --git a/src/core_init_atmosphere/mpas_init_atm_read_met.F b/src/core_init_atmosphere/mpas_init_atm_read_met.F index 510fa4574d..45cd3121b5 100644 --- a/src/core_init_atmosphere/mpas_init_atm_read_met.F +++ b/src/core_init_atmosphere/mpas_init_atm_read_met.F @@ -51,6 +51,7 @@ subroutine read_met_init(fg_source, source_is_constant, datestr, istatus) use mpas_derived_types, only : MPAS_LOG_ERR use mpas_log, only : mpas_log_write + use mpas_io_units, only : mpas_new_unit implicit none @@ -75,11 +76,8 @@ subroutine read_met_init(fg_source, source_is_constant, datestr, istatus) end if ! 2) OPEN FILE - do input_unit=10,100 - inquire(unit=input_unit, opened=is_used) - if (.not. is_used) exit - end do - if (input_unit > 100) call mpas_log_write('In read_met_init(), couldn''t find an available Fortran unit.', messageType=MPAS_LOG_ERR) + call mpas_new_unit(input_unit, unformatted = .true.) + if (input_unit < 0) call mpas_log_write('In read_met_init(), couldn''t find an available Fortran unit.', messageType=MPAS_LOG_ERR) open(unit=input_unit, file=trim(filename), status='old', form='unformatted', iostat=io_status) if (io_status > 0) istatus = 1 @@ -418,9 +416,12 @@ end subroutine read_next_met_field !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! subroutine read_met_close() + use mpas_io_units, only : mpas_release_unit + implicit none close(unit=input_unit) + call mpas_release_unit(input_unit) filename = 'UNINITIALIZED_FILENAME' end subroutine read_met_close diff --git a/src/core_sw/CMakeLists.txt b/src/core_sw/CMakeLists.txt new file mode 100644 index 0000000000..e1b4f4e00b --- /dev/null +++ b/src/core_sw/CMakeLists.txt @@ -0,0 +1,29 @@ +# MPAS/src/core_sw +# +# Targets +# MPAS::core::sw + +## Generated includes +set(sw_core_inc + block_dimension_routines.inc + core_variables.inc + define_packages.inc + domain_variables.inc + namelist_call.inc + namelist_defines.inc + setup_immutable_streams.inc + structs_and_variables.inc) + +## core_init_atosphere +set(sw_core_srcs + mpas_sw_advection.F + mpas_sw_constants.F + mpas_sw_core.F + mpas_sw_core_interface.F + mpas_sw_global_diagnostics.F + mpas_sw_test_cases.F + mpas_sw_time_integration.F + ) + +add_library(core_sw ${sw_core_srcs}) +mpas_core_target(CORE sw TARGET core_sw INCLUDES ${sw_core_inc}) diff --git a/src/core_test/CMakeLists.txt b/src/core_test/CMakeLists.txt new file mode 100644 index 0000000000..d4425c3ea0 --- /dev/null +++ b/src/core_test/CMakeLists.txt @@ -0,0 +1,29 @@ +# MPAS/src/core_test +# +# Targets +# MPAS::core::test + +## Generated includes +set(test_core_inc + block_dimension_routines.inc + core_variables.inc + define_packages.inc + domain_variables.inc + namelist_call.inc + namelist_defines.inc + setup_immutable_streams.inc + structs_and_variables.inc) + +## core_init_atosphere +set(test_core_srcs + mpas_test_core.F + mpas_test_core_field_tests.F + mpas_test_core_halo_exch.F + mpas_test_core_interface.F + mpas_test_core_sorting.F + mpas_test_core_streams.F + mpas_test_core_timekeeping_tests.F + ) + +add_library(core_test ${test_core_srcs}) +mpas_core_target(CORE test TARGET core_test INCLUDES ${test_core_inc}) diff --git a/src/driver/mpas_subdriver.F b/src/driver/mpas_subdriver.F index 2705777a25..79a051f347 100644 --- a/src/driver/mpas_subdriver.F +++ b/src/driver/mpas_subdriver.F @@ -39,7 +39,7 @@ module mpas_subdriver contains - subroutine mpas_init(corelist, domain_ptr, mpi_comm) + subroutine mpas_init(corelist, domain_ptr, mpi_comm, namelistFileParam, streamsFileParam) use mpas_stream_manager, only : MPAS_stream_mgr_init, MPAS_build_stream_filename, MPAS_stream_mgr_validate_streams use iso_c_binding, only : c_char, c_loc, c_ptr, c_int @@ -53,7 +53,9 @@ subroutine mpas_init(corelist, domain_ptr, mpi_comm) type (core_type), intent(inout), pointer :: corelist type (domain_type), intent(inout), pointer :: domain_ptr integer, intent(in), optional :: mpi_comm - + character(len=*), intent(in), optional :: namelistFileParam + character(len=*), intent(in), optional :: streamsFileParam + integer :: iArg, nArgs logical :: readNamelistArg, readStreamsArg character(len=StrKIND) :: argument, namelistFile, streamsFile @@ -109,6 +111,15 @@ end subroutine xml_stream_get_attributes readNamelistArg = .false. readStreamsArg = .false. + if (present(namelistFileParam) .and. len_trim(namelistFileParam) > 0 ) then + readNamelistArg = .true. + namelistFile = trim(namelistFileParam) + endif + if (present(streamsFileParam) .and. len_trim(streamsFileParam) > 0 ) then + readStreamsArg = .true. + streamsFile = trim(streamsFileParam) + endif + nArgs = command_argument_count() iArg = 1 do while (iArg < nArgs) diff --git a/src/external/esmf_time_f90/CMakeLists.txt b/src/external/esmf_time_f90/CMakeLists.txt new file mode 100644 index 0000000000..6546880fb4 --- /dev/null +++ b/src/external/esmf_time_f90/CMakeLists.txt @@ -0,0 +1,34 @@ + +set(_esmf_time_src + ESMF_AlarmClockMod.F90 + ESMF_AlarmMod.F90 + ESMF_BaseMod.F90 + ESMF_BaseTimeMod.F90 + ESMF_CalendarMod.F90 + ESMF_ClockMod.F90 + ESMF.F90 + ESMF_FractionMod.F90 + ESMF_Macros.inc + ESMF_ShrTimeMod.F90 + ESMF_Stubs.F90 + ESMF_TimeIntervalMod.F90 + ESMF_TimeMgr.inc + ESMF_TimeMod.F90 + MeatMod.F90 + wrf_error_fatal.F90 + wrf_message.F90) + +add_library(esmf ${_esmf_time_src}) +mpas_fortran_target(esmf) +add_library(${PROJECT_NAME}::external::esmf ALIAS esmf) + +target_compile_definitions(esmf PRIVATE HIDE_MPI=1) + +target_include_directories(esmf PUBLIC $) + +target_link_libraries(esmf PUBLIC MPI::MPI_Fortran) + +install(TARGETS esmf EXPORT ${PROJECT_NAME}ExportsExternal + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + diff --git a/src/external/ezxml/CMakeLists.txt b/src/external/ezxml/CMakeLists.txt new file mode 100644 index 0000000000..34955dbd98 --- /dev/null +++ b/src/external/ezxml/CMakeLists.txt @@ -0,0 +1,8 @@ + +add_library(ezxml ezxml.c) +add_library(${PROJECT_NAME}::external::ezxml ALIAS ezxml) +target_include_directories(ezxml PUBLIC $) + +install(TARGETS ezxml EXPORT ${PROJECT_NAME}ExportsExternal + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt new file mode 100644 index 0000000000..bb88f5477a --- /dev/null +++ b/src/framework/CMakeLists.txt @@ -0,0 +1,55 @@ + +set(_mpas_framework_src + mpas_abort.F + mpas_attlist.F + mpas_block_creator.F + mpas_block_decomp.F + mpas_bootstrapping.F + mpas_c_interfacing.F + mpas_constants.F + mpas_decomp.F + mpas_derived_types.F + mpas_dmpar.F + mpas_domain_routines.F + mpas_field_accessor.F + mpas_field_routines.F + mpas_forcing.F + mpas_framework.F + mpas_hash.F + mpas_io.F + mpas_io_streams.F + mpas_io_units.F + mpas_kind_types.F + mpas_log.F + mpas_pool_routines.F + mpas_sort.F + mpas_stream_list.F + mpas_stream_manager.F + mpas_threading.F + mpas_timekeeping.F + mpas_timer.F + pool_hash.c + random_id.c + regex_matching.c + xml_stream_parser.c) + +add_library(framework ${_mpas_framework_src}) +mpas_fortran_target(framework) +add_library(${PROJECT_NAME}::framework ALIAS framework) + +set_target_properties(framework PROPERTIES OUTPUT_NAME mpas_framework) + +target_link_libraries(framework PUBLIC ${PROJECT_NAME}::external::esmf) +target_link_libraries(framework PUBLIC ${PROJECT_NAME}::external::ezxml) +target_link_libraries(framework PUBLIC PIO::PIO_Fortran PIO::PIO_C) +target_link_libraries(framework PUBLIC PnetCDF::PnetCDF_Fortran) +target_link_libraries(framework PUBLIC NetCDF::NetCDF_Fortran) +target_link_libraries(framework PUBLIC MPI::MPI_Fortran) + +if(MPAS_PROFILE) + target_link_libraries(framework PUBLIC GPTL::GPTL) +endif() + +install(TARGETS framework EXPORT ${PROJECT_NAME}Exports + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/framework/mpas_dmpar.F b/src/framework/mpas_dmpar.F index 8e5340e420..42bb827efa 100644 --- a/src/framework/mpas_dmpar.F +++ b/src/framework/mpas_dmpar.F @@ -161,6 +161,28 @@ module mpas_dmpar private :: mpas_dmpar_exch_halo_field4d_real private :: mpas_dmpar_exch_halo_field5d_real + interface mpas_dmpar_exch_halo_adj_field +! module procedure mpas_dmpar_exch_halo_adj_field1d_integer +! module procedure mpas_dmpar_exch_halo_adj_field2d_integer +! module procedure mpas_dmpar_exch_halo_adj_field3d_integer +! module procedure mpas_dmpar_exch_halo_adj_field1d_real + module procedure mpas_dmpar_exch_halo_adj_field2d_real +! module procedure mpas_dmpar_exch_halo_adj_field3d_real +! module procedure mpas_dmpar_exch_halo_adj_field4d_real +! module procedure mpas_dmpar_exch_halo_adj_field5d_real + end interface + + public :: mpas_dmpar_exch_halo_adj_field + +! private :: mpas_dmpar_exch_halo_adj_field1d_integer +! private :: mpas_dmpar_exch_halo_adj_field2d_integer +! private :: mpas_dmpar_exch_halo_adj_field3d_integer +! private :: mpas_dmpar_exch_halo_adj_field1d_real + private :: mpas_dmpar_exch_halo_adj_field2d_real +! private :: mpas_dmpar_exch_halo_adj_field3d_real +! private :: mpas_dmpar_exch_halo_adj_field4d_real +! private :: mpas_dmpar_exch_halo_adj_field5d_real + interface mpas_dmpar_copy_field module procedure mpas_dmpar_copy_field1d_integer module procedure mpas_dmpar_copy_field2d_integer @@ -6133,6 +6155,189 @@ subroutine mpas_dmpar_exch_halo_field5d_real(field, haloLayersIn)!{{{ end subroutine mpas_dmpar_exch_halo_field5d_real!}}} +!----------------------------------------------------------------------- +! routine mpas_dmpar_exch_halo_adj_field2d_real +! +!> \brief MPAS dmpar halo exchange adjoint 2D real field +!> \author Doug Jacobsen +!> \date 03/26/13 +!> \details +!> This routine handles the halo exchange communication of an input field across all processors. +!> It requires exchange lists to be created prior to calling this routine. +! +!----------------------------------------------------------------------- + subroutine mpas_dmpar_exch_halo_adj_field2d_real(field, haloLayersIn)!{{{ + + implicit none + + type (field2dReal), pointer :: field !< Input: Field to communicate + integer, dimension(:), intent(in), optional :: haloLayersIn !< Input: List of halo layers to communicate. Defaults to all + + type (dm_info), pointer :: dminfo + type (field2dReal), pointer :: fieldCursor, fieldCursor2 + type (mpas_exchange_list), pointer :: exchListPtr + type (mpas_communication_list), pointer :: sendList, recvList, commListPtr + integer :: mpi_ierr, threadNum + integer :: nHaloLayers, iHalo, i, j + integer :: bufferOffset, nAdded + integer, dimension(:), pointer :: haloLayers + + if ( .not. field % isActive ) then +#ifdef MPAS_DEBUG + call mpas_log_write(' -- Skipping halo exchange for deactivated field: ' // trim(field % fieldName)) +#endif + return + end if + + do i = 1, 2 + if(field % dimSizes(i) <= 0) then + return + end if + end do + + dminfo => field % block % domain % dminfo + threadNum = mpas_threading_get_thread_num() + + if ( threadNum == 0 ) then + if(present(haloLayersIn)) then + nHaloLayers = size(haloLayersIn) + allocate(haloLayers(nHaloLayers)) + do iHalo = 1, nHaloLayers + haloLayers(iHalo) = haloLayersIn(iHalo) + end do + else + nHaloLayers = size(field % sendList % halos) + allocate(haloLayers(nHaloLayers)) + do iHalo = 1, nHaloLayers + haloLayers(iHalo) = iHalo + end do + end if + +#ifdef _MPI + ! Setup Communication Lists + call mpas_dmpar_build_comm_lists(field % sendList, field % recvList, haloLayers, field % dimsizes, sendList, recvList) + + ! Allocate space in recv lists, and initiate mpi_irecv calls + commListPtr => sendList + do while(associated(commListPtr)) + allocate(commListPtr % rbuffer(commListPtr % nList)) + nullify(commListPtr % ibuffer) + call MPI_Irecv(commListPtr % rbuffer, commListPtr % nList, MPI_REALKIND, commListPtr % procID, commListPtr % procID, dminfo % comm, commListPtr % reqID, mpi_ierr) + + commListPtr => commListPtr % next + end do + + ! Allocate space in send lists, copy data into buffer, and initiate mpi_isend calls + commListPtr => recvList + do while(associated(commListPtr)) + allocate(commListPtr % rbuffer(commListPtr % nList)) + nullify(commListPtr % ibuffer) + bufferOffset = 0 + do iHalo = 1, nHaloLayers + nAdded = 0 + fieldCursor => field + do while(associated(fieldCursor)) + exchListPtr => fieldCursor % recvList % halos(haloLayers(iHalo)) % exchList + do while(associated(exchListPtr)) + if(exchListPtr % endPointID == commListPtr % procID) then + do i = 1, exchListPtr % nList + do j = 1, fieldCursor % dimSizes(1) + commListPtr % rbuffer((exchListPtr % srcList(i)-1) * fieldCursor % dimSizes(1) + j + bufferOffset) = fieldCursor % array(j, exchListPtr % destList(i)) + fieldCursor % array(j, exchListPtr % destList(i)) = 0.0_RKIND + nAdded = nAdded + 1 + end do + end do + end if + + exchListPtr => exchListPtr % next + end do + + fieldCursor => fieldCursor % next + end do + bufferOffset = bufferOffset + nAdded + end do + + call MPI_Isend(commListPtr % rbuffer, commListPtr % nList, MPI_REALKIND, commListPtr % procID, dminfo % my_proc_id, dminfo % comm, commListPtr % reqID, mpi_ierr) + commListPtr => commListPtr % next + end do +#endif + + ! Handle local copy. If MPI is off, then only local copies are performed. + fieldCursor => field + do while(associated(fieldCursor)) + do iHalo = 1, nHaloLayers + exchListPtr => fieldCursor % copyList % halos(haloLayers(iHalo)) % exchList + + do while(associated(exchListPtr)) + fieldCursor2 => field + do while(associated(fieldCursor2)) + if(exchListPtr % endPointID == fieldCursor2 % block % localBlockID) then + do i = 1, exchListPtr % nList + !fieldCursor2 % array(:, exchListPtr % destList(i)) = fieldCursor % array(:, exchListPtr % srcList(i)) + fieldCursor % array(:, exchListPtr % srcList(i)) = fieldCursor % array(:, exchListPtr % srcList(i)) + fieldCursor2 % array(:, exchListPtr % destList(i)) + fieldCursor2 % array(:, exchListPtr % destList(i)) = 0.0_RKIND + end do + end if + + fieldCursor2 => fieldCursor2 % next + end do + + exchListPtr => exchListPtr % next + end do + end do + + fieldCursor => fieldCursor % next + end do + +#ifdef _MPI + + ! Wait for mpi_irecv to finish, and unpack data from buffer + commListPtr => sendList + do while(associated(commListPtr)) + call MPI_Wait(commListPtr % reqID, MPI_STATUS_IGNORE, mpi_ierr) + bufferOffset = 0 + do iHalo = 1, nHaloLayers + nAdded = 0 + fieldCursor => field + do while(associated(fieldCursor)) + exchListPtr => fieldCursor % sendList % halos(haloLayers(iHalo)) % exchList + do while(associated(exchListPtr)) + if(exchListPtr % endPointID == commListPtr % procID) then + do i = 1, exchListPtr % nList + do j = 1, fieldCursor % dimSizes(1) + fieldCursor % array(j, exchListPtr % srcList(i)) = fieldCursor % array(j, exchListPtr % srcList(i)) + commListPtr % rbuffer((exchListPtr % destList(i)-1) * fieldCursor % dimSizes(1) + j + bufferOffset) + commListPtr % rbuffer((exchListPtr % destList(i)-1) * fieldCursor % dimSizes(1) + j + bufferOffset) = 0.0_RKIND + end do + end do + nAdded = max(nAdded, maxval(exchListPtr % destList) * fieldCursor % dimSizes(1)) + end if + exchListPtr => exchListPtr % next + end do + + fieldCursor => fieldCursor % next + end do + bufferOffset = bufferOffset + nAdded + end do + commListPtr => commListPtr % next + end do + + ! wait for mpi_isend to finish. + commListPtr => recvList + do while(associated(commListPtr)) + call MPI_Wait(commListPtr % reqID, MPI_STATUS_IGNORE, mpi_ierr) + commListPtr => commListPtr % next + end do + + ! Destroy commLists. + call mpas_dmpar_destroy_communication_list(sendList) + call mpas_dmpar_destroy_communication_list(recvList) +#endif + + deallocate(haloLayers) + end if + + end subroutine mpas_dmpar_exch_halo_adj_field2d_real!}}} + !----------------------------------------------------------------------- ! routine mpas_dmpar_init_multihalo_exchange_list ! diff --git a/src/operators/CMakeLists.txt b/src/operators/CMakeLists.txt new file mode 100644 index 0000000000..5c04339b80 --- /dev/null +++ b/src/operators/CMakeLists.txt @@ -0,0 +1,24 @@ +list(APPEND _mpas_operators_src + mpas_geometry_utils.F + mpas_matrix_operations.F + mpas_rbf_interpolation.F + mpas_spline_interpolation.F + mpas_tensor_operations.F + mpas_tracer_advection_helpers.F + mpas_tracer_advection_mono.F + mpas_tracer_advection_std.F + mpas_vector_operations.F + mpas_vector_reconstruction.F) + +add_library(operators ${_mpas_operators_src}) + +mpas_fortran_target(operators) + +add_library(${PROJECT_NAME}::operators ALIAS operators) + +set_target_properties(operators PROPERTIES OUTPUT_NAME mpas_operators) +target_link_libraries(operators PUBLIC ${PROJECT_NAME}::framework) + +install(TARGETS operators EXPORT ${PROJECT_NAME}Exports + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/tools/input_gen/CMakeLists.txt b/src/tools/input_gen/CMakeLists.txt new file mode 100644 index 0000000000..2b8c770476 --- /dev/null +++ b/src/tools/input_gen/CMakeLists.txt @@ -0,0 +1,6 @@ + +add_executable(mpas_namelist_gen namelist_gen.c test_functions.c) +target_link_libraries(mpas_namelist_gen PUBLIC ${PROJECT_NAME}::external::ezxml) + +add_executable(mpas_streams_gen streams_gen.c test_functions.c) +target_link_libraries(mpas_streams_gen PUBLIC ${PROJECT_NAME}::external::ezxml) diff --git a/src/tools/registry/CMakeLists.txt b/src/tools/registry/CMakeLists.txt new file mode 100644 index 0000000000..7d18e3f3b6 --- /dev/null +++ b/src/tools/registry/CMakeLists.txt @@ -0,0 +1,17 @@ + +#Parsing library core-independent code +add_library(parselib dictionary.c fortprintf.c utility.c) +target_link_libraries(parselib PUBLIC ${PROJECT_NAME}::external::ezxml) +target_link_libraries(parselib PUBLIC ${PROJECT_NAME}::external::esmf) + +# Generate parser for each core +# +# Note: One parser is required per-core because the gen_inc.c depends on +# a pre-processor define MPAS_NAMELIST_SUFFIX which is core specific +foreach(_core IN LISTS MPAS_CORES) + add_executable(mpas_parse_${_core} parse.c gen_inc.c) + target_link_libraries(mpas_parse_${_core} PUBLIC parselib) + target_compile_definitions(mpas_parse_${_core} PRIVATE MPAS_NAMELIST_SUFFIX=${_core} + MPAS_GIT_VERSION=${MPAS_GIT_VERSION} + MPAS_EXE_NAME=${_core}_model) +endforeach() diff --git a/src/tools/registry/gen_inc.c b/src/tools/registry/gen_inc.c index eb9395016a..619740002f 100644 --- a/src/tools/registry/gen_inc.c +++ b/src/tools/registry/gen_inc.c @@ -154,16 +154,17 @@ int add_package_to_list(const char * package, const char * package_list){/*{{{*/ token = strsep(&string, ";"); if(strcmp(package, token) == 0){ + if(tofree) free(tofree); return 0; } while( (token = strsep(&string, ";")) != NULL){ if(strcmp(package, token) == 0){ - + if(tofree) free(tofree); return 0; } } - + if(tofree) free(tofree); return 1; }/*}}}*/ @@ -226,12 +227,13 @@ int build_struct_package_lists(ezxml_t currentPosition, char * out_packages){/*{ if(out_packages[0] == '\0'){ sprintf(out_packages, "%s", token); } else if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + strcat(out_packages, ";"); + strcat(out_packages, token); } while( (token = strsep(&string, ";")) != NULL){ if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + strcat(out_packages, token-1); } } @@ -250,12 +252,13 @@ int build_struct_package_lists(ezxml_t currentPosition, char * out_packages){/*{ if(out_packages[0] == '\0'){ sprintf(out_packages, "%s", token); } else if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + strcat(out_packages, ";"); + strcat(out_packages, token); } while( (token = strsep(&string, ";")) != NULL){ if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + strcat(out_packages, token-1); } } @@ -276,12 +279,13 @@ int build_struct_package_lists(ezxml_t currentPosition, char * out_packages){/*{ if(out_packages[0] == '\0'){ sprintf(out_packages, "%s", token); } else if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + strcat(out_packages, ";"); + strcat(out_packages, token); } while( (token = strsep(&string, ";")) != NULL){ if(add_package_to_list(token, out_packages)){ - sprintf(out_packages, "%s;%s", out_packages, token); + strcat(out_packages, token-1); } } @@ -388,12 +392,14 @@ int build_dimension_information(ezxml_t registry, ezxml_t var, int *ndims, int * (*decomp) = dim_decomp; } else if ( (*decomp) != -1 && dim_decomp != -1) { fprintf(stderr, "ERROR: Variable %s contains multiple decomposed dimensions in list: %s\n", varname, vardims); + if(tofree) free(tofree); return 1; } } else if (is_time) { (*has_time) = 1; } else if (!dim_exists) { fprintf(stderr, "ERROR: Dimension %s on variable %s doesn't exist.\n", token, varname); + if(tofree) free(tofree); return 1; } } @@ -409,17 +415,19 @@ int build_dimension_information(ezxml_t registry, ezxml_t var, int *ndims, int * (*decomp) = dim_decomp; } else if ( (*decomp) != -1 && dim_decomp != -1) { fprintf(stderr, "ERROR: Variable %s contains multiple decomposed dimensions in list: %s\n", varname, vardims); + if(tofree) free(tofree); return 1; } } else if (is_time) { (*has_time) = 1; } else if (!dim_exists) { fprintf(stderr, "ERROR: Dimension %s on variable %s doesn't exist.\n", token, varname); + if(tofree) free(tofree); return 1; } } - free(tofree); + if(tofree) free(tofree); return 0; }/*}}}*/ @@ -1157,6 +1165,7 @@ int parse_var_array(FILE *fd, ezxml_t registry, ezxml_t superStruct, ezxml_t var fortprintf(fd, ") then\n"); snprintf(sub_spacing, 1024, " "); + if(tofree) free(tofree); } fortprintf(fd, " %sindex_counter = index_counter + 1\n", sub_spacing); @@ -1222,6 +1231,7 @@ int parse_var_array(FILE *fd, ezxml_t registry, ezxml_t superStruct, ezxml_t var fortprintf(fd, ") then\n"); snprintf(sub_spacing, 1024, " "); + if(tofree) free(tofree); } fortprintf(fd, " %sindex_counter = index_counter + 1\n", sub_spacing); @@ -1383,7 +1393,8 @@ int parse_var_array(FILE *fd, ezxml_t registry, ezxml_t superStruct, ezxml_t var sprintf(temp_str, "%s", token); while ( ( token = strsep(&string, "'") ) != NULL ) { - sprintf(temp_str, "%s''%s", temp_str, token); + strcat(temp_str,"''"); + strcat(temp_str,token); } free(tofree); @@ -1399,7 +1410,8 @@ int parse_var_array(FILE *fd, ezxml_t registry, ezxml_t superStruct, ezxml_t var sprintf(temp_str, "%s", token); while ( ( token = strsep(&string, "'") ) != NULL ) { - sprintf(temp_str, "%s''%s", temp_str, token); + strcat(temp_str,"''"); + strcat(temp_str,token); } free(tofree); @@ -1434,6 +1446,7 @@ int parse_var_array(FILE *fd, ezxml_t registry, ezxml_t superStruct, ezxml_t var fortprintf(fd, " .or. %sActive", token); } fortprintf(fd, ") then\n"); + if(tofree) free(tofree); } for(time_lev = 1; time_lev <= time_levs; time_lev++){ @@ -1610,7 +1623,8 @@ int parse_var(FILE *fd, ezxml_t registry, ezxml_t superStruct, ezxml_t currentVa sprintf(temp_str, "%s", token); while ( ( token = strsep(&string, "'") ) != NULL ) { - sprintf(temp_str, "%s''%s", temp_str, token); + strcat(temp_str,"''"); + strcat(temp_str,token); } free(tofree); @@ -1626,7 +1640,8 @@ int parse_var(FILE *fd, ezxml_t registry, ezxml_t superStruct, ezxml_t currentVa sprintf(temp_str, "%s", token); while ( ( token = strsep(&string, "'") ) != NULL ) { - sprintf(temp_str, "%s''%s", temp_str, token); + strcat(temp_str,"''"); + strcat(temp_str,token); } free(tofree); @@ -1659,6 +1674,7 @@ int parse_var(FILE *fd, ezxml_t registry, ezxml_t superStruct, ezxml_t currentVa } fortprintf(fd, ") then\n"); + if(tofree) free(tofree); } for(time_lev = 1; time_lev <= time_levs; time_lev++){ @@ -1714,7 +1730,7 @@ int parse_struct(FILE *fd, ezxml_t registry, ezxml_t superStruct, int subpool, c structname = ezxml_attr(superStruct, "name"); structnameincode = ezxml_attr(superStruct, "name_in_code"); - + if(!structnameincode){ structnameincode = ezxml_attr(superStruct, "name"); } @@ -1960,7 +1976,6 @@ int generate_immutable_streams(ezxml_t registry){/*{{{*/ fortprintf(fd, " call MPAS_stream_mgr_add_field(manager, \'%s\', \'%s\', packages=packages, ierr=ierr)\n", optname, optvarname); else fortprintf(fd, " call MPAS_stream_mgr_add_field(manager, \'%s\', \'%s\', ierr=ierr)\n", optname, optvarname); - } /* Loop over arrays of fields listed within the stream */ @@ -2408,5 +2423,3 @@ int parse_structs_from_registry(ezxml_t registry)/*{{{*/ return 0; }/*}}}*/ - -