diff --git a/.gitmodules b/.gitmodules index 22c723ac1..a773677e6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,5 @@ -[submodule "atmos_cubed_sphere"] - path = atmos_cubed_sphere +[submodule "fv3/atmos_cubed_sphere"] + path = fv3/atmos_cubed_sphere url = https://github.com/NOAA-GFDL/GFDL_atmos_cubed_sphere branch = dev/emc [submodule "ccpp/framework"] @@ -14,3 +14,7 @@ path = upp url = https://github.com/NOAA-EMC/UPP branch = develop +[submodule "mpas/MPAS-Model"] + path = mpas/MPAS-Model + url = https://github.com/ufs-community/MPAS-Model.git + branch = feature/mpas-in-ufs diff --git a/CMakeLists.txt b/CMakeLists.txt index cdf597df2..8f26344f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ -# This is the main CMake file for fv3atm. +# This is the main CMake file for ufsatm. # -# Dusan Jovic, Alex Richert +# Dusan Jovic, Alex Richert, Dustin Swales cmake_minimum_required(VERSION 3.19) # Handle user build options. @@ -14,171 +14,233 @@ endif() # Enable CI build & unit testing: if(BUILD_TESTING) - project(fv3atm VERSION 1.0 LANGUAGES C CXX Fortran) + if (FV3) + project(ufsatm_fv3 VERSION 1.0 LANGUAGES C CXX Fortran) + endif() + if (MPAS) + project(ufsatm_mpas VERSION 1.0 LANGUAGES C CXX Fortran) + endif() include(ci/CMakeLists.txt) endif() +# Set variables for all dycore build options in UFSATM. +set(DYCORE_TARGET_MPAS ufsatm_mpas) +set(DYCORE_TARGET_FV3 ufsatm_fv3) + ############################################################################### -### CCPP +### All dynamical cores ############################################################################### - +# CCPP set(MPI ON) add_subdirectory(ccpp) -############################################################################### -### fv3 dynamical core -############################################################################### - -# These ifdefs need to be turned ON in the dycore. -set(use_WRTCOMP ON) -set(GFS_PHYS ON) -set(GFS_TYPES ON) -set(USE_GFSL63 ON) -if(MOVING_NEST) - set(MOVING_NEST ON) -endif() -if(HYDRO) - set(HYDRO ON) -endif() -add_subdirectory(atmos_cubed_sphere) -target_compile_definitions(fv3 PRIVATE BYPASS_BREED_SLP_INLINE) - -############################################################################### -### fv3atm -############################################################################### -if(INLINE_POST) - set(BUILD_POSTEXEC OFF) - add_subdirectory(upp) - set(POST_SRC io/post_nems_routines.F90 io/post_fv3.F90) - list(APPEND _fv3atm_defs_private INLINE_POST) -endif() - if(CCPP_32BIT) add_definitions(-DCCPP_32BIT) else() remove_definitions(-DCCPP_32BIT) endif() +# Pnetcdf if(NOT PARALLEL_NETCDF) - list(APPEND _fv3atm_defs_private NO_PARALLEL_NETCDF) + list(APPEND _ufsatm_defs_private NO_PARALLEL_NETCDF) endif() -if(MOVING_NEST) - list(APPEND _fv3atm_defs_private MOVING_NEST) - if(NOT HYDRO) - list(APPEND _fv3atm_defs_private MOIST_CAPPA USE_COND) - endif() +if(BUILD_TESTING) + include(CTest) + add_subdirectory(tests) +endif() - if(DEBUG) - list(APPEND _fv3atm_defs_private DEBUG) - endif() - if(GFS_PHYS) - list(APPEND _fv3atm_defs_private GFS_PHYS) - endif() - if(GFS_TYPES) - list(APPEND _fv3atm_defs_private GFS_TYPES) - endif() - if(USE_GFSL63) - list(APPEND _fv3atm_defs_private USE_GFSL63) +############################################################################### +### UFSATM with FV3 dynamical core +############################################################################### +if (FV3) + set(DYCORE_TARGET ${DYCORE_TARGET_FV3}) + + # These ifdefs need to be turned ON in the dycore. + set(use_WRTCOMP ON) + set(GFS_PHYS ON) + set(GFS_TYPES ON) + set(USE_GFSL63 ON) + if(MOVING_NEST) + set(MOVING_NEST ON) endif() - if(INTERNAL_FILE_NML) - list(APPEND _fv3atm_defs_private INTERNAL_FILE_NML) + + if(HYDRO) + set(HYDRO ON) endif() - if(ENABLE_QUAD_PRECISION) - list(APPEND _fv3atm_defs_private ENABLE_QUAD_PRECISION) + add_subdirectory(fv3/atmos_cubed_sphere) + target_compile_definitions(fv3 PRIVATE BYPASS_BREED_SLP_INLINE) + + if(INLINE_POST) + set(BUILD_POSTEXEC OFF) + add_subdirectory(upp) + set(POST_SRC io/post_nems_routines.F90 io/post_fv3.F90) + list(APPEND _ufsatm_defs_private INLINE_POST) endif() - if(32BIT) - list(APPEND _fv3atm_defs_private OVERLOAD_R4 OVERLOAD_R8) + + if(MOVING_NEST) + list(APPEND _ufsatm_defs_private MOVING_NEST) + if(NOT HYDRO) + list(APPEND _ufsatm_defs_private MOIST_CAPPA USE_COND) + endif() + + if(DEBUG) + list(APPEND _ufsatm_defs_private DEBUG) + endif() + if(GFS_PHYS) + list(APPEND _ufsatm_defs_private GFS_PHYS) + endif() + if(GFS_TYPES) + list(APPEND _ufsatm_defs_private GFS_TYPES) + endif() + if(USE_GFSL63) + list(APPEND _ufsatm_defs_private USE_GFSL63) + endif() + if(INTERNAL_FILE_NML) + list(APPEND _ufsatm_defs_private INTERNAL_FILE_NML) + endif() + if(ENABLE_QUAD_PRECISION) + list(APPEND _ufsatm_defs_private ENABLE_QUAD_PRECISION) + endif() + if(32BIT) + list(APPEND _ufsatm_defs_private OVERLOAD_R4 OVERLOAD_R8) + endif() + + list(APPEND moving_nest_srcs + fv3/moving_nest/bounding_box.F90 + fv3/moving_nest/fv_tracker.F90 + fv3/moving_nest/fv_moving_nest.F90 + fv3/moving_nest/fv_moving_nest_main.F90 + fv3/moving_nest/fv_moving_nest_physics.F90 + fv3/moving_nest/fv_moving_nest_types.F90 + fv3/moving_nest/fv_moving_nest_utils.F90 + ) + else() + list(APPEND moving_nest_srcs "") endif() - list(APPEND moving_nest_srcs - moving_nest/bounding_box.F90 - moving_nest/fv_tracker.F90 - moving_nest/fv_moving_nest.F90 - moving_nest/fv_moving_nest_main.F90 - moving_nest/fv_moving_nest_physics.F90 - moving_nest/fv_moving_nest_types.F90 - moving_nest/fv_moving_nest_utils.F90 - ) -else() - list(APPEND moving_nest_srcs "") + if(MULTI_GASES) + list(APPEND _ufsatm_defs_private MULTI_GASES) + endif() + + # FV3 drivers and dependencies + add_library(${DYCORE_TARGET} + fv3/atmos_model.F90 + fv3/fv3_cap.F90 + fv3/module_fv3_config.F90 + fv3/module_fcst_grid_comp.F90 + stochastic_physics/stochastic_physics_wrapper.F90 + cpl/module_block_data.F90 + cpl/module_cplfields.F90 + cpl/module_cap_cpl.F90 + cpl/module_cplscalars.F90 + io/fv3atm_common_io.F90 + io/fv3atm_clm_lake_io.F90 + io/fv3atm_rrfs_sd_io.F90 + io/fv3atm_sfc_io.F90 + io/fv3atm_oro_io.F90 + io/fv3atm_history_io.F90 + io/fv3atm_restart_io.F90 + io/module_write_netcdf.F90 + io/module_write_restart_netcdf.F90 + io/module_fv3_io_def.F90 + io/module_write_internal_state.F90 + io/module_wrt_grid_comp.F90 + ${moving_nest_srcs} + ${POST_SRC} + ) + add_dependencies(${DYCORE_TARGET} fv3 fv3ccpp stochastic_physics) + + list(APPEND _ufsatm_defs_private GFS_PHYS + INTERNAL_FILE_NML + use_WRTCOMP) endif() -add_library(fv3atm - atmos_model.F90 - fv3_cap.F90 - module_fv3_config.F90 - module_fcst_grid_comp.F90 - stochastic_physics/stochastic_physics_wrapper.F90 - cpl/module_block_data.F90 - cpl/module_cplfields.F90 - cpl/module_cap_cpl.F90 - cpl/module_cplscalars.F90 - io/fv3atm_common_io.F90 - io/fv3atm_clm_lake_io.F90 - io/fv3atm_rrfs_sd_io.F90 - io/fv3atm_sfc_io.F90 - io/fv3atm_oro_io.F90 - io/fv3atm_history_io.F90 - io/fv3atm_restart_io.F90 - io/module_write_netcdf.F90 - io/module_write_restart_netcdf.F90 - io/module_fv3_io_def.F90 - io/module_write_internal_state.F90 - io/module_wrt_grid_comp.F90 - ${moving_nest_srcs} - ${POST_SRC} -) - -add_dependencies(fv3atm fv3 fv3ccpp stochastic_physics) - -list(APPEND _fv3atm_defs_private GFS_PHYS - INTERNAL_FILE_NML - use_WRTCOMP) - -target_compile_definitions(fv3atm PRIVATE "${_fv3atm_defs_private}") - -set_target_properties(fv3atm PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod) -target_include_directories(fv3atm INTERFACE $ - $) - -if(MULTI_GASES) - list(APPEND _fv3atm_defs_private MULTI_GASES) +############################################################################### +### UFSATM with MPAS dynamical core. +############################################################################### +if (MPAS) + set(DYCORE_TARGET ${DYCORE_TARGET_MPAS}) + + # Include MPAS Cmake tools. + include(${CMAKE_CURRENT_SOURCE_DIR}/mpas/MPAS-Model/cmake/Functions/MPAS_Functions.cmake) + + # Set any pre-processor directive needed in MPAS dycore. + get_mpas_version(MPAS_VERSION) + set(MPAS_ALL_CORES atmosphere) + 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() + set(DO_MPASDA OFF) + set(DO_PHYSICS FALSE) + + # Source files for MPAS dynamical core drivers. + set(MPAS_MAIN_SRC ${CMAKE_CURRENT_SOURCE_DIR}/mpas/ufs_mpas.F90) + set(MPAS_SUBDRIVER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/mpas/ufs_mpas_subdriver.F90) + + # MPAS NUOPC cap. + set(MPAS_NUOPC_CAP ${CMAKE_CURRENT_SOURCE_DIR}/mpas/mpas_cap.F90) + + # MPAS dynamical core + add_subdirectory(mpas) + + # MPAS drivers and dependencies + add_library(${DYCORE_TARGET} + ${MPAS_MAIN_SRC} + ${MPAS_SUBDRIVER_SRC} + ${MPAS_NUOPC_CAP} + ) + add_dependencies(${DYCORE_TARGET} mpas) endif() -target_link_libraries(fv3atm PUBLIC fv3 - fv3ccpp - stochastic_physics - fms) - -target_link_libraries(fv3atm PUBLIC w3emc::w3emc_d - sp::sp_d - bacio::bacio_4 - esmf) - -if(INLINE_POST) - target_link_libraries(fv3atm PUBLIC upp::upp) +############################################################################### +### Link libraries +############################################################################### +target_compile_definitions(${DYCORE_TARGET} PRIVATE "${_ufsatm_defs_private}") + +set_target_properties(${DYCORE_TARGET} PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod) +target_include_directories(${DYCORE_TARGET} INTERFACE $ + $) + +if (FV3) + target_link_libraries(${DYCORE_TARGET} PUBLIC fv3 + fv3ccpp + stochastic_physics + fms) + if(INLINE_POST) + target_link_libraries(${DYCORE_TARGET} PUBLIC upp::upp) + endif() endif() -if(OPENMP) - target_link_libraries(fv3atm PUBLIC OpenMP::OpenMP_Fortran) +if (MPAS) + target_link_libraries(${DYCORE_TARGET} PUBLIC mpas) +# mpasccpp +# stochastic_physics +# fms) endif() -if(BUILD_TESTING) - include(CTest) - add_subdirectory(tests) +# Always include EMC libraries in dycore install +target_link_libraries(${DYCORE_TARGET} PUBLIC w3emc::w3emc_d + sp::sp_d + bacio::bacio_4 + esmf) +# OpenMP +if(OPENMP) + target_link_libraries(${DYCORE_TARGET} PUBLIC OpenMP::OpenMP_Fortran) endif() ############################################################################### -### Install +### Install UFSATM ############################################################################### install( - TARGETS fv3atm - EXPORT fv3atm-config + TARGETS ${DYCORE_TARGET} + EXPORT ufsatm-config LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod DESTINATION ${CMAKE_INSTALL_PREFIX}) -install(EXPORT fv3atm-config +install(EXPORT ufsatm-config DESTINATION lib/cmake) diff --git a/ccpp/CMakeLists.txt b/ccpp/CMakeLists.txt index e9a5d56c7..86d416002 100644 --- a/ccpp/CMakeLists.txt +++ b/ccpp/CMakeLists.txt @@ -1,8 +1,49 @@ cmake_minimum_required(VERSION 3.0) -project(CCPP-FV3 +project(CCPP-UFS LANGUAGES C CXX Fortran) -set(PROJECT "CCPP-FV3") +set(PROJECT "CCPP-UFS") + +#------------------------------------------------------------------------------ +# Which dycore are we coupling the CCPP to? +#------------------------------------------------------------------------------ + +#------------------------------------------------------------------------------ +# FV3 dynamical core +#------------------------------------------------------------------------------ +if (FV3) + message(STATUS "Build CCPP interface to FV3 dynamical core") + set(CCPP_TARGET fv3ccpp) + set(CCPP_PREBUILD_CONFIG ../fv3/ccpp/config/ccpp_prebuild_config.py) + set(DYCORE_CCPP_SRCS + GFS_diagnostics.F90 + GFS_restart.F90 + GFS_init.F90 + CCPP_driver.F90 + ) + list(TRANSFORM DYCORE_CCPP_SRCS PREPEND ../ccpp/driver/) + + # Add dycore-specific preprocessor flag (needed for some physics schemes) + add_definitions(-DFV3) + +endif() + +#------------------------------------------------------------------------------ +# MPAS dynamical core +#------------------------------------------------------------------------------ +if (MPAS) + message(STATUS "Build CCPP interface to MPAS dynamical core") + set(CCPP_TARGET mpasccpp) + set(CCPP_PREBUILD_CONFIG ../mpas/ccpp/config/ccpp_prebuild_config.py) + set(DYCORE_CCPP_SRCS + GFS_diagnostics.F90 + GFS_restart.F90 + GFS_init.F90 + CCPP_driver.F90 + ) + list(TRANSFORM DYCORE_CCPP_SRCS PREPEND ../ccpp/driver/) + add_definitions(-DFV3) +endif() #------------------------------------------------------------------------------ # Set a default build type if none was specified @@ -29,7 +70,7 @@ else() endif() execute_process(COMMAND ${Python_EXECUTABLE} "framework/scripts/ccpp_prebuild.py" - "--config=config/ccpp_prebuild_config.py" + "--config=${CCPP_PREBUILD_CONFIG}" "--builddir=${CMAKE_CURRENT_BINARY_DIR}" ${_ccpp_suites_arg} ${_ccpp_debug_arg} ${_ccpp_verbose_arg} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/ccpp_prebuild.out @@ -40,10 +81,6 @@ if(NOT RC EQUAL 0) message(FATAL_ERROR "An error occured while running ccpp_prebuild.py, check ${CMAKE_CURRENT_BINARY_DIR}/ccpp_prebuild.{out,err}") endif() -#------------------------------------------------------------------------------ -# Add host-model specific preprocessor flag (needed for some physics schemes) -add_definitions(-DFV3) - #------------------------------------------------------------------------------ # Set MPI flags for C/C++/Fortran preprocessor if(MPI) @@ -103,43 +140,40 @@ add_subdirectory(framework) add_subdirectory(physics) #------------------------------------------------------------------------------ -# Build fv3ccpp +# Build CCPP_TARGET # Can we move data/*.F90 and driver/*.F90 to this directory ??? add_library( - fv3ccpp - - driver/GFS_diagnostics.F90 - driver/GFS_restart.F90 - driver/GFS_init.F90 - driver/CCPP_driver.F90 - + ${CCPP_TARGET} + ${DYCORE_CCPP_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/physics/ccpp_static_api.F90 ) # Compile GFS_diagnostics.F90 without optimization, this leads to out of memory errors on wcoss_dell_p3 -set_property(SOURCE driver/GFS_diagnostics.F90 APPEND_STRING PROPERTY COMPILE_FLAGS "-O0") +if (FV3) + set_property(SOURCE ../fv3/ccpp/driver/GFS_diagnostics.F90 APPEND_STRING PROPERTY COMPILE_FLAGS "-O0") +endif() -target_link_libraries(fv3ccpp PUBLIC ccpp_framework) -target_link_libraries(fv3ccpp PUBLIC ccpp_physics) +target_link_libraries(${CCPP_TARGET} PUBLIC ccpp_framework) +target_link_libraries(${CCPP_TARGET} PUBLIC ccpp_physics) if(OPENMP) - target_link_libraries(fv3ccpp PUBLIC OpenMP::OpenMP_Fortran) + target_link_libraries(${CCPP_TARGET} PUBLIC OpenMP::OpenMP_Fortran) endif() -set_target_properties(fv3ccpp PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod) -target_include_directories(fv3ccpp PUBLIC $) +set_target_properties(${CCPP_TARGET} PROPERTIES Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod) +target_include_directories(${CCPP_TARGET} PUBLIC $) ############################################################################### ### Install ############################################################################### install( - TARGETS fv3ccpp ccpp_framework ccpp_physics - EXPORT fv3ccpp-config + TARGETS ${CCPP_TARGET} ccpp_framework ccpp_physics + EXPORT ${CCPP_TARGET}-config LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod DESTINATION ${CMAKE_INSTALL_PREFIX}) -install(EXPORT fv3ccpp-config +install(EXPORT ${CCPP_TARGET}-config DESTINATION lib/cmake) diff --git a/atmos_cubed_sphere b/fv3/atmos_cubed_sphere similarity index 100% rename from atmos_cubed_sphere rename to fv3/atmos_cubed_sphere diff --git a/atmos_model.F90 b/fv3/atmos_model.F90 similarity index 100% rename from atmos_model.F90 rename to fv3/atmos_model.F90 diff --git a/ccpp/config/ccpp_prebuild_config.py b/fv3/ccpp/config/ccpp_prebuild_config.py similarity index 98% rename from ccpp/config/ccpp_prebuild_config.py rename to fv3/ccpp/config/ccpp_prebuild_config.py index 7714774fb..5bfed0cb4 100755 --- a/ccpp/config/ccpp_prebuild_config.py +++ b/fv3/ccpp/config/ccpp_prebuild_config.py @@ -21,9 +21,9 @@ 'physics/physics/Radiation/RRTMG/radlw_param.f', 'physics/physics/photochem/module_ozphys.F90', 'physics/physics/photochem/module_h2ophys.F90', - 'data/CCPP_typedefs.F90', - 'data/GFS_typedefs.F90', - 'data/CCPP_data.F90', + '../ccpp/data/CCPP_typedefs.F90', + '../ccpp/data/GFS_typedefs.F90', + '../ccpp/data/CCPP_data.F90' ] TYPEDEFS_NEW_METADATA = { @@ -233,7 +233,7 @@ CAPS_DIR = '{build_dir}/physics' # Directory where the suite definition files are stored -SUITES_DIR = 'suites' +SUITES_DIR = '../ccpp/suites' # Directory where to write static API to STATIC_API_DIR = '{build_dir}/physics' diff --git a/fv3_cap.F90 b/fv3/fv3_cap.F90 similarity index 100% rename from fv3_cap.F90 rename to fv3/fv3_cap.F90 diff --git a/module_fcst_grid_comp.F90 b/fv3/module_fcst_grid_comp.F90 similarity index 100% rename from module_fcst_grid_comp.F90 rename to fv3/module_fcst_grid_comp.F90 diff --git a/module_fv3_config.F90 b/fv3/module_fv3_config.F90 similarity index 100% rename from module_fv3_config.F90 rename to fv3/module_fv3_config.F90 diff --git a/moving_nest/bounding_box.F90 b/fv3/moving_nest/bounding_box.F90 similarity index 100% rename from moving_nest/bounding_box.F90 rename to fv3/moving_nest/bounding_box.F90 diff --git a/moving_nest/fv_moving_nest.F90 b/fv3/moving_nest/fv_moving_nest.F90 similarity index 100% rename from moving_nest/fv_moving_nest.F90 rename to fv3/moving_nest/fv_moving_nest.F90 diff --git a/moving_nest/fv_moving_nest_main.F90 b/fv3/moving_nest/fv_moving_nest_main.F90 similarity index 100% rename from moving_nest/fv_moving_nest_main.F90 rename to fv3/moving_nest/fv_moving_nest_main.F90 diff --git a/moving_nest/fv_moving_nest_physics.F90 b/fv3/moving_nest/fv_moving_nest_physics.F90 similarity index 100% rename from moving_nest/fv_moving_nest_physics.F90 rename to fv3/moving_nest/fv_moving_nest_physics.F90 diff --git a/moving_nest/fv_moving_nest_types.F90 b/fv3/moving_nest/fv_moving_nest_types.F90 similarity index 100% rename from moving_nest/fv_moving_nest_types.F90 rename to fv3/moving_nest/fv_moving_nest_types.F90 diff --git a/moving_nest/fv_moving_nest_utils.F90 b/fv3/moving_nest/fv_moving_nest_utils.F90 similarity index 100% rename from moving_nest/fv_moving_nest_utils.F90 rename to fv3/moving_nest/fv_moving_nest_utils.F90 diff --git a/moving_nest/fv_tracker.F90 b/fv3/moving_nest/fv_tracker.F90 similarity index 100% rename from moving_nest/fv_tracker.F90 rename to fv3/moving_nest/fv_tracker.F90 diff --git a/mpas/CMakeLists.txt b/mpas/CMakeLists.txt new file mode 100644 index 000000000..201fd903a --- /dev/null +++ b/mpas/CMakeLists.txt @@ -0,0 +1,131 @@ +cmake_minimum_required(VERSION 3.19) + +project(MPAS + VERSION 1.0.0 + LANGUAGES Fortran) + +include(${CMAKE_CURRENT_SOURCE_DIR}/MPAS-Model/cmake/Functions/MPAS_Functions.cmake) + +list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) +set(CMAKE_DIRECTORY_LABELS ${PROJECT_NAME}) +include(GNUInstallDirs) + +# 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() + +# 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() + +# 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}/) + +# Registry file. +set(REGISTRY_FILE ${CMAKE_CURRENT_SOURCE_DIR}/MPAS-Model/src/core_atmosphere/Registry.xml) + +############################################################################### +# Build MPAS libraries... +############################################################################### + +# MPAS Utilities (Externals) +add_subdirectory(MPAS-Model/src/external/ezxml) + +# ESMF libraries. +if(NOT ESMF_FOUND) + find_package(ESMF REQUIRED) +endif() +add_definitions(-DMPAS_EXTERNAL_ESMF_LIB -DMPAS_NO_ESMF_INIT) +add_library(${PROJECT_NAME}::external::esmf ALIAS esmf) + +# MPAS Namelist +add_subdirectory(MPAS-Model/src/tools/input_gen) # Targets: namelist_gen, streams_gen + +# MPAS Registry +add_subdirectory(MPAS-Model/src/tools/registry) # Targets: mpas_parse_ + +# MPAS framework +add_subdirectory(MPAS-Model/src/framework) # Target: MPAS::framework + +# MPAS operators +add_subdirectory(MPAS-Model/src/operators) # Target: MPAS::operators + +# MPAS atmosphere +add_subdirectory(MPAS-Model/src/core_atmosphere) # Target: core_atmosphere +add_library(mpas ALIAS core_atmosphere) + +############################################################################### +# Package Configurations +############################################################################### +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(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules DESTINATION ${CONFIG_INSTALL_DESTINATION}) + +#### +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( + MPAS-Model/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) + +### +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( + MPAS-Model/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}) + +### +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}) + +### +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/mpas/MPAS-Model b/mpas/MPAS-Model new file mode 160000 index 000000000..cd4f33faa --- /dev/null +++ b/mpas/MPAS-Model @@ -0,0 +1 @@ +Subproject commit cd4f33faa9b7713d3b1b83b066ad2ad26d33e0a9 diff --git a/mpas/ccpp/config/ccpp_prebuild_config.py b/mpas/ccpp/config/ccpp_prebuild_config.py new file mode 100755 index 000000000..cd77c15a4 --- /dev/null +++ b/mpas/ccpp/config/ccpp_prebuild_config.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python + +# CCPP prebuild config for MPAS - Model for Prediction Across Scales + + +############################################################################### +# Definitions # +############################################################################### + +HOST_MODEL_IDENTIFIER = "MPAS" + +# Add all files with metadata tables on the host model side and in CCPP, +# relative to basedir = top-level directory of host model. This includes +# kind and type definitions used in CCPP physics. Also add any internal +# dependencies of these files to the list. +VARIABLE_DEFINITION_FILES = [ + # actual variable definition files + 'framework/src/ccpp_types.F90', + 'physics/physics/hooks/machine.F', + 'physics/physics/Radiation/RRTMG/radsw_param.f', + 'physics/physics/Radiation/RRTMG/radlw_param.f', + 'physics/physics/photochem/module_ozphys.F90', + 'physics/physics/photochem/module_h2ophys.F90', + '../ccpp/data/CCPP_typedefs.F90', + '../ccpp/data/GFS_typedefs.F90', + '../ccpp/data/CCPP_data.F90' + ] + +TYPEDEFS_NEW_METADATA = { + 'ccpp_types' : { + 'ccpp_t' : 'cdata', + 'MPI_Comm' : '', + 'ccpp_types' : '', + }, + 'machine' : { + 'machine' : '', + }, + 'module_radlw_parameters' : { + 'module_radsw_parameters' : '', + }, + 'module_radlw_parameters' : { + 'module_radlw_parameters' : '', + }, + 'module_ozphys' : { + 'module_ozphys' : '', + 'ty_ozphys' : '', + }, + 'module_h2ophys' : { + 'module_h2ophys' : '', + 'ty_h2ophys' : '', + }, + 'CCPP_typedefs' : { + 'GFS_interstitial_type' : 'GFS_Interstitial(cdata%thrd_no)', + 'GFDL_interstitial_type' : 'GFDL_interstitial', + 'CCPP_typedefs' : '', + }, + 'CCPP_data' : { + 'CCPP_data' : '', + }, + 'GFS_typedefs' : { + 'GFS_control_type' : 'GFS_Control', + 'GFS_statein_type' : 'GFS_Statein', + 'GFS_stateout_type' : 'GFS_Stateout', + 'GFS_grid_type' : 'GFS_Grid', + 'GFS_tbd_type' : 'GFS_Tbd', + 'GFS_cldprop_type' : 'GFS_Cldprop', + 'GFS_sfcprop_type' : 'GFS_Sfcprop', + 'GFS_radtend_type' : 'GFS_Radtend', + 'GFS_coupling_type' : 'GFS_Coupling', + 'GFS_diag_type' : 'GFS_Intdiag', + 'GFS_typedefs' : '', + }, + } + +# Add all physics scheme files relative to basedir +SCHEME_FILES = [ + # Relative path to source (from where ccpp_prebuild.py is called) : [ list of physics sets in which scheme may be called ]; + # current restrictions are that each scheme can only belong to one physics set, and all schemes within one group in the + # suite definition file have to belong to the same physics set + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_DCNV_generic_pre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_DCNV_generic_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_GWD_generic_pre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_GWD_generic_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_pre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_MP_generic_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_pre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_PBL_generic_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_SCNV_generic_pre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_SCNV_generic_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_debug.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_phys_time_vary.fv3.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_photochemistry.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rad_time_vary.fv3.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_radiation_surface.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_pre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmg_setup.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_setup.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_pre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_cloud_diagnostics.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_mp.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_cloud_overlap.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_rrtmgp_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_stochastics.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_rad_reset.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_phys_reset.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_1.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_2.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_stateout_reset.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_stateout_update.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_3.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_4.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_suite_interstitial_5.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_surface_generic_pre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_surface_generic_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_surface_composites_pre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_surface_composites_inter.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_surface_composites_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_surface_loop_control_part1.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_surface_loop_control_part2.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_time_vary_pre.fv3.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/cnvc90.f', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/dcyc2t3.f', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/maximum_hourly_diagnostics.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/GFS_physics_post.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpre.F90', + 'physics/physics/Interstitials/UFS_SCM_NEPTUNE/sgscloud_radpost.F90', + 'physics/physics/CONV/Chikira_Sugiyama/cs_conv_pre.F90', + 'physics/physics/CONV/Chikira_Sugiyama/cs_conv.F90', + 'physics/physics/CONV/Chikira_Sugiyama/cs_conv_post.F90', + 'physics/physics/CONV/Chikira_Sugiyama/cs_conv_aw_adj.F90', + 'physics/physics/CONV/nTiedtke/cu_ntiedtke_pre.F90', + 'physics/physics/CONV/nTiedtke/cu_ntiedtke.F90', + 'physics/physics/CONV/nTiedtke/cu_ntiedtke_post.F90', + 'physics/physics/CONV/SAMF/samfdeepcnv.f', + 'physics/physics/CONV/SAMF/samfshalcnv.f', + 'physics/physics/CONV/SAS/sascnvn.F', + 'physics/physics/CONV/SAS/shalcnv.F', + 'physics/physics/CONV/Grell_Freitas/cu_gf_driver_pre.F90', + 'physics/physics/CONV/Grell_Freitas/cu_gf_driver.F90', + 'physics/physics/CONV/Grell_Freitas/cu_gf_driver_post.F90', + 'physics/physics/CONV/C3/cu_c3_driver_pre.F90', + 'physics/physics/CONV/C3/cu_c3_driver.F90', + 'physics/physics/CONV/C3/cu_c3_driver_post.F90', + 'physics/physics/CONV/RAS/rascnv.F90', + 'physics/physics/GWD/cires_ugwp.F90', + 'physics/physics/GWD/cires_ugwp_post.F90', + 'physics/physics/GWD/unified_ugwp.F90', + 'physics/physics/GWD/unified_ugwp_post.F90', + 'physics/physics/GWD/ugwpv1_gsldrag.F90', + 'physics/physics/GWD/ugwpv1_gsldrag_post.F90', + 'physics/physics/GWD/drag_suite.F90', + 'physics/physics/GWD/gwdc_pre.f', + 'physics/physics/GWD/gwdc.f', + 'physics/physics/GWD/gwdc_post.f', + 'physics/physics/GWD/gwdps.f', + 'physics/physics/GWD/rayleigh_damp.f', + 'physics/physics/photochem/module_h2ophys.F90', + 'physics/physics/photochem/module_ozphys.F90', + 'physics/physics/MP/Ferrier_Aligo/mp_fer_hires.F90', + 'physics/physics/MP/GFDL/gfdl_cloud_microphys.F90', + 'physics/physics/MP/GFDL/fv_sat_adj.F90', + 'physics/physics/MP/Morrison_Gettelman/m_micro.F90', + 'physics/physics/MP/Morrison_Gettelman/m_micro_pre.F90', + 'physics/physics/MP/Morrison_Gettelman/m_micro_post.F90', + 'physics/physics/MP/NSSL/mp_nssl.F90', + 'physics/physics/MP/Thompson/mp_thompson_pre.F90', + 'physics/physics/MP/Thompson/mp_thompson.F90', + 'physics/physics/MP/Thompson/mp_thompson_post.F90', + 'physics/physics/MP/Zhao_Carr/zhaocarr_gscond.f', + 'physics/physics/MP/Zhao_Carr/zhaocarr_precpd.f', + 'physics/physics/PBL/HEDMF/hedmf.f', + 'physics/physics/PBL/SHOC/moninshoc.f', + 'physics/physics/PBL/SHOC/shoc.F90', + 'physics/physics/PBL/MYJ/myjpbl_wrapper.F90', + 'physics/physics/PBL/MYNN_EDMF/mynnedmf_wrapper.F90', + 'physics/physics/PBL/SATMEDMF/satmedmfvdif.F', + 'physics/physics/PBL/SATMEDMF/satmedmfvdifq.F', + 'physics/physics/PBL/YSU/ysuvdif.F90', + 'physics/physics/PBL/saYSU/shinhongvdif.F90', + 'physics/physics/Radiation/RRTMG/radsw_main.F90', + 'physics/physics/Radiation/RRTMG/radlw_main.F90', + 'physics/physics/Radiation/RRTMG/rrtmg_lw_post.F90', + 'physics/physics/Radiation/RRTMG/rrtmg_sw_post.F90', + 'physics/physics/Radiation/RRTMG/rad_sw_pre.F90', + 'physics/physics/Radiation/RRTMGP/rrtmgp_aerosol_optics.F90', + 'physics/physics/Radiation/RRTMGP/rrtmgp_lw_main.F90', + 'physics/physics/Radiation/RRTMGP/rrtmgp_sw_main.F90', + 'physics/physics/SFC_Layer/GFDL/gfdl_sfc_layer.F90', + 'physics/physics/SFC_Layer/MYNN/mynnsfc_wrapper.F90', + 'physics/physics/SFC_Layer/MYJ/myjsfc_wrapper.F90', + 'physics/physics/SFC_Layer/UFS/sfc_diag.f', + 'physics/physics/SFC_Layer/UFS/sfc_diag_post.F90', + 'physics/physics/SFC_Layer/UFS/sfc_diff.f', + 'physics/physics/SFC_Layer/UFS/sfc_nst_pre.f90', + 'physics/physics/SFC_Layer/UFS/sfc_nst.f90', + 'physics/physics/SFC_Layer/UFS/sfc_nst_post.f90', + 'physics/physics/SFC_Models/Land/RUC/lsm_ruc.F90', + 'physics/physics/SFC_Models/SeaIce/CICE/sfc_cice.f', + 'physics/physics/SFC_Models/Land/sfc_land.F90', + 'physics/physics/SFC_Models/Land/Noah/lsm_noah.f', + 'physics/physics/SFC_Models/Land/Noahmp/noahmpdrv.F90', + 'physics/physics/SFC_Models/Lake/Flake/flake_driver.F90', + 'physics/physics/SFC_Models/Lake/CLM/clm_lake.f90', + 'physics/physics/SFC_Models/Ocean/UFS/sfc_ocean.F', + 'physics/physics/SFC_Models/SeaIce/CICE/sfc_sice.f', + 'physics/physics/smoke_dust/rrfs_smoke_wrapper.F90', + 'physics/physics/smoke_dust/rrfs_smoke_postpbl.F90', + 'physics/physics/tools/get_prs_fv3.F90', + 'physics/physics/tools/get_phi_fv3.F90' + ] + +# Default build dir, relative to current working directory, +# if not specified as command-line argument +DEFAULT_BUILD_DIR = 'build' + +# Auto-generated makefile/cmakefile snippets that contain all type definitions +TYPEDEFS_MAKEFILE = '{build_dir}/physics/CCPP_TYPEDEFS.mk' +TYPEDEFS_CMAKEFILE = '{build_dir}/physics/CCPP_TYPEDEFS.cmake' +TYPEDEFS_SOURCEFILE = '{build_dir}/physics/CCPP_TYPEDEFS.sh' + +# Auto-generated makefile/cmakefile snippets that contain all schemes +SCHEMES_MAKEFILE = '{build_dir}/physics/CCPP_SCHEMES.mk' +SCHEMES_CMAKEFILE = '{build_dir}/physics/CCPP_SCHEMES.cmake' +SCHEMES_SOURCEFILE = '{build_dir}/physics/CCPP_SCHEMES.sh' + +# Auto-generated makefile/cmakefile snippets that contain all caps +CAPS_MAKEFILE = '{build_dir}/physics/CCPP_CAPS.mk' +CAPS_CMAKEFILE = '{build_dir}/physics/CCPP_CAPS.cmake' +CAPS_SOURCEFILE = '{build_dir}/physics/CCPP_CAPS.sh' + +# Directory where to put all auto-generated physics caps +CAPS_DIR = '{build_dir}/physics' + +# Directory where the suite definition files are stored +SUITES_DIR = '../ccpp/suites' + +# Directory where to write static API to +STATIC_API_DIR = '{build_dir}/physics' +STATIC_API_CMAKEFILE = '{build_dir}/physics/CCPP_STATIC_API.cmake' +STATIC_API_SOURCEFILE = '{build_dir}/physics/CCPP_STATIC_API.sh' + +# Directory for writing HTML pages generated from metadata files +# used by metadata2html.py for generating scientific documentation +METADATA_HTML_OUTPUT_DIR = '{build_dir}/physics/physics/docs' + +# HTML document containing the model-defined CCPP variables +HTML_VARTABLE_FILE = '{build_dir}/physics/CCPP_VARIABLES_FV3.html' + +# LaTeX document containing the provided vs requested CCPP variables +LATEX_VARTABLE_FILE = '{build_dir}/framework/doc/DevelopersGuide/CCPP_VARIABLES_FV3.tex' diff --git a/mpas/mpas_cap.F90 b/mpas/mpas_cap.F90 new file mode 100644 index 000000000..c886ee375 --- /dev/null +++ b/mpas/mpas_cap.F90 @@ -0,0 +1,19 @@ +!--------------- MPAS ATM solo model ---------------- +! +!*** The MPAS atmosphere grid component nuopc cap +! +module mpasatm_cap_mod + use ESMF + use NUOPC + implicit none + ! +!----------------------------------------------------------------------- +! Module parameters +!----------------------------------------------------------------------- + +contains + + subroutine SetServices() + end subroutine SetServices + +end module mpasatm_cap_mod diff --git a/mpas/ufs_mpas.F90 b/mpas/ufs_mpas.F90 new file mode 100644 index 000000000..9e9e02ec0 --- /dev/null +++ b/mpas/ufs_mpas.F90 @@ -0,0 +1,26 @@ +! Copyright (c) 2013, Los Alamos National Security, LLC (LANS) +! and the University Corporation for Atmospheric Research (UCAR). +! +! Unless noted otherwise source code is licensed under the BSD license. +! Additional copyright and license information can be found in the LICENSE file +! distributed with this code, or at http://mpas-dev.github.com/license.html +! +program ufs_mpas + + use ufs_mpas_subdriver + use mpas_derived_types, only : core_type, domain_type + + implicit none + + type (core_type), pointer :: corelist => null() + type (domain_type), pointer :: domain => null() + + call mpas_init(corelist, domain) + + call mpas_run(domain) + + call mpas_finalize(corelist, domain) + + stop + +end program ufs_mpas diff --git a/mpas/ufs_mpas_subdriver.F90 b/mpas/ufs_mpas_subdriver.F90 new file mode 100644 index 000000000..a773421ff --- /dev/null +++ b/mpas/ufs_mpas_subdriver.F90 @@ -0,0 +1,560 @@ +! Copyright (c) 2013, Los Alamos National Security, LLC (LANS) +! and the University Corporation for Atmospheric Research (UCAR). +! +! Unless noted otherwise source code is licensed under the BSD license. +! Additional copyright and license information can be found in the LICENSE file +! distributed with this code, or at http://mpas-dev.github.com/license.html +! +module ufs_mpas_subdriver + + use mpas_framework + use mpas_kind_types + use mpas_abort, only : mpas_dmpar_global_abort + + use mpas_derived_types, only: dm_info, domain_type + +#ifdef CORE_ATMOSPHERE + use atm_core_interface +#endif +#ifdef CORE_SEAICE + use seaice_core_interface +#endif +#ifdef CORE_INIT_ATMOSPHERE + use init_atm_core_interface +#endif +#ifdef CORE_LANDICE + use li_core_interface +#endif +#ifdef CORE_OCEAN + use ocn_core_interface +#endif +#ifdef CORE_SW + use sw_core_interface +#endif +#ifdef CORE_TEST + use test_core_interface +#endif + + + contains + + + subroutine mpas_init(corelist, domain_ptr, external_comm, namelistFileParam, streamsFileParam) + +#ifdef MPAS_USE_MPI_F08 + use mpi_f08, only : MPI_Comm +#endif + 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 + use mpas_c_interfacing, only : mpas_f_to_c_string, mpas_c_to_f_string + use mpas_timekeeping, only : mpas_get_clock_time, mpas_get_time + use mpas_bootstrapping, only : mpas_bootstrap_framework_phase1, mpas_bootstrap_framework_phase2 + use mpas_log + use mpas_stream_inquiry, only : MPAS_stream_inquiry_new_streaminfo + + implicit none + + type (core_type), intent(inout), pointer :: corelist + type (domain_type), intent(inout), pointer :: domain_ptr +#ifdef MPAS_USE_MPI_F08 + type (MPI_Comm), intent(in), optional :: external_comm +#else + integer, intent(in), optional :: external_comm +#endif + character(len=*), intent(in), optional :: namelistFileParam + character(len=*), intent(in), optional :: streamsFileParam + + integer :: iArg, nArgs + logical :: readNamelistArg, readStreamsArg + character(len=StrKIND) :: argument, namelistFile, streamsFile + character(len=StrKIND) :: timeStamp + integer :: ierr + integer :: blockID + + character(kind=c_char), dimension(StrKIND+1) :: c_filename ! StrKIND+1 for C null-termination character + integer(kind=c_int) :: c_comm + integer(kind=c_int) :: c_ierr + type (c_ptr) :: mgr_p + character(len=StrKIND) :: mesh_stream + character(len=StrKIND) :: mesh_filename + character(len=StrKIND) :: mesh_filename_temp + character(len=StrKIND) :: ref_time_temp + character(len=StrKIND) :: filename_interval_temp + character(kind=c_char), dimension(StrKIND+1) :: c_mesh_stream + character(kind=c_char), dimension(StrKIND+1) :: c_mesh_filename_temp + character(kind=c_char), dimension(StrKIND+1) :: c_ref_time_temp + character(kind=c_char), dimension(StrKIND+1) :: c_filename_interval_temp + character(kind=c_char), dimension(StrKIND+1) :: c_iotype + type (MPAS_Time_type) :: start_time + type (MPAS_Time_type) :: ref_time + type (MPAS_TimeInterval_type) :: filename_interval + character(len=StrKIND) :: start_timestamp + character(len=StrKIND) :: iotype + logical :: streamsExists + integer :: mesh_iotype + integer, save :: domainID = 0 + + interface + subroutine xml_stream_parser(xmlname, mgr_p, comm, ierr) bind(c) + use iso_c_binding, only : c_char, c_ptr, c_int + character(kind=c_char), dimension(*), intent(in) :: xmlname + type (c_ptr), intent(inout) :: mgr_p + integer(kind=c_int), intent(inout) :: comm + integer(kind=c_int), intent(out) :: ierr + end subroutine xml_stream_parser + + subroutine xml_stream_get_attributes(xmlname, streamname, comm, filename, ref_time, filename_interval, io_type, ierr) bind(c) + use iso_c_binding, only : c_char, c_int + character(kind=c_char), dimension(*), intent(in) :: xmlname + character(kind=c_char), dimension(*), intent(in) :: streamname + integer(kind=c_int), intent(inout) :: comm + character(kind=c_char), dimension(*), intent(out) :: filename + character(kind=c_char), dimension(*), intent(out) :: ref_time + character(kind=c_char), dimension(*), intent(out) :: filename_interval + character(kind=c_char), dimension(*), intent(out) :: io_type + integer(kind=c_int), intent(out) :: ierr + end subroutine xml_stream_get_attributes + end interface + + readNamelistArg = .false. + readStreamsArg = .false. + + ! If provided, error check the namelistFileParam and copy it to namelistFile to override default + if (present(namelistFileParam)) then + if (len_trim(namelistFileParam) == 0) then + write (0,*) 'WARNING: mpas_init argument namelistFileParam has 0 length and will be ignored' + else if (len_trim(namelistFileParam) > len(namelistFile)) then + write(0,'(A,I5,A,I5,A)') 'CRITICAL ERROR: mpas_init argument ''namelistFileParam'' has length ',& + len_trim(namelistFileParam), ', but the maximum allowed is ', len(namelistFile), ' characters' + stop + else + readNamelistArg = .true. + namelistFile = trim(namelistFileParam) + end if + end if + ! If provided, error check the streamsFileParam and copy it to streamsFile to override default + if (present(streamsFileParam)) then + if (len_trim(streamsFileParam) == 0) then + write (0,*) 'WARNING: mpas_init argument streamsFileParam has 0 length and will be ignored' + else if (len_trim(streamsFileParam) > len(streamsFile)) then + write(0,'(A,I5,A,I5,A)') 'CRITICAL ERROR: mpas_init argument ''streamsFileParam'' has length ',& + len_trim(streamsFileParam), ', but the maximum allowed is ', len(streamsFile), ' characters' + stop + else + readStreamsArg = .true. + streamsFile = trim(streamsFileParam) + end if + end if + + ! If optional arguments weren't used, parse the command-line arguments for -n and -s + if (.not. (present(namelistFileParam) .or. present(streamsFileParam))) then + nArgs = command_argument_count() + iArg = 1 + do while (iArg < nArgs) + call get_command_argument(iArg, argument) + if (len_trim(argument) == 0) exit + + if ( trim(argument) == '-n' ) then + iArg = iArg + 1 + readNamelistArg = .true. + call get_command_argument(iArg, namelistFile) + if ( len_trim(namelistFile) == 0 ) then + write(0,*) 'ERROR: The -n argument requires a namelist file argument.' + stop + else if ( trim(namelistFile) == '-s' ) then + write(0,*) 'ERROR: The -n argument requires a namelist file argument.' + stop + end if + else if ( trim(argument) == '-s' ) then + iArg = iArg + 1 + readStreamsArg = .true. + call get_command_argument(iArg, streamsFile) + if ( len_trim(streamsFile) == 0 ) then + write(0,*) 'ERROR: The -s argument requires a streams file argument.' + stop + else if ( trim(streamsFile) == '-n' ) then + write(0,*) 'ERROR: The -s argument requires a streams file argument.' + stop + end if + end if + + iArg = iArg + 1 + end do + end if + + allocate(corelist) + nullify(corelist % next) + + allocate(corelist % domainlist) + nullify(corelist % domainlist % next) + + domain_ptr => corelist % domainlist + domain_ptr % core => corelist + + call mpas_allocate_domain(domain_ptr) + + domain_ptr % domainID = domainID + domainID = domainID + 1 + + ! + ! Initialize infrastructure + ! + call mpas_framework_init_phase1(domain_ptr % dminfo, external_comm=external_comm) + + +#ifdef CORE_ATMOSPHERE + call atm_setup_core(corelist) + call atm_setup_domain(domain_ptr) +#endif +#ifdef CORE_SEAICE + call seaice_setup_core(corelist) + call seaice_setup_domain(domain_ptr) +#endif +#ifdef CORE_INIT_ATMOSPHERE + call init_atm_setup_core(corelist) + call init_atm_setup_domain(domain_ptr) +#endif +#ifdef CORE_LANDICE + call li_setup_core(corelist) + call li_setup_domain(domain_ptr) +#endif +#ifdef CORE_OCEAN + call ocn_setup_core(corelist) + call ocn_setup_domain(domain_ptr) +#endif +#ifdef CORE_SW + call sw_setup_core(corelist) + call sw_setup_domain(domain_ptr) +#endif +#ifdef CORE_TEST + call test_setup_core(corelist) + call test_setup_domain(domain_ptr) +#endif + + ! Set up the log manager as early as possible so we can use it for any errors/messages during subsequent init steps + ! We need: + ! 1) domain_ptr to be allocated, + ! 2) dmpar_init complete to access dminfo, + ! 3) *_setup_core to assign the setup_log function pointer + ierr = domain_ptr % core % setup_log(domain_ptr % logInfo, domain_ptr) + if ( ierr /= 0 ) then + call mpas_dmpar_global_abort('ERROR: Log setup failed for core ' // trim(domain_ptr % core % coreName)) + end if + + if ( readNamelistArg ) then + domain_ptr % namelist_filename = namelistFile + end if + + if ( readStreamsArg ) then + domain_ptr % streams_filename = streamsFile + end if + + ierr = domain_ptr % core % setup_namelist(domain_ptr % configs, domain_ptr % namelist_filename, domain_ptr % dminfo) + if ( ierr /= 0 ) then + call mpas_log_write('Namelist setup failed for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + call mpas_framework_init_phase2(domain_ptr) + + ! + ! Before defining packages, initialize the stream inquiry instance for the domain + ! + domain_ptr % streamInfo => MPAS_stream_inquiry_new_streaminfo() + if (.not. associated(domain_ptr % streamInfo)) then + call mpas_log_write('Failed to instantiate streamInfo object for core '//trim(domain_ptr % core % coreName), & + messageType=MPAS_LOG_CRIT) + end if + if (domain_ptr % streamInfo % init(domain_ptr % dminfo % comm, domain_ptr % streams_filename) /= 0) then + call mpas_log_write('Initialization of streamInfo object failed for core '//trim(domain_ptr % core % coreName), & + messageType=MPAS_LOG_CRIT) + end if + + ierr = domain_ptr % core % define_packages(domain_ptr % packages) + if ( ierr /= 0 ) then + call mpas_log_write('Package definition failed for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + ierr = domain_ptr % core % setup_packages(domain_ptr % configs, domain_ptr % streamInfo, domain_ptr % packages, & + domain_ptr % iocontext) + if ( ierr /= 0 ) then + call mpas_log_write('Package setup failed for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + ierr = domain_ptr % core % setup_decompositions(domain_ptr % decompositions) + if ( ierr /= 0 ) then + call mpas_log_write('Decomposition setup failed for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + ierr = domain_ptr % core % setup_clock(domain_ptr % clock, domain_ptr % configs) + if ( ierr /= 0 ) then + call mpas_log_write('Clock setup failed for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + call mpas_log_write('Reading streams configuration from file '//trim(domain_ptr % streams_filename)) + inquire(file=trim(domain_ptr % streams_filename), exist=streamsExists) + + if ( .not. streamsExists ) then + call mpas_log_write('Streams file '//trim(domain_ptr % streams_filename)//' does not exist.', messageType=MPAS_LOG_CRIT) + end if + + call mpas_timer_start('total time') + call mpas_timer_start('initialize') + + ! + ! Using information from the namelist, a graph.info file, and a file containing + ! mesh fields, build halos and allocate blocks in the domain + ! + ierr = domain_ptr % core % get_mesh_stream(domain_ptr % configs, domain_ptr % streamInfo, mesh_stream) + if ( ierr /= 0 ) then + call mpas_log_write('Failed to find mesh stream for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + call mpas_f_to_c_string(domain_ptr % streams_filename, c_filename) + call mpas_f_to_c_string(mesh_stream, c_mesh_stream) +#ifdef MPAS_USE_MPI_F08 + c_comm = domain_ptr % dminfo % comm % mpi_val +#else + c_comm = domain_ptr % dminfo % comm +#endif + call xml_stream_get_attributes(c_filename, c_mesh_stream, c_comm, & + c_mesh_filename_temp, c_ref_time_temp, & + c_filename_interval_temp, c_iotype, c_ierr) + if (c_ierr /= 0) then + call mpas_log_write('stream xml get attribute failed: '//trim(domain_ptr % streams_filename), messageType=MPAS_LOG_CRIT) + end if + call mpas_c_to_f_string(c_mesh_filename_temp, mesh_filename_temp) + call mpas_c_to_f_string(c_ref_time_temp, ref_time_temp) + call mpas_c_to_f_string(c_filename_interval_temp, filename_interval_temp) + call mpas_c_to_f_string(c_iotype, iotype) + + if (trim(iotype) == 'pnetcdf') then + mesh_iotype = MPAS_IO_PNETCDF + else if (trim(iotype) == 'pnetcdf,cdf5') then + mesh_iotype = MPAS_IO_PNETCDF5 + else if (trim(iotype) == 'netcdf') then + mesh_iotype = MPAS_IO_NETCDF + else if (trim(iotype) == 'netcdf4') then + mesh_iotype = MPAS_IO_NETCDF4 + else + mesh_iotype = MPAS_IO_PNETCDF + end if + + start_time = mpas_get_clock_time(domain_ptr % clock, MPAS_START_TIME, ierr) + if ( trim(ref_time_temp) == 'initial_time' ) then + call mpas_get_time(start_time, dateTimeString=ref_time_temp, ierr=ierr) + end if + + blockID = -1 + if ( trim(filename_interval_temp) == 'none' ) then + call mpas_expand_string(ref_time_temp, blockID, mesh_filename_temp, mesh_filename) + else + call mpas_set_time(ref_time, dateTimeString=ref_time_temp, ierr=ierr) + call mpas_set_timeInterval(filename_interval, timeString=filename_interval_temp, ierr=ierr) + call mpas_build_stream_filename(ref_time, start_time, filename_interval, mesh_filename_temp, blockID, mesh_filename, ierr) + end if + call mpas_log_write(' ** Attempting to bootstrap MPAS framework using stream: ' // trim(mesh_stream)) + call mpas_bootstrap_framework_phase1(domain_ptr, mesh_filename, mesh_iotype) + + ! + ! Set up run-time streams + ! + call MPAS_stream_mgr_init(domain_ptr % streamManager, domain_ptr % ioContext, domain_ptr % clock, & + domain_ptr % blocklist % allFields, domain_ptr % packages, domain_ptr % blocklist % allStructs) + + call add_stream_attributes(domain_ptr) + + ierr = domain_ptr % core % setup_immutable_streams(domain_ptr % streamManager) + if ( ierr /= 0 ) then + call mpas_log_write('Immutable streams setup failed for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + mgr_p = c_loc(domain_ptr % streamManager) + call xml_stream_parser(c_filename, mgr_p, c_comm, c_ierr) + if (c_ierr /= 0) then + call mpas_log_write('xml stream parser failed: '//trim(domain_ptr % streams_filename), messageType=MPAS_LOG_CRIT) + end if + + ! + ! Validate streams after set-up + ! + call mpas_log_write(' ** Validating streams') + call MPAS_stream_mgr_validate_streams(domain_ptr % streamManager, ierr = ierr) + if ( ierr /= MPAS_STREAM_MGR_NOERR ) then + call mpas_dmpar_global_abort('ERROR: Validation of streams failed for core ' // trim(domain_ptr % core % coreName)) + end if + + ! + ! Finalize the setup of blocks and fields + ! + call mpas_bootstrap_framework_phase2(domain_ptr) + + ! + ! Initialize core + ! + iErr = domain_ptr % core % core_init(domain_ptr, timeStamp) + if ( ierr /= 0 ) then + call mpas_log_write('Core init failed for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + call mpas_timer_stop('initialize') + + end subroutine mpas_init + + + subroutine mpas_run(domain_ptr) + + use mpas_log, only: mpas_log_info + + implicit none + + type (domain_type), intent(inout), pointer :: domain_ptr + + integer :: iErr + + if ( associated(domain_ptr % logInfo) ) mpas_log_info => domain_ptr % logInfo + + iErr = domain_ptr % core % core_run(domain_ptr) + if ( iErr /= 0 ) then + call mpas_log_write('Core run failed for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + end subroutine mpas_run + + + subroutine mpas_finalize(corelist, domain_ptr) + + use mpas_stream_manager, only : MPAS_stream_mgr_finalize + use mpas_log, only : mpas_log_finalize, mpas_log_info + use mpas_derived_types, only : MPAS_streamInfo_type + + implicit none + + type (core_type), intent(inout), pointer :: corelist + type (domain_type), intent(inout), pointer :: domain_ptr + + integer :: iErr + type (MPAS_streamInfo_type), pointer :: streamInfo + + + ! + ! Finalize core + ! + iErr = domain_ptr % core % core_finalize(domain_ptr) + if ( iErr /= 0 ) then + call mpas_log_write('Core finalize failed for core '//trim(domain_ptr % core % coreName), messageType=MPAS_LOG_CRIT) + end if + + call mpas_timer_stop('total time') + call mpas_timer_write_header() + call mpas_timer_write() + call mpas_timer_finalize(domain_ptr) + + ! + ! Finalize infrastructure + ! + call MPAS_stream_mgr_finalize(domain_ptr % streamManager) + + streamInfo => domain_ptr % streamInfo + if (streamInfo % finalize() /= 0) then + call mpas_log_write('Finalization of streamInfo object failed for core '//trim(domain_ptr % core % coreName), & + messageType=MPAS_LOG_ERR) + end if + deallocate(domain_ptr % streamInfo) + + ! Print out log stats and close log file + ! (Do this after timer stats are printed and stream mgr finalized, + ! but before framework is finalized because domain is destroyed there.) + if ( associated(domain_ptr % logInfo) ) mpas_log_info => domain_ptr % logInfo + + call mpas_log_finalize(iErr) + if ( iErr /= 0 ) then + call mpas_dmpar_global_abort('ERROR: Log finalize failed for core ' // trim(domain_ptr % core % coreName)) + end if + + call mpas_framework_finalize(domain_ptr % dminfo, domain_ptr) + + deallocate(corelist % domainlist) + deallocate(corelist) + + end subroutine mpas_finalize + + + subroutine add_stream_attributes(domain) + + use mpas_stream_manager, only : MPAS_stream_mgr_add_att + + implicit none + + type (domain_type), intent(inout) :: domain + + type (MPAS_Pool_iterator_type) :: itr + integer, pointer :: intAtt + logical, pointer :: logAtt + character (len=StrKIND), pointer :: charAtt + real (kind=RKIND), pointer :: realAtt + character (len=StrKIND) :: histAtt + + integer :: local_ierr + + if (domain % dminfo % nProcs < 10) then + write(histAtt, '(A,I1,A,A,A)') 'mpirun -n ', domain % dminfo % nProcs, ' ./', trim(domain % core % coreName), '_model' + else if (domain % dminfo % nProcs < 100) then + write(histAtt, '(A,I2,A,A,A)') 'mpirun -n ', domain % dminfo % nProcs, ' ./', trim(domain % core % coreName), '_model' + else if (domain % dminfo % nProcs < 1000) then + write(histAtt, '(A,I3,A,A,A)') 'mpirun -n ', domain % dminfo % nProcs, ' ./', trim(domain % core % coreName), '_model' + else if (domain % dminfo % nProcs < 10000) then + write(histAtt, '(A,I4,A,A,A)') 'mpirun -n ', domain % dminfo % nProcs, ' ./', trim(domain % core % coreName), '_model' + else if (domain % dminfo % nProcs < 100000) then + write(histAtt, '(A,I5,A,A,A)') 'mpirun -n ', domain % dminfo % nProcs, ' ./', trim(domain % core % coreName), '_model' + else + write(histAtt, '(A,I6,A,A,A)') 'mpirun -n ', domain % dminfo % nProcs, ' ./', trim(domain % core % coreName), '_model' + end if + + call MPAS_stream_mgr_add_att(domain % streamManager, 'model_name', domain % core % modelName) + call MPAS_stream_mgr_add_att(domain % streamManager, 'core_name', domain % core % coreName) + call MPAS_stream_mgr_add_att(domain % streamManager, 'source', domain % core % source) + call MPAS_stream_mgr_add_att(domain % streamManager, 'Conventions', domain % core % Conventions) + call MPAS_stream_mgr_add_att(domain % streamManager, 'git_version', domain % core % git_version) + + call MPAS_stream_mgr_add_att(domain % streamManager, 'on_a_sphere', domain % on_a_sphere) + call MPAS_stream_mgr_add_att(domain % streamManager, 'sphere_radius', domain % sphere_radius) + call MPAS_stream_mgr_add_att(domain % streamManager, 'is_periodic', domain % is_periodic) + call MPAS_stream_mgr_add_att(domain % streamManager, 'x_period', domain % x_period) + call MPAS_stream_mgr_add_att(domain % streamManager, 'y_period', domain % y_period) + ! DWJ 10/01/2014: Eventually add the real history attribute, for now (due to length restrictions) + ! add a shortened version. +! call MPAS_stream_mgr_add_att(domain % streamManager, 'history', domain % history) + call MPAS_stream_mgr_add_att(domain % streamManager, 'history', histAtt) + call MPAS_stream_mgr_add_att(domain % streamManager, 'parent_id', domain % parent_id) + call MPAS_stream_mgr_add_att(domain % streamManager, 'mesh_spec', domain % mesh_spec) + + call mpas_pool_begin_iteration(domain % configs) + + do while (mpas_pool_get_next_member(domain % configs, itr)) + + if ( itr % memberType == MPAS_POOL_CONFIG) then + + if ( itr % dataType == MPAS_POOL_REAL ) then + call mpas_pool_get_config(domain % configs, itr % memberName, realAtt) + call MPAS_stream_mgr_add_att(domain % streamManager, itr % memberName, realAtt, ierr=local_ierr) + else if ( itr % dataType == MPAS_POOL_INTEGER ) then + call mpas_pool_get_config(domain % configs, itr % memberName, intAtt) + call MPAS_stream_mgr_add_att(domain % streamManager, itr % memberName, intAtt, ierr=local_ierr) + else if ( itr % dataType == MPAS_POOL_CHARACTER ) then + call mpas_pool_get_config(domain % configs, itr % memberName, charAtt) + call MPAS_stream_mgr_add_att(domain % streamManager, itr % memberName, charAtt, ierr=local_ierr) + else if ( itr % dataType == MPAS_POOL_LOGICAL ) then + call mpas_pool_get_config(domain % configs, itr % memberName, logAtt) + if (logAtt) then + call MPAS_stream_mgr_add_att(domain % streamManager, itr % memberName, 'YES', ierr=local_ierr) + else + call MPAS_stream_mgr_add_att(domain % streamManager, itr % memberName, 'NO', ierr=local_ierr) + end if + end if + + end if + end do + + end subroutine add_stream_attributes + +end module ufs_mpas_subdriver