diff --git a/.github/workflows/capgen_unit_tests.yaml b/.github/workflows/capgen_unit_tests.yaml index 820553af..15c7ca9b 100644 --- a/.github/workflows/capgen_unit_tests.yaml +++ b/.github/workflows/capgen_unit_tests.yaml @@ -15,7 +15,34 @@ jobs: steps: - uses: actions/checkout@v3 - name: update repos and install dependencies - run: sudo apt-get update && sudo apt-get install -y build-essential ${{matrix.fortran-compiler}} cmake python3 git libxml2-utils + run: sudo apt-get update && sudo apt-get install -y build-essential libopenmpi-dev ${{matrix.fortran-compiler}} cmake python3 git libxml2-utils + + - name: Build pFUnit + run: | + git clone --depth 1 --branch v4.10.0 https://github.com/Goddard-Fortran-Ecosystem/pFUnit.git + cd pFUnit + cmake -B./build -S. + cd build + make install + + - name: Build the framework + run: | + cmake -S. -B./build \ + -DCCPP_FRAMEWORK_ENABLE_TESTS=ON \ + -DCMAKE_PREFIX_PATH=/home/runner/work/ccpp-framework/ccpp-framework/pFUnit/build/installed + cd build + make + - name: Run unit tests - run: cd test && ./run_fortran_tests.sh + run: | + cd build + ctest --rerun-failed --output-on-failure . --verbose + - name: Run python tests + run: | + pip install --user pytest + BUILD_DIR=./build pytest \ + test/capgen_test/capgen_test_reports.py \ + test/advection_test/advection_test_reports.py \ + test/ddthost_test/ddthost_test_reports.py \ + test/var_compatibility_test/var_compatibility_test_reports.py diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 100192cd..00000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: python - -python: - - "3.6" - - "3.7" - - "3.8" - - "3.9" - -branches: - only: - - feature/capgen - -install: - - pip install pylint - -script: - - env PYTHONPATH=scripts:${PYTHONPATH} pylint --rcfile ./test/.pylintrc ./test/unit_tests/test_metadata_table.py - - env PYTHONPATH=scripts:${PYTHONPATH} pylint --rcfile ./test/.pylintrc ./test/unit_tests/test_metadata_scheme_file.py - - python test/unit_tests/test_metadata_table.py - - python test/unit_tests/test_metadata_scheme_file.py - -notifications: - email: - recipients: - - dom.heinzeller@noaa.gov - - goldy@ucar.edu - on_success: always # default: change - on_failure: always # default: always diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d03783d..a595429e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,33 +4,83 @@ project(ccpp_framework VERSION 5.0.0 LANGUAGES Fortran) +enable_language(C CXX) +include(FetchContent) +include(cmake/ccpp_capgen.cmake) +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${PROJECT_SOURCE_DIR}/cmake") + + #------------------------------------------------------------------------------ # Set package definitions set(PACKAGE "ccpp-framework") set(AUTHORS "Dom Heinzeller" "Grant Firl" "Mike Kavulich" "Dustin Swales" "Courtney Peverley") string(TIMESTAMP YEAR "%Y") +option(CCPP_FRAMEWORK_BUILD_DOCUMENTATION + "Create and install the HTML documentation (requires Doxygen)" OFF) +option(CCPP_FRAMEWORK_ENABLE_OPENMP "Enable OpenMP support for the framework" OFF) +option(CCPP_FRAMEWORK_ENABLE_TESTS "Enable building/running tests" OFF) +option(BUILD_SHARED_LIBS "Build a static library" OFF) +set(CCPP_VERBOSITY "0" CACHE STRING "Verbosity level of output (default: 0)") + +if(CCPP_FRAMEWORK_ENABLE_TESTS) + ADD_COMPILE_OPTIONS(-O0) + if(${CMAKE_Fortran_COMPILER_ID} STREQUAL "GNU") + ADD_COMPILE_OPTIONS(-fcheck=all) + ADD_COMPILE_OPTIONS(-fbacktrace) + ADD_COMPILE_OPTIONS(-ffpe-trap=zero) + ADD_COMPILE_OPTIONS(-finit-real=nan) + ADD_COMPILE_OPTIONS(-ggdb) + ADD_COMPILE_OPTIONS(-ffree-line-length-none) + ADD_COMPILE_OPTIONS(-cpp) + elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "Intel") + ADD_COMPILE_OPTIONS(-fpe0) + ADD_COMPILE_OPTIONS(-warn) + ADD_COMPILE_OPTIONS(-traceback) + ADD_COMPILE_OPTIONS(-debug extended) + ADD_COMPILE_OPTIONS(-fpp) + elseif(${CMAKE_Fortran_COMPILER_ID} STREQUAL "IntelLLVM") + ADD_COMPILE_OPTIONS(-fpe0) + ADD_COMPILE_OPTIONS(-warn) + ADD_COMPILE_OPTIONS(-traceback) + ADD_COMPILE_OPTIONS(-debug full) + ADD_COMPILE_OPTIONS(-fpp) + elseif (${CMAKE_Fortran_COMPILER_ID} STREQUAL "NVIDIA" OR ${CMAKE_Fortran_COMPILER_ID} STREQUAL "NVHPC") + ADD_COMPILE_OPTIONS(-g) + ADD_COMPILE_OPTIONS(-Mnoipa) + ADD_COMPILE_OPTIONS(-traceback) + ADD_COMPILE_OPTIONS(-Mfree) + ADD_COMPILE_OPTIONS(-Ktrap=fp) + ADD_COMPILE_OPTIONS(-Mpreprocess) + else() + message (WARNING "This program has only been compiled with gfortran and ifx.") + endif() +endif() + +# Use rpaths on MacOSX +set(CMAKE_MACOSX_RPATH 1) + #------------------------------------------------------------------------------ # Set MPI flags for Fortran with MPI F08 interface -find_package(MPI REQUIRED Fortran) +find_package(MPI REQUIRED COMPONENTS Fortran) if(NOT MPI_Fortran_HAVE_F08_MODULE) message(FATAL_ERROR "MPI implementation does not support the Fortran 2008 mpi_f08 interface") endif() #------------------------------------------------------------------------------ # Set OpenMP flags for C/C++/Fortran -if (OPENMP) +if(CCPP_FRAMEWORK_ENABLE_OPENMP) find_package(OpenMP REQUIRED) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}") -endif (OPENMP) +endif() #------------------------------------------------------------------------------ # Set a default build type if none was specified if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Release' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "Coverage") endif() #------------------------------------------------------------------------------ @@ -39,11 +89,21 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug") add_definitions(-DDEBUG) endif() -#------------------------------------------------------------------------------ -# Request a static build -option(BUILD_SHARED_LIBS "Build a static library" OFF) - #------------------------------------------------------------------------------ # Add the sub-directories add_subdirectory(src) -add_subdirectory(doc) + +if(CCPP_FRAMEWORK_ENABLE_TESTS) + find_package(PFUNIT REQUIRED) + enable_testing() + add_subdirectory(test) +endif() + +if (CCPP_FRAMEWORK_BUILD_DOCUMENTATION) + find_package(Doxygen REQUIRED) + if(NOT DOXYGEN_FOUND) + message(FATAL_ERROR "Doxygen is needed to build the documentation.") + endif() + add_subdirectory(doc) +endif() + diff --git a/cmake/ccpp_capgen.cmake b/cmake/ccpp_capgen.cmake new file mode 100644 index 00000000..ff3905f3 --- /dev/null +++ b/cmake/ccpp_capgen.cmake @@ -0,0 +1,114 @@ +function(ccpp_capgen) + set(optionalArgs CAPGEN_DEBUG CAPGEN_EXPECT_THROW_ERROR) + set(oneValueArgs HOST_NAME OUTPUT_ROOT VERBOSITY) + set(multi_value_keywords HOSTFILES SCHEMEFILES SUITES) + + cmake_parse_arguments(arg "${optionalArgs}" "${oneValueArgs}" "${multi_value_keywords}" ${ARGN}) + + # list(APPEND CCPP_CAPGEN_CMD_LIST "${CMAKE_SOURCE_DIR}/scripts/ccpp_capgen.py") + + unset(CCPP_CAPGEN_CMD_LIST) + if(DEFINED arg_CAPGEN_DEBUG) + list(APPEND CCPP_CAPGEN_CMD_LIST "--debug") + endif() + + if(DEFINED arg_HOSTFILES) + list(JOIN arg_HOSTFILES "," HOSTFILES_SEPARATED) + list(APPEND CCPP_CAPGEN_CMD_LIST "--host-files" "${HOSTFILES_SEPARATED}") + endif() + if(DEFINED arg_SCHEMEFILES) + list(JOIN arg_SCHEMEFILES "," SCHEMEFILES_SEPARATED) + list(APPEND CCPP_CAPGEN_CMD_LIST "--scheme-files" "${SCHEMEFILES_SEPARATED}") + endif() + if(DEFINED arg_SUITES) + list(JOIN arg_SUITES "," SUITES_SEPARATED) + list(APPEND CCPP_CAPGEN_CMD_LIST "--suites" "${SUITES_SEPARATED}") + endif() + if(DEFINED arg_HOST_NAME) + list(APPEND CCPP_CAPGEN_CMD_LIST "--host-name" "${arg_HOST_NAME}") + endif() + if(DEFINED arg_OUTPUT_ROOT) + message(STATUS "Creating output directory: ${arg_OUTPUT_ROOT}") + file(MAKE_DIRECTORY "${arg_OUTPUT_ROOT}") + list(APPEND CCPP_CAPGEN_CMD_LIST "--output-root" "${arg_OUTPUT_ROOT}") + endif() + if(DEFINED arg_VERBOSITY) + string(REPEAT "--verbose" ${arg_VERBOSITY} VERBOSE_PARAMS_SEPERATED) + separate_arguments(VERBOSE_PARAMS UNIX_COMMAND "${VERBOSE_PARAMS_SEPERATED}") + list(APPEND CCPP_CAPGEN_CMD_LIST ${VERBOSE_PARAMS}) + endif() + + message(STATUS "Running ccpp_capgen from ${CMAKE_CURRENT_SOURCE_DIR}") + + list(JOIN CCPP_CAPGEN_CMD_LIST " " CCPP_CAPGEN_CMD) + message(STATUS "Running ccpp_capgen: ${CCPP_CAPGEN_CMD}") + + list(JOIN CCPP_CAPGEN_CMD_LIST ";" CCPP_CAPGEN_CMAKE_CMD) + unset(CAPGEN_OUT) + execute_process(COMMAND "${CMAKE_SOURCE_DIR}/scripts/ccpp_capgen.py" ${CCPP_CAPGEN_CMAKE_CMD} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE CAPGEN_OUT + ERROR_VARIABLE CAPGEN_OUT + RESULT_VARIABLE RES) + + message(STATUS "ccpp-capgen stdout: ${CAPGEN_OUT}") + + if(arg_CAPGEN_EXPECT_THROW_ERROR) + string(FIND "${CAPGEN_OUT}" "Variables of type ccpp_constituent_properties_t only allowed in register phase" ERROR_INDEX) + + if (ERROR_INDEX GREATER -1) + message(STATUS "Capgen build produces expected error message.") + else() + message(FATAL_ERROR "CCPP cap generation did not generate expected error. Expected 'Variables of type ccpp_cosntituent_properties_t only allowed in register phase.") + endif() + else() + if(RES EQUAL 0) + message(STATUS "ccpp-capgen completed successfully") + else() + message(FATAL_ERROR "CCPP cap generation FAILED: result = ${RES}") + endif() + endif() +endfunction() + + + +function(ccpp_datafile) + set(oneValueArgs DATATABLE REPORT_NAME CCPP_CAPS_LIB_FILES) + cmake_parse_arguments(arg "" "${oneValueArgs}" "" ${ARGN}) + + set(CCPP_DATAFILE_CMD "${CMAKE_SOURCE_DIR}/scripts/ccpp_datafile.py") + + if(NOT DEFINED arg_DATATABLE) + message(FATAL_ERROR "function(ccpp_datafile): DATATABLE not set. A datatable file must be configured to call ccpp_datafile.") + endif() + list(APPEND CCPP_DATAFILE_CMD "${arg_DATATABLE}") + + if(NOT DEFINED arg_REPORT_NAME) + message(FATAL_ERROR "function(ccpp_datafile): REPORT_NAME not set. Must specify the report to generate to run cpp_datafile.py") + endif() + list(APPEND CCPP_DATAFILE_CMD "${arg_REPORT_NAME}") + + message(STATUS "${CCPP_DATAFILE_CMD}") + message(STATUS "Running ccpp_datafile from ${CMAKE_CURRENT_SOURCE_DIR}") + + string(REPLACE ";" " " CCPP_DATAFILE_CMD_SEPERATED "${CCPP_DATAFILE_CMD}") + message(STATUS "Running ccpp_datafile.py command: ${CCPP_DATAFILE_CMD_SEPERATED}") + + unset(CCPP_CAPS) + list(JOIN CCPP_DATAFILE_CMD ";" CCPP_DATAFILE_CMAKE_CMD) + execute_process(COMMAND ${CCPP_DATAFILE_CMAKE_CMD} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + OUTPUT_VARIABLE CCPP_CAPS + RESULT_VARIABLE RES + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_STRIP_TRAILING_WHITESPACE) + message(STATUS "CCPP_CAPS = ${CCPP_CAPS}") + if(RES EQUAL 0) + message(STATUS "CCPP cap files retrieved") + else() + message(FATAL_ERROR "CCPP cap file retrieval FAILED: result = ${RES}") + endif() + string(REPLACE "," ";" CCPP_CAPS_LIST ${CCPP_CAPS}) + set(CCPP_CAPS_LIST "${CCPP_CAPS_LIST}" PARENT_SCOPE) +endfunction() + diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 9e96e4e4..b7997658 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -2,28 +2,16 @@ # Doxygen rules # # Add a target to generate API documentation with Doxygen -find_package(Doxygen) -option(BUILD_DOCUMENTATION - "Create and install the HTML documentation (requires Doxygen)" - ${DOXYGEN_FOUND}) +set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) +set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) -# -if(BUILD_DOCUMENTATION) - if(NOT DOXYGEN_FOUND) - message(FATAL_ERROR "Doxygen is needed to build the documentation.") - endif() - - set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in) - set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) - - configure_file(${doxyfile_in} ${doxyfile} @ONLY) +configure_file(${doxyfile_in} ${doxyfile} @ONLY) - add_custom_target(doc - COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} - COMMENT "Generating API documentation with Doxygen" - VERBATIM) -endif() +add_custom_target(doc + COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" + VERBATIM) set(gmtb_sty_in ${CMAKE_CURRENT_SOURCE_DIR}/DevelopersGuide/gmtb.sty) set(gmtb_sty ${CMAKE_CURRENT_BINARY_DIR}/DevelopersGuide/gmtb.sty) diff --git a/scripts/ccpp_datafile.py b/scripts/ccpp_datafile.py index 6bb5e537..efa2f1dd 100755 --- a/scripts/ccpp_datafile.py +++ b/scripts/ccpp_datafile.py @@ -159,51 +159,49 @@ def _command_line_parser(): the list of optional arguments below. Note that exactly one action is required. """ - parser = argparse.ArgumentParser(description=description) + parser = argparse.ArgumentParser(description=description, + formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument("datatable", type=str, help="Path to a data table XML file created by capgen") ### Only one action per call group = parser.add_mutually_exclusive_group(required=True) for report in _VALID_REPORTS: - rep_type = "--{}".format(report["report"].replace("_", "-")) + report_name = report["report"].replace("_", "-") + report_name_option = f"--{report_name}" if report["type"] is bool: - group.add_argument(rep_type, action='store_true', default=False, + group.add_argument(report_name_option, action='store_true', default=False, help=report["help"]) elif report["type"] is str: if "metavar" in report: - group.add_argument(rep_type, required=False, type=str, - metavar=report["metavar"], default='', - help=report["help"]) + report_help = report["help"] + default_str = '' + group.add_argument(report_name_option, required=False, type=str, + default=default_str, help=report_help, + metavar=report["metavar"],) else: - group.add_argument(rep_type, required=False, type=str, - default='', help=report["help"]) + group.add_argument(report_name_option, required=False, type=str, + default=default_str, help=report_help) # end if else: - raise ValueError("Unknown report type, '{}'".format(report["type"])) + raise ValueError(f"Unknown report type, '{report['type']}'") # end if # end for ### - defval = "," - help_str = "String to separate items in a list (default: '{}')" - parser.add_argument("--separator", type=str, required=False, default=defval, - metavar="SEP", dest="sep", help=help_str.format(defval)) - defval = False + + parser.add_argument("--separator", type=str, required=False, default=",", + metavar="SEP", dest="sep", + help="String to separate items in a list") + help_str = ("Exclude protected variables (only has an effect if the " - "requested report is returning a list of variables)." - " (default: {})") + "requested report is returning a list of variables).") parser.add_argument("--exclude-protected", action='store_true', - required=False, - default=defval, help=help_str.format(defval)) - defval = -1 - help_str = ("Screen width for '--show' line wrapping. -1 means do not " - "wrap. (default: {})") + required=False, default=False, help=help_str) parser.add_argument("--line-wrap", type=int, required=False, metavar="LINE_WIDTH", dest="line_wrap", - default=defval, help=help_str.format(defval)) - defval = 2 - help_str = "Indent depth for '--show' output (default: {})" + default=-1, + help="Screen width for '--show' line wrapping. -1 means do not wrap.") parser.add_argument("--indent", type=int, required=False, default=2, - help=help_str.format(defval)) + help="Indent depth for '--show' output") return parser ############################################################################### @@ -1195,12 +1193,10 @@ def generate_ccpp_datatable(run_env, host_model, api, scheme_headers, ARG_VARS = vars(PARGS) _ACTION = None _ERRMSG = '' - _ESEP = '' for opt in ARG_VARS: if (opt in DatatableReport.valid_actions()) and ARG_VARS[opt]: if _ACTION: - _ERRMSG += _ESEP + "Duplicate action, '{}'".format(opt) - _ESEP = '\n' + _ERRMSG += f"Duplicate action, '{opt}'\n" else: _ACTION = DatatableReport(opt, ARG_VARS[opt]) # end if @@ -1212,5 +1208,5 @@ def generate_ccpp_datatable(run_env, host_model, api, scheme_headers, REPORT = datatable_report(PARGS.datatable, _ACTION, PARGS.sep, PARGS.exclude_protected) # end if - print("{}".format(REPORT.rstrip())) + print(f"{REPORT.rstrip()}") sys.exit(0) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eaa78afe..ff7d36b0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,9 +29,10 @@ set(${PACKAGE}_LIB_DIRS # Define the executable and what to link add_library(ccpp_framework STATIC ${SOURCES_F90}) target_link_libraries(ccpp_framework PUBLIC MPI::MPI_Fortran) -set_target_properties(ccpp_framework PROPERTIES VERSION ${PROJECT_VERSION} +set_target_properties(ccpp_framework PROPERTIES + VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} - LINK_FLAGS ${CMAKE_Fortran_FLAGS}) + LINK_FLAGS "${CMAKE_Fortran_FLAGS}") #------------------------------------------------------------------------------ # Installation diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 00000000..96b793d9 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,5 @@ + +add_subdirectory(advection_test) +add_subdirectory(capgen_test) +add_subdirectory(ddthost_test) +add_subdirectory(var_compatibility_test) diff --git a/test/advection_test/CMakeLists.txt b/test/advection_test/CMakeLists.txt index c3f45190..ceb0c24a 100644 --- a/test/advection_test/CMakeLists.txt +++ b/test/advection_test/CMakeLists.txt @@ -1,32 +1,18 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -PROJECT(test_host) -ENABLE_LANGUAGE(Fortran) -include(CMakeForceCompiler) - -SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules) - -#------------------------------------------------------------------------------ -# -# Set where the CCPP Framework lives -# -#------------------------------------------------------------------------------ -get_filename_component(TEST_ROOT "${CMAKE_SOURCE_DIR}" DIRECTORY) -get_filename_component(CCPP_ROOT "${TEST_ROOT}" DIRECTORY) #------------------------------------------------------------------------------ # # Create list of SCHEME_FILES, HOST_FILES, and SUITE_FILES # Paths should be relative to CMAKE_SOURCE_DIR (this file's directory) # #------------------------------------------------------------------------------ -LIST(APPEND SCHEME_FILES "cld_suite_files.txt") -LIST(APPEND SCHEME_FILES_ERROR "cld_suite_files_error.txt") -LIST(APPEND HOST_FILES "test_host_data" "test_host_mod") -LIST(APPEND SUITE_FILES "cld_suite.xml") -LIST(APPEND SUITE_FILES_ERROR "cld_suite_error.xml") +set(SCHEME_FILES "cld_suite_files.txt") +set(SCHEME_FILES_ERROR "cld_suite_files_error.txt") +set(HOST_FILES "test_host_data" "test_host_mod") +set(SUITE_FILES "cld_suite.xml") +set(SUITE_FILES_ERROR "cld_suite_error.xml") # HOST is the name of the executable we will build. # We assume there are files ${HOST}.meta and ${HOST}.F90 in CMAKE_SOURCE_DIR -SET(HOST "${CMAKE_PROJECT_NAME}") +set(HOST "test_host") #------------------------------------------------------------------------------ # @@ -34,200 +20,55 @@ SET(HOST "${CMAKE_PROJECT_NAME}") # #------------------------------------------------------------------------------ -# By default, no verbose output -SET(VERBOSITY 0 CACHE STRING "Verbosity level of output (default: 0)") # By default, generated caps go in ccpp subdir -SET(CCPP_CAP_FILES "${CMAKE_BINARY_DIR}/ccpp" CACHE - STRING "Location of CCPP-generated cap files") - -SET(CCPP_FRAMEWORK ${CCPP_ROOT}/scripts) - -# Use rpaths on MacOSX -set(CMAKE_MACOSX_RPATH 1) - -#------------------------------------------------------------------------------ -# Set a default build type if none was specified -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - #message(STATUS "Setting build type to 'Debug' as none was specified.") - #set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) - message(STATUS "Setting build type to 'Release' as none was specified.") - set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) - - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" - "MinSizeRel" "RelWithDebInfo") -endif() - -ADD_COMPILE_OPTIONS(-O0) - -if (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") -# gfortran -# MESSAGE("gfortran being used.") - ADD_COMPILE_OPTIONS(-fcheck=all) - ADD_COMPILE_OPTIONS(-fbacktrace) - ADD_COMPILE_OPTIONS(-ffpe-trap=zero) - ADD_COMPILE_OPTIONS(-finit-real=nan) - ADD_COMPILE_OPTIONS(-ggdb) - ADD_COMPILE_OPTIONS(-ffree-line-length-none) - ADD_COMPILE_OPTIONS(-cpp) -elseif (${CMAKE_Fortran_COMPILER_ID} MATCHES "Intel") -# ifort -# MESSAGE("ifort being used.") - #ADD_COMPILE_OPTIONS(-check all) - ADD_COMPILE_OPTIONS(-fpe0) - ADD_COMPILE_OPTIONS(-warn) - ADD_COMPILE_OPTIONS(-traceback) - ADD_COMPILE_OPTIONS(-debug extended) - ADD_COMPILE_OPTIONS(-fpp) -elseif (${CMAKE_Fortran_COMPILER_ID} MATCHES "PGI") -# pgf90 -# MESSAGE("pgf90 being used.") - ADD_COMPILE_OPTIONS(-g) - ADD_COMPILE_OPTIONS(-Mipa=noconst) - ADD_COMPILE_OPTIONS(-traceback) - ADD_COMPILE_OPTIONS(-Mfree) - ADD_COMPILE_OPTIONS(-Mfptrap) - ADD_COMPILE_OPTIONS(-Mpreprocess) -else (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") - message (WARNING "This program has only been compiled with gfortran, pgf90 and ifort. If another compiler is needed, the appropriate flags SHOULD be added in ${CMAKE_SOURCE_DIR}/CMakeLists.txt") -endif (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") - -#------------------------------------------------------------------------------ -# CMake Modules -# Set the CMake module path -list(APPEND CMAKE_MODULE_PATH "${CCPP_FRAMEWORK}/cmake") -#------------------------------------------------------------------------------ -# Set OpenMP flags for C/C++/Fortran -if (OPENMP) - include(detect_openmp) - detect_openmp() - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}") - message(STATUS "Enable OpenMP support for C/C++/Fortran compiler") -else(OPENMP) - message (STATUS "Disable OpenMP support for C/C++/Fortran compiler") -endif() - -# Create metadata and source file lists -FOREACH(FILE ${SCHEME_FILES}) - FILE(STRINGS ${FILE} FILENAMES) - LIST(APPEND SCHEME_FILENAMES ${FILENAMES}) -ENDFOREACH(FILE) -string(REPLACE ";" "," SCHEME_METADATA "${SCHEME_FILES}") +set(CCPP_CAP_FILES "${CMAKE_CURRENT_BINARY_DIR}/ccpp") # Create metadata and source file lists -FOREACH(FILE ${SCHEME_FILES_ERROR}) - FILE(STRINGS ${FILE} FILENAMES) - LIST(APPEND SCHEME_FILENAMES_ERROR ${FILENAMES}) -ENDFOREACH(FILE) -string(REPLACE ";" "," SCHEME_METADATA_ERROR "${SCHEME_FILES_ERROR}") - -FOREACH(FILE ${SCHEME_FILENAMES}) - # target_sources prefers absolute pathnames - string(REPLACE ".meta" ".F90" TEMP "${FILE}") - get_filename_component(ABS_PATH "${TEMP}" ABSOLUTE) - list(APPEND LIBRARY_LIST ${ABS_PATH}) -ENDFOREACH(FILE) - -FOREACH(FILE ${HOST_FILES}) - LIST(APPEND HOST_METADATA "${FILE}.meta") +foreach(FILE ${SCHEME_FILES}) + file(STRINGS "${FILE}" FILENAMES) + list(TRANSFORM FILENAMES REPLACE ".meta" ".F90") + foreach(filename ${FILENAMES}) + file(REAL_PATH "${filename}" ABS_PATH) + list(APPEND ADVECTION_LIBRARY_LIST "${ABS_PATH}") + endforeach() +endforeach() + +foreach(FILE ${HOST_FILES}) + list(APPEND ADVECTION_HOST_METADATA "${FILE}.meta") # target_sources prefers absolute pathnames - get_filename_component(ABS_PATH "${FILE}.F90" ABSOLUTE) - LIST(APPEND HOST_SOURCE "${ABS_PATH}") -ENDFOREACH(FILE) -list(APPEND LIBRARY_LIST ${HOST_SOURCE}) -string(REPLACE ";" ".meta," HOST_METADATA "${HOST_FILES}") -set(HOST_METADATA "${HOST_METADATA}.meta,${HOST}.meta") + file(REAL_PATH "${FILE}.F90" ABS_PATH) + list(APPEND ADVECTION_LIBRARY_LIST "${ABS_PATH}") +endforeach() -string(REPLACE ";" "," SUITE_XML "${SUITE_FILES}") -string(REPLACE ";" "," SUITE_XML_ERROR "${SUITE_FILES_ERROR}") +list(APPEND ADVECTION_HOST_METADATA "${HOST}.meta") # Run ccpp_capgen that we expect to fail -set(CAPGEN_CMD "${CCPP_FRAMEWORK}/ccpp_capgen.py") -list(APPEND CAPGEN_CMD "--host-files") -list(APPEND CAPGEN_CMD "${HOST_METADATA}") -list(APPEND CAPGEN_CMD "--scheme-files") -list(APPEND CAPGEN_CMD "${SCHEME_METADATA_ERROR}") -list(APPEND CAPGEN_CMD "--suites") -list(APPEND CAPGEN_CMD "${SUITE_XML_ERROR}") -list(APPEND CAPGEN_CMD "--host-name") -list(APPEND CAPGEN_CMD "test_host") -list(APPEND CAPGEN_CMD "--output-root") -list(APPEND CAPGEN_CMD "${CCPP_CAP_FILES}") -while (VERBOSITY GREATER 0) - list(APPEND CAPGEN_CMD "--verbose") - MATH(EXPR VERBOSITY "${VERBOSITY} - 1") -endwhile () -list(APPEND CAPGEN_CMD "--debug") -string(REPLACE ";" " " CAPGEN_STRING "${CAPGEN_CMD}") -MESSAGE(STATUS "Running: ${CAPGEN_STRING}") -EXECUTE_PROCESS(COMMAND ${CAPGEN_CMD} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE CAPGEN_OUT ERROR_VARIABLE CAPGEN_OUT RESULT_VARIABLE RES) -MESSAGE(STATUS "${CAPGEN_OUT}") -if (RES EQUAL 0) - MESSAGE(STATUS "CCPP cap generation completed") -else() - # Example: Validate the error message - string(FIND "${CAPGEN_OUT}" "Variables of type ccpp_constituent_properties_t only allowed in register phase" ERROR_INDEX) - - if (ERROR_INDEX GREATER -1) - MESSAGE(STATUS "Capgen build produces expected error message.") - else() - MESSAGE(FATAL_ERROR "CCPP cap generation did not generate expected error. Expected 'Variables of type ccpp_cosntituent_properties_t only allowed in register phase. Got: " ${CAPGEN_OUT}"") - endif() -endif(RES EQUAL 0) +ccpp_capgen(CAPGEN_EXPECT_THROW_ERROR ON + CAPGEN_DEBUG ON + VERBOSITY ${CCPP_VERBOSITY} + HOSTFILES ${ADVECTION_HOST_METADATA} + SCHEMEFILES ${SCHEME_FILES_ERROR} + SUITES ${SUITE_FILES_ERROR} + HOST_NAME "test_host" + OUTPUT_ROOT "${CCPP_CAP_FILES}") # Run ccpp_capgen -set(CAPGEN_CMD "${CCPP_FRAMEWORK}/ccpp_capgen.py") -list(APPEND CAPGEN_CMD "--host-files") -list(APPEND CAPGEN_CMD "${HOST_METADATA}") -list(APPEND CAPGEN_CMD "--scheme-files") -list(APPEND CAPGEN_CMD "${SCHEME_METADATA}") -list(APPEND CAPGEN_CMD "--suites") -list(APPEND CAPGEN_CMD "${SUITE_XML}") -list(APPEND CAPGEN_CMD "--host-name") -list(APPEND CAPGEN_CMD "test_host") -list(APPEND CAPGEN_CMD "--output-root") -list(APPEND CAPGEN_CMD "${CCPP_CAP_FILES}") -while (VERBOSITY GREATER 0) - list(APPEND CAPGEN_CMD "--verbose") - MATH(EXPR VERBOSITY "${VERBOSITY} - 1") -endwhile () -list(APPEND CAPGEN_CMD "--debug") -string(REPLACE ";" " " CAPGEN_STRING "${CAPGEN_CMD}") -MESSAGE(STATUS "Running: ${CAPGEN_STRING}") -EXECUTE_PROCESS(COMMAND ${CAPGEN_CMD} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE CAPGEN_OUT ERROR_VARIABLE CAPGEN_OUT RESULT_VARIABLE RES) -MESSAGE(STATUS "${CAPGEN_OUT}") -if (RES EQUAL 0) - MESSAGE(STATUS "CCPP cap generation completed") -else(RES EQUAL 0) - MESSAGE(FATAL_ERROR "CCPP cap generation FAILED: result = ${RES}") -endif(RES EQUAL 0) +ccpp_capgen(CAPGEN_DEBUG ON + VERBOSITY ${CCPP_VERBOSITY} + HOSTFILES ${ADVECTION_HOST_METADATA} + SCHEMEFILES ${SCHEME_FILES} + SUITES ${SUITE_FILES} + HOST_NAME "test_host" + OUTPUT_ROOT "${CCPP_CAP_FILES}") # Retrieve the list of files from datatable.xml and set to CCPP_CAPS -set(DTABLE_CMD "${CCPP_FRAMEWORK}/ccpp_datafile.py") -list(APPEND DTABLE_CMD "${CCPP_CAP_FILES}/datatable.xml") -list(APPEND DTABLE_CMD "--ccpp-files") -list(APPEND DTABLE_CMD "--separator=\\;") -string(REPLACE ";" " " DTABLE_STRING "${DTABLE_CMD}") -MESSAGE(STATUS "Running: ${DTABLE_STRING}") -EXECUTE_PROCESS(COMMAND ${DTABLE_CMD} OUTPUT_VARIABLE CCPP_CAPS - RESULT_VARIABLE RES - OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE) -message(STATUS "CCPP_CAPS = ${CCPP_CAPS}") -if (RES EQUAL 0) - MESSAGE(STATUS "CCPP cap files retrieved") -else(RES EQUAL 0) - MESSAGE(FATAL_ERROR "CCPP cap file retrieval FAILED: result = ${RES}") -endif(RES EQUAL 0) -list(APPEND LIBRARY_LIST ${CCPP_CAPS}) -add_library(TESTLIB OBJECT ${LIBRARY_LIST}) -ADD_EXECUTABLE(${HOST} ${HOST}.F90 $) +ccpp_datafile(DATATABLE "${CCPP_CAP_FILES}/datatable.xml" + REPORT_NAME "--ccpp-files") + +list(APPEND ADVECTION_LIBRARY_LIST ${CCPP_CAPS_LIST}) +add_library(ADVECTION_TESTLIB OBJECT ${ADVECTION_LIBRARY_LIST}) +add_executable(advection_${HOST} ${HOST}.F90 $) -INCLUDE_DIRECTORIES(${CCPP_CAP_FILES}) +target_include_directories(advection_${HOST} PRIVATE ${CCPP_CAP_FILES}) -set_target_properties(${HOST} PROPERTIES - COMPILE_FLAGS "${CMAKE_Fortran_FLAGS}" - LINK_FLAGS "${CMAKE_Fortran_FLAGS}") +add_test(NAME advection_${HOST} COMMAND advection_${HOST}) \ No newline at end of file diff --git a/test/advection_test/advection_test_reports.py b/test/advection_test/advection_test_reports.py new file mode 100644 index 00000000..b255b767 --- /dev/null +++ b/test/advection_test/advection_test_reports.py @@ -0,0 +1,202 @@ +#! /usr/bin/env python3 +""" +----------------------------------------------------------------------- + Description: Test advection database report python interface + + Assumptions: + + Command line arguments: build_dir database_filepath + + Usage: python test_reports +----------------------------------------------------------------------- +""" +import sys +import os +import unittest +import subprocess + +_BUILD_DIR = os.path.join(os.path.abspath(os.environ['BUILD_DIR']), "test", "advection_test") +_TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +_FRAMEWORK_DIR = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir)) +_SCRIPTS_DIR = os.path.abspath(os.path.join(_FRAMEWORK_DIR, "scripts")) + +sys.path.append(_SCRIPTS_DIR) +# pylint: disable=wrong-import-position +from ccpp_datafile import datatable_report, DatatableReport +# pylint: enable=wrong-import-position + +_DATABASE = os.path.abspath(os.path.join(_BUILD_DIR, "ccpp", "datatable.xml")) + +# Check data +_HOST_FILES = [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90")] +_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_cld_suite_cap.F90")] +_UTILITY_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_kinds.F90"), + os.path.join(_FRAMEWORK_DIR, "src", + "ccpp_constituent_prop_mod.F90"), + os.path.join(_FRAMEWORK_DIR, "src", "ccpp_hashable.F90"), + os.path.join(_FRAMEWORK_DIR, "src", "ccpp_hash_table.F90")] +_CCPP_FILES = _UTILITY_FILES + _HOST_FILES + _SUITE_FILES +_DEPENDENCIES = [""] +_PROCESS_LIST = [""] +_MODULE_LIST = ["apply_constituent_tendencies", "cld_ice", "cld_liq"] +_SUITE_LIST = ["cld_suite"] +_DYN_CONST_ROUTINES = ["cld_ice_dynamic_constituents", "cld_liq_dynamic_constituents"] +_REQUIRED_VARS_CLD = ["ccpp_error_code", "ccpp_error_message", + "horizontal_loop_begin", "horizontal_loop_end", + "surface_air_pressure", "temperature", + "tendency_of_cloud_liquid_dry_mixing_ratio", + "time_step_for_physics", "water_temperature_at_freezing", + "water_vapor_specific_humidity", + "cloud_ice_dry_mixing_ratio", + "cloud_liquid_dry_mixing_ratio", + "ccpp_constituents", + "ccpp_constituent_tendencies", + "number_of_ccpp_constituents", + "dynamic_constituents_for_cld_ice", + "dynamic_constituents_for_cld_liq", + # Added by --debug option + "horizontal_dimension", + "vertical_layer_dimension"] +_INPUT_VARS_CLD = ["surface_air_pressure", "temperature", + "horizontal_loop_begin", "horizontal_loop_end", + "time_step_for_physics", "water_temperature_at_freezing", + "water_vapor_specific_humidity", + "cloud_ice_dry_mixing_ratio", + "cloud_liquid_dry_mixing_ratio", + "tendency_of_cloud_liquid_dry_mixing_ratio", + "ccpp_constituents", + "ccpp_constituent_tendencies", + "number_of_ccpp_constituents", + # Added by --debug option + "horizontal_dimension", + "vertical_layer_dimension"] +_OUTPUT_VARS_CLD = ["ccpp_error_code", "ccpp_error_message", + "water_vapor_specific_humidity", "temperature", + "tendency_of_cloud_liquid_dry_mixing_ratio", + "cloud_ice_dry_mixing_ratio", + "ccpp_constituents", + "ccpp_constituent_tendencies", + "cloud_liquid_dry_mixing_ratio", + "dynamic_constituents_for_cld_ice", + "dynamic_constituents_for_cld_liq"] +_SEP = "," + +class TestAdvectionDataTables(unittest.TestCase): + def test_host_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("host_files"), _SEP) + self.assertSetEqual(set(_HOST_FILES), set(test_str.split(_SEP))) + + def test_suite_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("suite_files"), _SEP) + self.assertSetEqual(set(_SUITE_FILES), set(test_str.split(_SEP))) + + def test_utility_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("utility_files"), _SEP) + self.assertSetEqual(set(_UTILITY_FILES), set(test_str.split(_SEP))) + + def test_ccpp_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("ccpp_files"), _SEP) + self.assertSetEqual(set(_CCPP_FILES), set(test_str.split(_SEP))) + + def test_process_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("process_list"), _SEP) + self.assertSetEqual(set(_PROCESS_LIST), set(test_str.split(_SEP))) + + def test_module_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("module_list"), _SEP) + self.assertSetEqual(set(_MODULE_LIST), set(test_str.split(_SEP))) + + def test_dependencies_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("dependencies"), _SEP) + self.assertSetEqual(set(_DEPENDENCIES), set(test_str.split(_SEP))) + + def test_suite_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("suite_list"), _SEP) + self.assertSetEqual(set(_SUITE_LIST), set(test_str.split(_SEP))) + +class CommandLineAdvectionDatafileRequiredFiles(unittest.TestCase): + def test_host_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--host-files"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_HOST_FILES), actualOutput) + + def test_suite_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--suite-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_SUITE_FILES), completedProcess.stdout.strip()) + + def test_utility_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--utility-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_UTILITY_FILES), completedProcess.stdout.strip()) + + def test_ccpp_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--ccpp-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_CCPP_FILES), completedProcess.stdout.strip()) + + def test_process_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--process-list"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_PROCESS_LIST), actualOutput) + + def test_module_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--module-list"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_MODULE_LIST), completedProcess.stdout.strip()) + + def test_dependencies(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--dependencies"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_DEPENDENCIES), completedProcess.stdout.strip()) + + def test_suite_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--suite-list", "--sep=;"], + capture_output=True, + text=True) + # actualOutput = {s.strip() for s in completedProcess.stdout.split(";")} + self.assertEqual(";".join(_SUITE_LIST), completedProcess.stdout.strip()) + +class TestCldSuite(unittest.TestCase): + def test_required_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("required_variables", value="cld_suite"), _SEP) + self.assertSetEqual(set(_REQUIRED_VARS_CLD), set(test_str.split(_SEP))) + + def test_input_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("input_variables", value="cld_suite"), _SEP) + self.assertSetEqual(set(_INPUT_VARS_CLD), set(test_str.split(_SEP))) + + def test_output_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("output_variables", value="cld_suite"), _SEP) + self.assertSetEqual(set(_OUTPUT_VARS_CLD), set(test_str.split(_SEP))) + +class CommandLineCldSuite(unittest.TestCase): + def test_required_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--required-variables", "cld_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_REQUIRED_VARS_CLD), actualOutput) + + def test_input_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--input-variables", "cld_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_INPUT_VARS_CLD), actualOutput) + + def test_output_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--output-variables", "cld_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_OUTPUT_VARS_CLD), actualOutput) diff --git a/test/advection_test/run_test b/test/advection_test/run_test deleted file mode 100755 index 5f9f8a8b..00000000 --- a/test/advection_test/run_test +++ /dev/null @@ -1,262 +0,0 @@ -#! /bin/bash - -currdir="`pwd -P`" -scriptdir="$( cd $( dirname $0 ); pwd -P )" - -## -## Option default values -## -defdir="at_build" -build_dir="${currdir}/${defdir}" -cleanup="PASS" # Other supported options are ALWAYS and NEVER -verbosity=0 - -## -## General syntax help function -## Usage: help -## -help () { - local hname="Usage: `basename ${0}`" - local hprefix="`echo ${hname} | tr '[!-~]' ' '`" - echo "${hname} [ --build-dir ] [ --cleanup ]" - echo "${hprefix} [ --verbosity <#> ]" - hprefix=" " - echo "" - echo "${hprefix} : Directory for building and running the test" - echo "${hprefix} default is /${defdir}" - echo "${hprefix} : Cleanup option is ALWAYS, NEVER, or PASS" - echo "${hprefix} default is PASS" - echo "${hprefix} verbosity: 0, 1, or 2" - echo "${hprefix} default is 0" - exit $1 -} - -## -## Error output function (should be handed a string) -## -perr() { - >&2 echo -e "\nERROR: ${@}\n" - exit 1 -} - -## -## Cleanup the build and test directory -## -docleanup() { - # We start off in the build directory - if [ "${build_dir}" == "${currdir}" ]; then - echo "WARNING: Cannot clean ${build_dir}" - else - cd ${currdir} - rm -rf ${build_dir} - fi -} - -## Process our input arguments -while [ $# -gt 0 ]; do - case $1 in - --h | -h | --help | -help) - help 0 - ;; - --build-dir) - if [ $# -lt 2 ]; then - perr "${1} requires a build directory" - fi - build_dir="${2}" - shift - ;; - --cleanup) - if [ $# -lt 2 ]; then - perr "${1} requies a cleanup option (ALWAYS, NEVER, PASS)" - fi - if [ "${2}" == "ALWAYS" -o "${2}" == "NEVER" -o "${2}" == "PASS" ]; then - cleanup="${2}" - else - perr "Allowed cleanup options: ALWAYS, NEVER, PASS" - fi - shift - ;; - --verbosity) - if [ $# -lt 2 ]; then - perr "${1} requires a verbosity value (0, 1, or 2)" - fi - if [ "${2}" == "0" -o "${2}" == "1" -o "${2}" == "2" ]; then - verbosity=$2 - else - perr "allowed verbosity levels are 0, 1, 2" - fi - shift - ;; - *) - perr "Unrecognized option, \"${1}\"" - ;; - esac - shift -done - -# Create the build directory, if necessary -if [ -d "${build_dir}" ]; then - # Always make sure build_dir is not in the test dir - if [ "$( cd ${build_dir}; pwd -P )" == "${currdir}" ]; then - build_dir="${build_dir}/${defdir}" - fi -else - mkdir -p ${build_dir} - res=$? - if [ $res -ne 0 ]; then - perr "Unable to create build directory, '${build_dir}'" - fi -fi -build_dir="$( cd ${build_dir}; pwd -P )" - -## framework is the CCPP Framework root dir -framework="$( cd $( dirname $( dirname ${scriptdir} ) ); pwd -P )" -fsrc="${framework}/src" - -## -## check strings for datafile command-list test -## NB: This has to be after build_dir is finalized -## -host_files="${build_dir}/ccpp/test_host_ccpp_cap.F90" -hash_files="${fsrc}/ccpp_hashable.F90,${fsrc}/ccpp_hash_table.F90" -suite_files="${build_dir}/ccpp/ccpp_cld_suite_cap.F90" -utility_files="${build_dir}/ccpp/ccpp_kinds.F90" -utility_files="${utility_files},${fsrc}/ccpp_constituent_prop_mod.F90" -utility_files="${utility_files},${hash_files}" -ccpp_files="${utility_files},${host_files},${suite_files}" -process_list="" -module_list="apply_constituent_tendencies,cld_ice,cld_liq" -dependencies="" -suite_list="cld_suite" -required_vars="ccpp_constituent_tendencies,ccpp_constituents" -required_vars="${required_vars},ccpp_error_code,ccpp_error_message" -required_vars="${required_vars},cloud_ice_dry_mixing_ratio" -required_vars="${required_vars},cloud_liquid_dry_mixing_ratio" -required_vars="${required_vars},dynamic_constituents_for_cld_ice" -required_vars="${required_vars},dynamic_constituents_for_cld_liq" -required_vars="${required_vars},horizontal_dimension" -required_vars="${required_vars},horizontal_loop_begin" -required_vars="${required_vars},horizontal_loop_end" -required_vars="${required_vars},number_of_ccpp_constituents" -required_vars="${required_vars},surface_air_pressure" -required_vars="${required_vars},temperature" -required_vars="${required_vars},tendency_of_cloud_liquid_dry_mixing_ratio" -required_vars="${required_vars},time_step_for_physics" -required_vars="${required_vars},vertical_layer_dimension" -required_vars="${required_vars},water_temperature_at_freezing" -required_vars="${required_vars},water_vapor_specific_humidity" -input_vars="ccpp_constituent_tendencies,ccpp_constituents" -input_vars="${input_vars},cloud_ice_dry_mixing_ratio,cloud_liquid_dry_mixing_ratio" -input_vars="${input_vars},horizontal_dimension" -input_vars="${input_vars},horizontal_loop_begin" -input_vars="${input_vars},horizontal_loop_end" -input_vars="${input_vars},number_of_ccpp_constituents" -input_vars="${input_vars},surface_air_pressure,temperature" -input_vars="${input_vars},tendency_of_cloud_liquid_dry_mixing_ratio" -input_vars="${input_vars},time_step_for_physics" -input_vars="${input_vars},vertical_layer_dimension" -input_vars="${input_vars},water_temperature_at_freezing" -input_vars="${input_vars},water_vapor_specific_humidity" -output_vars="ccpp_constituent_tendencies,ccpp_constituents" -output_vars="${output_vars},ccpp_error_code,ccpp_error_message" -output_vars="${output_vars},cloud_ice_dry_mixing_ratio" -output_vars="${output_vars},cloud_liquid_dry_mixing_ratio" -output_vars="${output_vars},dynamic_constituents_for_cld_ice" -output_vars="${output_vars},dynamic_constituents_for_cld_liq" -output_vars="${output_vars},temperature" -output_vars="${output_vars},tendency_of_cloud_liquid_dry_mixing_ratio" -output_vars="${output_vars},water_vapor_specific_humidity" - -## -## Run a database report and check the return string -## $1 is the report program file -## $2 is the database file -## $3 is the report string -## $4 is the check string -## $5+ are any optional arguments -## -check_datatable() { - local checkstr=${4} - local teststr - local prog=${1} - local database=${2} - local report=${3} - shift 4 - echo "Checking ${report} report" - teststr="`${prog} ${database} ${report} $@`" - if [ "${teststr}" != "${checkstr}" ]; then - perr "datatable check:\nExpected: '${checkstr}'\nGot: '${teststr}'" - fi -} - -# cd to the build directory -cd ${build_dir} -res=$? -if [ $res -ne 0 ]; then - perr "Unable to cd to build directory, '${build_dir}'" -fi -# Clean build directory -rm -rf * -res=$? -if [ $res -ne 0 ]; then - perr "Unable to clean build directory, '${build_dir}'" -fi -# Run CMake -opts="" -if [ $verbosity -gt 0 ]; then - opts="${opts} -DVERBOSITY=${verbosity}" -fi -# Run cmake -cmake ${scriptdir} ${opts} -res=$? -if [ $res -ne 0 ]; then - perr "CMake failed with exit code, ${res}" -fi -# Test the datafile user interface -report_prog="${framework}/scripts/ccpp_datafile.py" -datafile="${build_dir}/ccpp/datatable.xml" -echo "Running python interface tests" -python3 ${scriptdir}/test_reports.py ${build_dir} ${datafile} -res=$? -if [ $res -ne 0 ]; then - perr "python interface tests failed" -fi -echo "Running command line tests" -echo "Checking required files from command line:" -check_datatable ${report_prog} ${datafile} "--host-files" ${host_files} -check_datatable ${report_prog} ${datafile} "--suite-files" ${suite_files} -check_datatable ${report_prog} ${datafile} "--utility-files" ${utility_files} -check_datatable ${report_prog} ${datafile} "--ccpp-files" ${ccpp_files} -echo -e "\nChecking lists from command line" -check_datatable ${report_prog} ${datafile} "--process-list" "${process_list}" -check_datatable ${report_prog} ${datafile} "--module-list" ${module_list} -check_datatable ${report_prog} ${datafile} "--dependencies" "${dependencies}" -check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \ - --sep ";" -echo -e "\nChecking variables from command line" -check_datatable ${report_prog} ${datafile} "--required-variables" \ - ${required_vars} "cld_suite" -check_datatable ${report_prog} ${datafile} "--input-variables" \ - ${input_vars} "cld_suite" -check_datatable ${report_prog} ${datafile} "--output-variables" \ - ${output_vars} "cld_suite" -# Run make -make -res=$? -if [ $res -ne 0 ]; then - perr "make failed with exit code, ${res}" -fi -# Run test -./test_host -res=$? -if [ $res -ne 0 ]; then - perr "test_host failed with exit code, ${res}" -fi - -if [ "${cleanup}" == "ALWAYS" ]; then - docleanup -elif [ $res -eq 0 -a "${cleanup}" == "PASS" ]; then - docleanup -fi - -exit $res diff --git a/test/advection_test/test_reports.py b/test/advection_test/test_reports.py deleted file mode 100644 index 2a51a411..00000000 --- a/test/advection_test/test_reports.py +++ /dev/null @@ -1,184 +0,0 @@ -#! /usr/bin/env python3 -""" ------------------------------------------------------------------------ - Description: Test advection database report python interface - - Assumptions: - - Command line arguments: build_dir database_filepath - - Usage: python test_reports ------------------------------------------------------------------------ -""" -import sys -import os - -_TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -_FRAMEWORK_DIR = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir)) -_SCRIPTS_DIR = os.path.abspath(os.path.join(_FRAMEWORK_DIR, "scripts")) - -if not os.path.exists(_SCRIPTS_DIR): - raise ImportError("Cannot find scripts directory") -# end if - -if ((sys.version_info[0] < 3) or - (sys.version_info[0] == 3) and (sys.version_info[1] < 8)): - raise Exception("Python 3.8 or greater required") -# end if - -sys.path.append(_SCRIPTS_DIR) -# pylint: disable=wrong-import-position -from ccpp_datafile import datatable_report, DatatableReport -# pylint: enable=wrong-import-position - -def usage(errmsg=None): - """Raise an exception with optional error message and usage message""" - emsg = "usage: {} " - if errmsg: - emsg = errmsg + '\n' + emsg - # end if - raise ValueError(emsg.format(sys.argv[0])) - -if len(sys.argv) != 3: - usage() -# end if - -_BUILD_DIR = os.path.abspath(sys.argv[1]) -_DATABASE = os.path.abspath(sys.argv[2]) -if not os.path.isdir(_BUILD_DIR): - _EMSG = " must be an existing build directory" - usage(_EMSG) -# end if -if (not os.path.exists(_DATABASE)) or (not os.path.isfile(_DATABASE)): - _EMSG = " must be an existing CCPP database file" - usage(_EMSG) -# end if - -# Check data -_HOST_FILES = [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90")] -_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_cld_suite_cap.F90")] -_UTILITY_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_kinds.F90"), - os.path.join(_FRAMEWORK_DIR, "src", - "ccpp_constituent_prop_mod.F90"), - os.path.join(_FRAMEWORK_DIR, "src", "ccpp_hashable.F90"), - os.path.join(_FRAMEWORK_DIR, "src", "ccpp_hash_table.F90")] -_CCPP_FILES = _UTILITY_FILES + _HOST_FILES + _SUITE_FILES -_PROCESS_LIST = list() -_MODULE_LIST = ["cld_ice", "cld_liq", "apply_constituent_tendencies"] -_SUITE_LIST = ["cld_suite"] -_DYN_CONST_ROUTINES = ["cld_ice_dynamic_constituents", "cld_liq_dynamic_constituents"] -_REQUIRED_VARS_CLD = ["ccpp_error_code", "ccpp_error_message", - "horizontal_loop_begin", "horizontal_loop_end", - "surface_air_pressure", "temperature", - "tendency_of_cloud_liquid_dry_mixing_ratio", - "time_step_for_physics", "water_temperature_at_freezing", - "water_vapor_specific_humidity", - "cloud_ice_dry_mixing_ratio", - "cloud_liquid_dry_mixing_ratio", - "ccpp_constituents", - "ccpp_constituent_tendencies", - "number_of_ccpp_constituents", - "dynamic_constituents_for_cld_ice", - "dynamic_constituents_for_cld_liq", - # Added by --debug option - "horizontal_dimension", - "vertical_layer_dimension"] -_INPUT_VARS_CLD = ["surface_air_pressure", "temperature", - "horizontal_loop_begin", "horizontal_loop_end", - "time_step_for_physics", "water_temperature_at_freezing", - "water_vapor_specific_humidity", - "cloud_ice_dry_mixing_ratio", - "cloud_liquid_dry_mixing_ratio", - "tendency_of_cloud_liquid_dry_mixing_ratio", - "ccpp_constituents", - "ccpp_constituent_tendencies", - "number_of_ccpp_constituents", - # Added by --debug option - "horizontal_dimension", - "vertical_layer_dimension"] -_OUTPUT_VARS_CLD = ["ccpp_error_code", "ccpp_error_message", - "water_vapor_specific_humidity", "temperature", - "tendency_of_cloud_liquid_dry_mixing_ratio", - "cloud_ice_dry_mixing_ratio", - "ccpp_constituents", - "ccpp_constituent_tendencies", - "cloud_liquid_dry_mixing_ratio", - "dynamic_constituents_for_cld_ice", - "dynamic_constituents_for_cld_liq"] - -def fields_string(field_type, field_list, sep): - """Create an error string for field(s), . - is used to separate items in """ - indent = ' '*11 - if field_list: - if len(field_list) > 1: - field_str = "{} Fields: ".format(field_type) - else: - field_str = "{} Field: ".format(field_type) - # end if - fmsg = "\n{}{}{}".format(indent, field_str, sep.join(field_list)) - else: - fmsg = "" - # end if - return fmsg - -def check_datatable(database, report_type, check_list, sep=','): - """Run a database report and check the return string. - If an error is found, print an error message. - Return the number of errors""" - if sep is None: - sep = ',' - # end if - test_str = datatable_report(database, report_type, sep) - test_list = [x for x in test_str.split(sep) if x] - missing = list() - unexpected = list() - for item in check_list: - if item not in test_list: - missing.append(item) - # end if - # end for - for item in test_list: - if item not in check_list: - unexpected.append(item) - # end if - # end for - if missing or unexpected: - vmsg = "ERROR in {} datafile check:".format(report_type.action) - vmsg += fields_string("Missing", missing, sep) - vmsg += fields_string("Unexpected", unexpected, sep) - print(vmsg) - else: - print("{} report okay".format(report_type.action)) - # end if - return len(missing) + len(unexpected) - -NUM_ERRORS = 0 -print("Checking required files from python:") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("host_files"), - _HOST_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_files"), - _SUITE_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("utility_files"), - _UTILITY_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("ccpp_files"), - _CCPP_FILES) -print("\nChecking lists from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("process_list"), - _PROCESS_LIST) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("module_list"), - _MODULE_LIST) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_list"), - _SUITE_LIST) -print("\nChecking variables for CLD suite from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", - value="cld_suite"), - _REQUIRED_VARS_CLD) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", - value="cld_suite"), - _INPUT_VARS_CLD) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("output_variables", - value="cld_suite"), - _OUTPUT_VARS_CLD) - -sys.exit(NUM_ERRORS) diff --git a/test/capgen_test/.gitignore b/test/capgen_test/.gitignore deleted file mode 100644 index 378eac25..00000000 --- a/test/capgen_test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build diff --git a/test/capgen_test/CMakeLists.txt b/test/capgen_test/CMakeLists.txt index ccae4f08..5b2d5062 100644 --- a/test/capgen_test/CMakeLists.txt +++ b/test/capgen_test/CMakeLists.txt @@ -1,188 +1,58 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -PROJECT(test_host) -ENABLE_LANGUAGE(Fortran) - -include(CMakeForceCompiler) - -SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules) -#------------------------------------------------------------------------------ -# -# Set where the CCPP Framework lives -# -#------------------------------------------------------------------------------ -get_filename_component(TEST_ROOT "${CMAKE_SOURCE_DIR}" DIRECTORY) -get_filename_component(CCPP_ROOT "${TEST_ROOT}" DIRECTORY) #------------------------------------------------------------------------------ # # Create list of SCHEME_FILES, HOST_FILES, and SUITE_FILES # Paths should be relative to CMAKE_SOURCE_DIR (this file's directory) # #------------------------------------------------------------------------------ -LIST(APPEND SCHEME_FILES "temp_scheme_files.txt" "ddt_suite_files.txt") -LIST(APPEND HOST_FILES "test_host_data" "test_host_mod") -LIST(APPEND SUITE_FILES "ddt_suite.xml" "temp_suite.xml") +set(SCHEME_FILES "temp_scheme_files.txt" "ddt_suite_files.txt") +set(HOST_FILES "test_host_data" "test_host_mod") +set(SUITE_FILES "ddt_suite.xml" "temp_suite.xml") + # HOST is the name of the executable we will build. # We assume there are files ${HOST}.meta and ${HOST}.F90 in CMAKE_SOURCE_DIR -SET(HOST "${CMAKE_PROJECT_NAME}") +set(HOST "test_host") -#------------------------------------------------------------------------------ -# -# End of project-specific input -# -#------------------------------------------------------------------------------ - -# By default, no verbose output -SET(VERBOSITY 0 CACHE STRING "Verbosity level of output (default: 0)") # By default, generated caps go in ccpp subdir -SET(CCPP_CAP_FILES "${CMAKE_BINARY_DIR}/ccpp" CACHE - STRING "Location of CCPP-generated cap files") - -SET(CCPP_FRAMEWORK ${CCPP_ROOT}/scripts) - -# Use rpaths on MacOSX -set(CMAKE_MACOSX_RPATH 1) - -#------------------------------------------------------------------------------ -# Set a default build type if none was specified -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - #message(STATUS "Setting build type to 'Debug' as none was specified.") - #set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) - message(STATUS "Setting build type to 'Release' as none was specified.") - set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) - - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" - "MinSizeRel" "RelWithDebInfo") -endif() - -ADD_COMPILE_OPTIONS(-O0) - -if (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") -# gfortran -# MESSAGE("gfortran being used.") - ADD_COMPILE_OPTIONS(-fcheck=all) - ADD_COMPILE_OPTIONS(-fbacktrace) - ADD_COMPILE_OPTIONS(-ffpe-trap=zero) - ADD_COMPILE_OPTIONS(-finit-real=nan) - ADD_COMPILE_OPTIONS(-ggdb) - ADD_COMPILE_OPTIONS(-ffree-line-length-none) - ADD_COMPILE_OPTIONS(-cpp) -elseif (${CMAKE_Fortran_COMPILER_ID} MATCHES "Intel") -# ifort -# MESSAGE("ifort being used.") - #ADD_COMPILE_OPTIONS(-check all) - ADD_COMPILE_OPTIONS(-fpe0) - ADD_COMPILE_OPTIONS(-warn) - ADD_COMPILE_OPTIONS(-traceback) - ADD_COMPILE_OPTIONS(-debug extended) - ADD_COMPILE_OPTIONS(-fpp) -elseif (${CMAKE_Fortran_COMPILER_ID} MATCHES "PGI") -# pgf90 -# MESSAGE("pgf90 being used.") - ADD_COMPILE_OPTIONS(-g) - ADD_COMPILE_OPTIONS(-Mipa=noconst) - ADD_COMPILE_OPTIONS(-traceback) - ADD_COMPILE_OPTIONS(-Mfree) - ADD_COMPILE_OPTIONS(-Mfptrap) - ADD_COMPILE_OPTIONS(-Mpreprocess) -else (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") - message (WARNING "This program has only been compiled with gfortran, pgf90 and ifort. If another compiler is needed, the appropriate flags SHOULD be added in ${CMAKE_SOURCE_DIR}/CMakeLists.txt") -endif (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") - -#------------------------------------------------------------------------------ -# CMake Modules -# Set the CMake module path -list(APPEND CMAKE_MODULE_PATH "${CCPP_FRAMEWORK}/cmake") -#------------------------------------------------------------------------------ -# Set OpenMP flags for C/C++/Fortran -if (OPENMP) - include(detect_openmp) - detect_openmp() - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}") - message(STATUS "Enable OpenMP support for C/C++/Fortran compiler") -else(OPENMP) - message (STATUS "Disable OpenMP support for C/C++/Fortran compiler") -endif() +set(CCPP_CAP_FILES "${CMAKE_CURRENT_BINARY_DIR}/ccpp") # Create metadata and source file lists -FOREACH(FILE ${SCHEME_FILES}) - FILE(STRINGS ${FILE} FILENAMES) - LIST(APPEND SCHEME_FILENAMES ${FILENAMES}) -ENDFOREACH(FILE) -string(REPLACE ";" "," SCHEME_METADATA "${SCHEME_FILES}") - -FOREACH(FILE ${SCHEME_FILENAMES}) +foreach(SCHEME_FILE ${SCHEME_FILES}) + file(STRINGS ${SCHEME_FILE} FILENAMES) + foreach(filename ${FILENAMES}) + string(REPLACE ".meta" ".F90" TEMP "${filename}") + file(REAL_PATH "${TEMP}" ABS_PATH) + list(APPEND CAPGEN_LIBRARY_LIST "${ABS_PATH}") + endforeach() +endforeach() + +foreach(FILE ${HOST_FILES}) + list(APPEND CAPGEN_HOST_METADATA "${FILE}.meta") # target_sources prefers absolute pathnames - string(REPLACE ".meta" ".F90" TEMP "${FILE}") - get_filename_component(ABS_PATH "${TEMP}" ABSOLUTE) - list(APPEND LIBRARY_LIST ${ABS_PATH}) -ENDFOREACH(FILE) + file(REAL_PATH "${FILE}.F90" ABS_PATH) + list(APPEND CAPGEN_LIBRARY_LIST "${ABS_PATH}") +endforeach() -FOREACH(FILE ${HOST_FILES}) - LIST(APPEND HOST_METADATA "${FILE}.meta") - # target_sources prefers absolute pathnames - get_filename_component(ABS_PATH "${FILE}.F90" ABSOLUTE) - LIST(APPEND HOST_SOURCE "${ABS_PATH}") -ENDFOREACH(FILE) -list(APPEND LIBRARY_LIST ${HOST_SOURCE}) -string(REPLACE ";" ".meta," HOST_METADATA "${HOST_FILES}") -set(HOST_METADATA "${HOST_METADATA}.meta,${HOST}.meta") - -string(REPLACE ";" "," SUITE_XML "${SUITE_FILES}") +list(APPEND CAPGEN_HOST_METADATA "${HOST}.meta") -# Run ccpp_capgen -set(CAPGEN_CMD "${CCPP_FRAMEWORK}/ccpp_capgen.py") -list(APPEND CAPGEN_CMD "--host-files") -list(APPEND CAPGEN_CMD "${HOST_METADATA}") -list(APPEND CAPGEN_CMD "--scheme-files") -list(APPEND CAPGEN_CMD "${SCHEME_METADATA}") -list(APPEND CAPGEN_CMD "--suites") -list(APPEND CAPGEN_CMD "${SUITE_XML}") -list(APPEND CAPGEN_CMD "--host-name") -list(APPEND CAPGEN_CMD "test_host") -list(APPEND CAPGEN_CMD "--output-root") -list(APPEND CAPGEN_CMD "${CCPP_CAP_FILES}") -while (VERBOSITY GREATER 0) - list(APPEND CAPGEN_CMD "--verbose") - MATH(EXPR VERBOSITY "${VERBOSITY} - 1") -endwhile () -list(APPEND CAPGEN_CMD "--debug") -string(REPLACE ";" " " CAPGEN_STRING "${CAPGEN_CMD}") -MESSAGE(STATUS "Running: ${CAPGEN_STRING}") -EXECUTE_PROCESS(COMMAND ${CAPGEN_CMD} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE CAPGEN_OUT ERROR_VARIABLE CAPGEN_OUT RESULT_VARIABLE RES) -MESSAGE(STATUS "${CAPGEN_OUT}") -if (RES EQUAL 0) - MESSAGE(STATUS "CCPP cap generation completed") -else(RES EQUAL 0) - MESSAGE(FATAL_ERROR "CCPP cap generation FAILED: result = ${RES}") -endif(RES EQUAL 0) +message(STATUS "CCPP_VERBOSITY = ${CCPP_VERBOSITY}") +ccpp_capgen(CAPGEN_DEBUG ON + VERBOSITY ${CCPP_VERBOSITY} + HOSTFILES ${CAPGEN_HOST_METADATA} + SCHEMEFILES ${SCHEME_FILES} + SUITES ${SUITE_FILES} + HOST_NAME "test_host" + OUTPUT_ROOT "${CCPP_CAP_FILES}") # Retrieve the list of files from datatable.xml and set to CCPP_CAPS -set(DTABLE_CMD "${CCPP_FRAMEWORK}/ccpp_datafile.py") -list(APPEND DTABLE_CMD "${CCPP_CAP_FILES}/datatable.xml") -list(APPEND DTABLE_CMD "--ccpp-files") -list(APPEND DTABLE_CMD "--separator=\\;") -string(REPLACE ";" " " DTABLE_STRING "${DTABLE_CMD}") -MESSAGE(STATUS "Running: ${DTABLE_STRING}") -EXECUTE_PROCESS(COMMAND ${DTABLE_CMD} OUTPUT_VARIABLE CCPP_CAPS - RESULT_VARIABLE RES - OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE) -message(STATUS "CCPP_CAPS = ${CCPP_CAPS}") -if (RES EQUAL 0) - MESSAGE(STATUS "CCPP cap files retrieved") -else(RES EQUAL 0) - MESSAGE(FATAL_ERROR "CCPP cap file retrieval FAILED: result = ${RES}") -endif(RES EQUAL 0) -list(APPEND LIBRARY_LIST ${CCPP_CAPS}) -add_library(TESTLIB OBJECT ${LIBRARY_LIST}) -ADD_EXECUTABLE(${HOST} ${HOST}.F90 $) +ccpp_datafile(DATATABLE "${CCPP_CAP_FILES}/datatable.xml" + REPORT_NAME "--ccpp-files") + +message(STATUS "Adding ${CCPP_CAPS_LIST} to library list") +list(APPEND CAPGEN_LIBRARY_LIST ${CCPP_CAPS_LIST}) +add_library(CAPGEN_TESTLIB OBJECT ${CAPGEN_LIBRARY_LIST}) +add_executable(capgen_${HOST} ${HOST}.F90 $) -INCLUDE_DIRECTORIES(${CCPP_CAP_FILES}) +target_include_directories(capgen_${HOST} PRIVATE ${CCPP_CAP_FILES}) -set_target_properties(${HOST} PROPERTIES - COMPILE_FLAGS "${CMAKE_Fortran_FLAGS}" - LINK_FLAGS "${CMAKE_Fortran_FLAGS}") +add_test(NAME capgen_${HOST} COMMAND capgen_${HOST}) diff --git a/test/capgen_test/README.md b/test/capgen_test/README.md deleted file mode 100644 index 127544e0..00000000 --- a/test/capgen_test/README.md +++ /dev/null @@ -1,6 +0,0 @@ -ccpp_capgen test -=========== - -To build and run the ccpp_capgen test, run ./run_test -This script will build and run the test. -The exit code is zero (0) on PASS and non-zero on FAIL. diff --git a/test/capgen_test/capgen_test_reports.py b/test/capgen_test/capgen_test_reports.py new file mode 100644 index 00000000..78ba5b85 --- /dev/null +++ b/test/capgen_test/capgen_test_reports.py @@ -0,0 +1,247 @@ +#! /usr/bin/env python3 +""" +----------------------------------------------------------------------- + Description: Test capgen database report python interface + + Assumptions: + + Command line arguments: build_dir database_filepath + + Usage: python test_reports +----------------------------------------------------------------------- +""" +import sys +import os +import unittest +import subprocess + +_BUILD_DIR = os.path.join(os.path.abspath(os.environ['BUILD_DIR']), "test", "capgen_test") + +_TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +_FRAMEWORK_DIR = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir)) +_SCRIPTS_DIR = os.path.join(_FRAMEWORK_DIR, "scripts") +_SRC_DIR = os.path.join(_FRAMEWORK_DIR, "src") + +sys.path.append(_SCRIPTS_DIR) +# pylint: disable=wrong-import-position +from ccpp_datafile import datatable_report, DatatableReport +# pylint: enable=wrong-import-position + +_DATABASE = os.path.abspath(os.path.join(_BUILD_DIR, "ccpp", "datatable.xml")) + +# Check data +_HOST_FILES = [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90")] +_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_ddt_suite_cap.F90"), + os.path.join(_BUILD_DIR, "ccpp", "ccpp_temp_suite_cap.F90")] +_UTILITY_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_kinds.F90"), + os.path.join(_SRC_DIR, "ccpp_constituent_prop_mod.F90"), + os.path.join(_SRC_DIR, "ccpp_hashable.F90"), + os.path.join(_SRC_DIR, "ccpp_hash_table.F90")] +_CCPP_FILES = _UTILITY_FILES + \ + [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90"), + os.path.join(_BUILD_DIR, "ccpp", "ccpp_ddt_suite_cap.F90"), + os.path.join(_BUILD_DIR, "ccpp", "ccpp_temp_suite_cap.F90")] +_DEPENDENCIES = [os.path.join(_TEST_DIR, "adjust", "qux.F90"), + os.path.join(_TEST_DIR, "bar.F90"), + os.path.join(_TEST_DIR, "foo.F90")] +_PROCESS_LIST = ["setter=temp_set", "adjusting=temp_calc_adjust"] +_MODULE_LIST = ["environ_conditions", "make_ddt", "setup_coeffs", "temp_adjust", + "temp_calc_adjust", "temp_set"] +_SUITE_LIST = ["ddt_suite", "temp_suite"] +_INPUT_VARS_DDT = ["model_times", "number_of_model_times", + "horizontal_loop_begin", "horizontal_loop_end", + "surface_air_pressure", "horizontal_dimension"] +_OUTPUT_VARS_DDT = ["ccpp_error_code", "ccpp_error_message", "model_times", + "surface_air_pressure", "number_of_model_times"] +_REQUIRED_VARS_DDT = _INPUT_VARS_DDT + _OUTPUT_VARS_DDT +_PROT_VARS_TEMP = ["horizontal_loop_begin", "horizontal_loop_end", + "horizontal_dimension", "vertical_layer_dimension", + "number_of_tracers", + "configuration_variable", + # Added for --debug + "index_of_water_vapor_specific_humidity", + "vertical_interface_dimension"] +_REQUIRED_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", + "potential_temperature", + "potential_temperature_at_interface", + "coefficients_for_interpolation", + "potential_temperature_increment", + "surface_air_pressure", "time_step_for_physics", + "water_vapor_specific_humidity"] +_INPUT_VARS_TEMP = ["potential_temperature", + "potential_temperature_at_interface", + "coefficients_for_interpolation", + "potential_temperature_increment", + "surface_air_pressure", "time_step_for_physics", + "water_vapor_specific_humidity"] +_OUTPUT_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", + "potential_temperature", + "potential_temperature_at_interface", + "coefficients_for_interpolation", + "surface_air_pressure", "water_vapor_specific_humidity"] +_SEP = "," + +class TestCapgenDataTables(unittest.TestCase): + def test_host_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("host_files"), _SEP) + self.assertSetEqual(set(_HOST_FILES), set(test_str.split(_SEP))) + + def test_suite_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("suite_files"), _SEP) + self.assertSetEqual(set(_SUITE_FILES), set(test_str.split(_SEP))) + + def test_utility_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("utility_files"), _SEP) + self.assertSetEqual(set(_UTILITY_FILES), set(test_str.split(_SEP))) + + def test_ccpp_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("ccpp_files"), _SEP) + self.assertSetEqual(set(_CCPP_FILES), set(test_str.split(_SEP))) + + def test_process_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("process_list"), _SEP) + self.assertSetEqual(set(_PROCESS_LIST), set(test_str.split(_SEP))) + + def test_module_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("module_list"), _SEP) + self.assertSetEqual(set(_MODULE_LIST), set(test_str.split(_SEP))) + + def test_dependencies_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("dependencies"), _SEP) + self.assertSetEqual(set(_DEPENDENCIES), set(test_str.split(_SEP))) + + def test_suite_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("suite_list"), _SEP) + self.assertSetEqual(set(_SUITE_LIST), set(test_str.split(_SEP))) + + +class TestDdtSuite(unittest.TestCase): + def test_required_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("required_variables", value="ddt_suite"), _SEP) + self.assertSetEqual(set(_REQUIRED_VARS_DDT), set(test_str.split(_SEP))) + + def test_input_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("input_variables", value="ddt_suite"), _SEP) + self.assertSetEqual(set(_INPUT_VARS_DDT), set(test_str.split(_SEP))) + + def test_output_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("output_variables", value="ddt_suite"), _SEP) + self.assertSetEqual(set(_OUTPUT_VARS_DDT), set(test_str.split(_SEP))) + + +class TestTempSuite(unittest.TestCase): + def test_required_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("required_variables", value="temp_suite"), _SEP) + self.assertSetEqual(set(_REQUIRED_VARS_TEMP + _PROT_VARS_TEMP), set(test_str.split(_SEP))) + + def test_required_variables_excluding_protected(self): + test_str = datatable_report(_DATABASE, DatatableReport("required_variables", value="temp_suite"), _SEP, exclude_protected=True) + self.assertSetEqual(set(_REQUIRED_VARS_TEMP), set(test_str.split(_SEP))) + + def test_input_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("input_variables", value="temp_suite"), _SEP) + self.assertSetEqual(set(_INPUT_VARS_TEMP + _PROT_VARS_TEMP), set(test_str.split(_SEP))) + + def test_input_variables_excluding_protected(self): + test_str = datatable_report(_DATABASE, DatatableReport("input_variables", value="temp_suite"), _SEP, exclude_protected=True) + self.assertSetEqual(set(_INPUT_VARS_TEMP), set(test_str.split(_SEP))) + + def test_output_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("output_variables", value="temp_suite"), _SEP) + self.assertSetEqual(set(_OUTPUT_VARS_TEMP), set(test_str.split(_SEP))) + + +class CommandLineCapgenDatafileRequiredFiles(unittest.TestCase): + def test_host_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--host-files"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_HOST_FILES), actualOutput) + + def test_suite_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--suite-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_SUITE_FILES), completedProcess.stdout.strip()) + + def test_utility_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--utility-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_UTILITY_FILES), completedProcess.stdout.strip()) + + def test_ccpp_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--ccpp-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_CCPP_FILES), completedProcess.stdout.strip()) + + def test_process_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--process-list"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_PROCESS_LIST), actualOutput) + + def test_module_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--module-list"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_MODULE_LIST), completedProcess.stdout.strip()) + + def test_dependencies(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--dependencies"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_DEPENDENCIES), completedProcess.stdout.strip()) + + def test_suite_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--suite-list", "--sep=;"], + capture_output=True, + text=True) + # actualOutput = {s.strip() for s in completedProcess.stdout.split(";")} + self.assertEqual(";".join(_SUITE_LIST), completedProcess.stdout.strip()) + +class CommandLineDdtSuite(unittest.TestCase): + def test_required_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--required-variables", "ddt_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_REQUIRED_VARS_DDT), actualOutput) + + def test_input_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--input-variables", "ddt_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_INPUT_VARS_DDT), actualOutput) + + def test_output_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--output-variables", "ddt_suite"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_OUTPUT_VARS_DDT), completedProcess.stdout.strip()) + +class CommandLineTempSuite(unittest.TestCase): + def test_required_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--required-variables", "temp_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_REQUIRED_VARS_TEMP + _PROT_VARS_TEMP), actualOutput) + + def test_input_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--input-variables", "temp_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_INPUT_VARS_TEMP + _PROT_VARS_TEMP), actualOutput) + + def test_output_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--output-variables", "temp_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_OUTPUT_VARS_TEMP), actualOutput) diff --git a/test/capgen_test/run_test b/test/capgen_test/run_test deleted file mode 100755 index f0b71aa2..00000000 --- a/test/capgen_test/run_test +++ /dev/null @@ -1,284 +0,0 @@ -#! /bin/bash - -currdir="`pwd -P`" -scriptdir="$( cd $( dirname $0 ); pwd -P )" - -## -## Option default values -## -defdir="ct_build" -build_dir="${currdir}/${defdir}" -cleanup="PASS" # Other supported options are ALWAYS and NEVER -verbosity=0 - -## -## General syntax help function -## Usage: help -## -help () { - local hname="Usage: `basename ${0}`" - local hprefix="`echo ${hname} | tr '[!-~]' ' '`" - echo "${hname} [ --build-dir ] [ --cleanup ]" - echo "${hprefix} [ --verbosity <#> ]" - hprefix=" " - echo "" - echo "${hprefix} : Directory for building and running the test" - echo "${hprefix} default is /${defdir}" - echo "${hprefix} : Cleanup option is ALWAYS, NEVER, or PASS" - echo "${hprefix} default is PASS" - echo "${hprefix} verbosity: 0, 1, or 2" - echo "${hprefix} default is 0" - exit $1 -} - -## -## Error output function (should be handed a string) -## -perr() { - >&2 echo -e "\nERROR: ${@}\n" - exit 1 -} - -## -## Cleanup the build and test directory -## -docleanup() { - # We start off in the build directory - if [ "${build_dir}" == "${currdir}" ]; then - echo "WARNING: Cannot clean ${build_dir}" - else - cd ${currdir} - rm -rf ${build_dir} - fi -} - -## Process our input arguments -while [ $# -gt 0 ]; do - case $1 in - --h | -h | --help | -help) - help 0 - ;; - --build-dir) - if [ $# -lt 2 ]; then - perr "${1} requires a build directory" - fi - build_dir="${2}" - shift - ;; - --cleanup) - if [ $# -lt 2 ]; then - perr "${1} requies a cleanup option (ALWAYS, NEVER, PASS)" - fi - if [ "${2}" == "ALWAYS" -o "${2}" == "NEVER" -o "${2}" == "PASS" ]; then - cleanup="${2}" - else - perr "Allowed cleanup options: ALWAYS, NEVER, PASS" - fi - shift - ;; - --verbosity) - if [ $# -lt 2 ]; then - perr "${1} requires a verbosity value (0, 1, or 2)" - fi - if [ "${2}" == "0" -o "${2}" == "1" -o "${2}" == "2" ]; then - verbosity=$2 - else - perr "allowed verbosity levels are 0, 1, 2" - fi - shift - ;; - *) - perr "Unrecognized option, \"${1}\"" - ;; - esac - shift -done - -# Create the build directory, if necessary -if [ -d "${build_dir}" ]; then - # Always make sure build_dir is not in the test dir - if [ "$( cd ${build_dir}; pwd -P )" == "${currdir}" ]; then - build_dir="${build_dir}/${defdir}" - fi -else - mkdir -p ${build_dir} - res=$? - if [ $res -ne 0 ]; then - perr "Unable to create build directory, '${build_dir}'" - fi -fi -build_dir="$( cd ${build_dir}; pwd -P )" - -## framework is the CCPP Framework root dir -framework="$( cd $( dirname $( dirname ${scriptdir} ) ); pwd -P )" -frame_src="${framework}/src" - -## -## check strings for datafile command-list test -## NB: This has to be after build_dir is finalized -## -host_files="${build_dir}/ccpp/test_host_ccpp_cap.F90" -suite_files="${build_dir}/ccpp/ccpp_ddt_suite_cap.F90" -suite_files="${suite_files},${build_dir}/ccpp/ccpp_temp_suite_cap.F90" -utility_files="${build_dir}/ccpp/ccpp_kinds.F90" -utility_files="${utility_files},${frame_src}/ccpp_constituent_prop_mod.F90" -utility_files="${utility_files},${frame_src}/ccpp_hashable.F90" -utility_files="${utility_files},${frame_src}/ccpp_hash_table.F90" -ccpp_files="${utility_files}" -ccpp_files="${ccpp_files},${build_dir}/ccpp/test_host_ccpp_cap.F90" -ccpp_files="${ccpp_files},${build_dir}/ccpp/ccpp_ddt_suite_cap.F90" -ccpp_files="${ccpp_files},${build_dir}/ccpp/ccpp_temp_suite_cap.F90" -process_list="adjusting=temp_calc_adjust,setter=temp_set" -module_list="environ_conditions,make_ddt,setup_coeffs,temp_adjust,temp_calc_adjust,temp_set" -dependencies="${scriptdir}/adjust/qux.F90,${scriptdir}/bar.F90,${scriptdir}/foo.F90" -suite_list="ddt_suite;temp_suite" -required_vars_ddt="ccpp_error_code,ccpp_error_message,horizontal_dimension" -required_vars_ddt="${required_vars_ddt},horizontal_loop_begin" -required_vars_ddt="${required_vars_ddt},horizontal_loop_end" -required_vars_ddt="${required_vars_ddt},model_times" -required_vars_ddt="${required_vars_ddt},number_of_model_times" -required_vars_ddt="${required_vars_ddt},surface_air_pressure" -input_vars_ddt="horizontal_dimension" -input_vars_ddt="${input_vars_ddt},horizontal_loop_begin" -input_vars_ddt="${input_vars_ddt},horizontal_loop_end" -input_vars_ddt="${input_vars_ddt},model_times,number_of_model_times" -input_vars_ddt="${input_vars_ddt},surface_air_pressure" -output_vars_ddt="ccpp_error_code,ccpp_error_message" -output_vars_ddt="${output_vars_ddt},model_times,number_of_model_times,surface_air_pressure" -required_vars_temp="ccpp_error_code,ccpp_error_message" -required_vars_temp="${required_vars_temp},coefficients_for_interpolation" -required_vars_temp="${required_vars_temp},configuration_variable" -required_vars_temp="${required_vars_temp},horizontal_dimension" -required_vars_temp="${required_vars_temp},horizontal_loop_begin" -required_vars_temp="${required_vars_temp},horizontal_loop_end" -required_vars_temp="${required_vars_temp},index_of_water_vapor_specific_humidity" -required_vars_temp="${required_vars_temp},number_of_tracers" -required_vars_temp="${required_vars_temp},potential_temperature" -required_vars_temp="${required_vars_temp},potential_temperature_at_interface" -required_vars_temp="${required_vars_temp},potential_temperature_increment" -required_vars_temp="${required_vars_temp},surface_air_pressure" -required_vars_temp="${required_vars_temp},time_step_for_physics" -required_vars_temp="${required_vars_temp},vertical_interface_dimension" -required_vars_temp="${required_vars_temp},vertical_layer_dimension" -required_vars_temp="${required_vars_temp},water_vapor_specific_humidity" -input_vars_temp="coefficients_for_interpolation" -input_vars_temp="${input_vars_temp},configuration_variable" -input_vars_temp="${input_vars_temp},horizontal_dimension" -input_vars_temp="${input_vars_temp},horizontal_loop_begin" -input_vars_temp="${input_vars_temp},horizontal_loop_end" -input_vars_temp="${input_vars_temp},index_of_water_vapor_specific_humidity" -input_vars_temp="${input_vars_temp},number_of_tracers" -input_vars_temp="${input_vars_temp},potential_temperature" -input_vars_temp="${input_vars_temp},potential_temperature_at_interface" -input_vars_temp="${input_vars_temp},potential_temperature_increment" -input_vars_temp="${input_vars_temp},surface_air_pressure,time_step_for_physics" -input_vars_temp="${input_vars_temp},vertical_interface_dimension" -input_vars_temp="${input_vars_temp},vertical_layer_dimension" -input_vars_temp="${input_vars_temp},water_vapor_specific_humidity" -output_vars_temp="ccpp_error_code,ccpp_error_message" -output_vars_temp="${output_vars_temp},coefficients_for_interpolation" -output_vars_temp="${output_vars_temp},potential_temperature" -output_vars_temp="${output_vars_temp},potential_temperature_at_interface" -output_vars_temp="${output_vars_temp},surface_air_pressure" -output_vars_temp="${output_vars_temp},water_vapor_specific_humidity" - -## -## Run a database report and check the return string -## $1 is the report program file -## $2 is the database file -## $3 is the report string -## $4 is the check string -## $5+ are any optional arguments -## -check_datatable() { - local checkstr=${4} - local teststr - local prog=${1} - local database=${2} - local report=${3} - shift 4 - echo "Checking ${report} report" - teststr="`${prog} ${database} ${report} $@`" - if [ "${teststr}" != "${checkstr}" ]; then - perr "datatable check:\nExpected: '${checkstr}'\nGot: '${teststr}'" - fi -} - -# cd to the build directory -cd ${build_dir} -res=$? -if [ $res -ne 0 ]; then - perr "Unable to cd to build directory, '${build_dir}'" -fi -# Clean build directory -rm -rf * -res=$? -if [ $res -ne 0 ]; then - perr "Unable to clean build directory, '${build_dir}'" -fi -# Run CMake -opts="" -if [ $verbosity -gt 0 ]; then - opts="${opts} -DVERBOSITY=${verbosity}" -fi -# Run cmake -cmake ${scriptdir} ${opts} -res=$? -if [ $res -ne 0 ]; then - perr "CMake failed with exit code, ${res}" -fi -# Test the datafile user interface -report_prog="${framework}/scripts/ccpp_datafile.py" -datafile="${build_dir}/ccpp/datatable.xml" -echo "Running python interface tests" -python3 ${scriptdir}/test_reports.py ${build_dir} ${datafile} -res=$? -if [ $res -ne 0 ]; then - perr "python interface tests failed" -fi -echo "Running command line tests" -echo "Checking required files from command line:" -check_datatable ${report_prog} ${datafile} "--host-files" ${host_files} -check_datatable ${report_prog} ${datafile} "--suite-files" ${suite_files} -check_datatable ${report_prog} ${datafile} "--utility-files" ${utility_files} -check_datatable ${report_prog} ${datafile} "--ccpp-files" ${ccpp_files} -echo -e "\nChecking lists from command line" -check_datatable ${report_prog} ${datafile} "--process-list" ${process_list} -check_datatable ${report_prog} ${datafile} "--module-list" ${module_list} -check_datatable ${report_prog} ${datafile} "--dependencies" ${dependencies} -check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \ - --sep ";" -echo -e "\nChecking variables for DDT suite from command line" -check_datatable ${report_prog} ${datafile} "--required-variables" \ - ${required_vars_ddt} "ddt_suite" -check_datatable ${report_prog} ${datafile} "--input-variables" \ - ${input_vars_ddt} "ddt_suite" -check_datatable ${report_prog} ${datafile} "--output-variables" \ - ${output_vars_ddt} "ddt_suite" -echo -e "\nChecking variables for temp suite from command line" -check_datatable ${report_prog} ${datafile} "--required-variables" \ - ${required_vars_temp} "temp_suite" -check_datatable ${report_prog} ${datafile} "--input-variables" \ - ${input_vars_temp} "temp_suite" -check_datatable ${report_prog} ${datafile} "--output-variables" \ - ${output_vars_temp} "temp_suite" -# Run make -make -res=$? -if [ $res -ne 0 ]; then - perr "make failed with exit code, ${res}" -fi -# Run test -./test_host -res=$? -if [ $res -ne 0 ]; then - perr "test_host failed with exit code, ${res}" -fi - -if [ "${cleanup}" == "ALWAYS" ]; then - docleanup -elif [ $res -eq 0 -a "${cleanup}" == "PASS" ]; then - docleanup -fi - -exit $res diff --git a/test/capgen_test/test_reports.py b/test/capgen_test/test_reports.py deleted file mode 100644 index ed123013..00000000 --- a/test/capgen_test/test_reports.py +++ /dev/null @@ -1,198 +0,0 @@ -#! /usr/bin/env python3 -""" ------------------------------------------------------------------------ - Description: Test capgen database report python interface - - Assumptions: - - Command line arguments: build_dir database_filepath - - Usage: python test_reports ------------------------------------------------------------------------ -""" -import sys -import os - -_TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -_FRAMEWORK_DIR = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir)) -_SCRIPTS_DIR = os.path.join(_FRAMEWORK_DIR, "scripts") -_SRC_DIR = os.path.join(_FRAMEWORK_DIR, "src") - -if not os.path.exists(_SCRIPTS_DIR): - raise ImportError("Cannot find scripts directory") -# end if - -if ((sys.version_info[0] < 3) or - (sys.version_info[0] == 3) and (sys.version_info[1] < 8)): - raise Exception("Python 3.8 or greater required") -# end if - -sys.path.append(_SCRIPTS_DIR) -# pylint: disable=wrong-import-position -from ccpp_datafile import datatable_report, DatatableReport -# pylint: enable=wrong-import-position - -def usage(errmsg=None): - """Raise an exception with optional error message and usage message""" - emsg = "usage: {} " - if errmsg: - emsg = errmsg + '\n' + emsg - # end if - raise ValueError(emsg.format(sys.argv[0])) - -if len(sys.argv) != 3: - usage() -# end if - -_BUILD_DIR = os.path.abspath(sys.argv[1]) -_DATABASE = os.path.abspath(sys.argv[2]) -if not os.path.isdir(_BUILD_DIR): - _EMSG = " must be an existing build directory" - usage(_EMSG) -# end if -if (not os.path.exists(_DATABASE)) or (not os.path.isfile(_DATABASE)): - _EMSG = " must be an existing CCPP database file" - usage(_EMSG) -# end if - -# Check data -_HOST_FILES = [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90")] -_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_ddt_suite_cap.F90"), - os.path.join(_BUILD_DIR, "ccpp", "ccpp_temp_suite_cap.F90")] -_UTILITY_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_kinds.F90"), - os.path.join(_SRC_DIR, "ccpp_constituent_prop_mod.F90"), - os.path.join(_SRC_DIR, "ccpp_hashable.F90"), - os.path.join(_SRC_DIR, "ccpp_hash_table.F90")] -_CCPP_FILES = _UTILITY_FILES + \ - [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90"), - os.path.join(_BUILD_DIR, "ccpp", "ccpp_ddt_suite_cap.F90"), - os.path.join(_BUILD_DIR, "ccpp", "ccpp_temp_suite_cap.F90")] -_PROCESS_LIST = ["setter=temp_set", "adjusting=temp_calc_adjust"] -_MODULE_LIST = ["environ_conditions", "make_ddt", "setup_coeffs", "temp_adjust", - "temp_calc_adjust", "temp_set"] -_SUITE_LIST = ["ddt_suite", "temp_suite"] -_INPUT_VARS_DDT = ["model_times", "number_of_model_times", - "horizontal_loop_begin", "horizontal_loop_end", - "surface_air_pressure", "horizontal_dimension"] -_OUTPUT_VARS_DDT = ["ccpp_error_code", "ccpp_error_message", "model_times", - "surface_air_pressure", "number_of_model_times"] -_REQUIRED_VARS_DDT = _INPUT_VARS_DDT + _OUTPUT_VARS_DDT -_PROT_VARS_TEMP = ["horizontal_loop_begin", "horizontal_loop_end", - "horizontal_dimension", "vertical_layer_dimension", - "number_of_tracers", - "configuration_variable", - # Added for --debug - "index_of_water_vapor_specific_humidity", - "vertical_interface_dimension"] -_REQUIRED_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", - "potential_temperature", - "potential_temperature_at_interface", - "coefficients_for_interpolation", - "potential_temperature_increment", - "surface_air_pressure", "time_step_for_physics", - "water_vapor_specific_humidity"] -_INPUT_VARS_TEMP = ["potential_temperature", - "potential_temperature_at_interface", - "coefficients_for_interpolation", - "potential_temperature_increment", - "surface_air_pressure", "time_step_for_physics", - "water_vapor_specific_humidity"] -_OUTPUT_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", - "potential_temperature", - "potential_temperature_at_interface", - "coefficients_for_interpolation", - "surface_air_pressure", "water_vapor_specific_humidity"] - -def fields_string(field_type, field_list, sep): - """Create an error string for field(s), . - is used to separate items in """ - indent = ' '*11 - if field_list: - if len(field_list) > 1: - field_str = "{} Fields: ".format(field_type) - else: - field_str = "{} Field: ".format(field_type) - # end if - fmsg = "\n{}{}{}".format(indent, field_str, sep.join(field_list)) - else: - fmsg = "" - # end if - return fmsg - -def check_datatable(database, report_type, check_list, - sep=',', exclude_protected=False): - """Run a database report and check the return string. - If an error is found, print an error message. - Return the number of errors""" - if sep is None: - sep = ',' - # end if - test_str = datatable_report(database, report_type, sep, exclude_protected=exclude_protected) - test_list = [x for x in test_str.split(sep) if x] - missing = list() - unexpected = list() - for item in check_list: - if item not in test_list: - missing.append(item) - # end if - # end for - for item in test_list: - if item not in check_list: - unexpected.append(item) - # end if - # end for - if missing or unexpected: - vmsg = "ERROR in {} datafile check:".format(report_type.action) - vmsg += fields_string("Missing", missing, sep) - vmsg += fields_string("Unexpected", unexpected, sep) - print(vmsg) - else: - print("{} report okay".format(report_type.action)) - # end if - return len(missing) + len(unexpected) - -NUM_ERRORS = 0 -print("Checking required files from python:") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("host_files"), - _HOST_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_files"), - _SUITE_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("utility_files"), - _UTILITY_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("ccpp_files"), - _CCPP_FILES) -print("\nChecking lists from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("process_list"), - _PROCESS_LIST) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("module_list"), - _MODULE_LIST) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_list"), - _SUITE_LIST) -print("\nChecking variables for DDT suite from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", - value="ddt_suite"), - _REQUIRED_VARS_DDT) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", - value="ddt_suite"), - _INPUT_VARS_DDT) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("output_variables", - value="ddt_suite"), - _OUTPUT_VARS_DDT) -print("\nChecking variables for temp suite from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", - value="temp_suite"), - _REQUIRED_VARS_TEMP + _PROT_VARS_TEMP) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", - value="temp_suite"), - _REQUIRED_VARS_TEMP, exclude_protected=True) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", - value="temp_suite"), - _INPUT_VARS_TEMP + _PROT_VARS_TEMP) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", - value="temp_suite"), - _INPUT_VARS_TEMP, exclude_protected=True) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("output_variables", - value="temp_suite"), - _OUTPUT_VARS_TEMP) - -sys.exit(NUM_ERRORS) diff --git a/test/ddthost_test/CMakeLists.txt b/test/ddthost_test/CMakeLists.txt index 5bbe196d..4d216d94 100644 --- a/test/ddthost_test/CMakeLists.txt +++ b/test/ddthost_test/CMakeLists.txt @@ -1,30 +1,16 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.15) -PROJECT(test_host) -ENABLE_LANGUAGE(Fortran) -include(CMakeForceCompiler) - -SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules) - -#------------------------------------------------------------------------------ -# -# Set where the CCPP Framework lives -# -#------------------------------------------------------------------------------ -get_filename_component(TEST_ROOT "${CMAKE_SOURCE_DIR}" DIRECTORY) -get_filename_component(CCPP_ROOT "${TEST_ROOT}" DIRECTORY) #------------------------------------------------------------------------------ # # Create list of SCHEME_FILES, HOST_FILES, and SUITE_FILES # Paths should be relative to CMAKE_SOURCE_DIR (this file's directory) # #------------------------------------------------------------------------------ -LIST(APPEND SCHEME_FILES "temp_scheme_files.txt" "ddt_suite_files.txt") -LIST(APPEND HOST_FILES "test_host_data" "test_host_mod" "host_ccpp_ddt") -LIST(APPEND SUITE_FILES "ddt_suite.xml" "temp_suite.xml") +set(SCHEME_FILES "temp_scheme_files.txt" "ddt_suite_files.txt") +set(HOST_FILES "test_host_data" "test_host_mod" "host_ccpp_ddt") +set(SUITE_FILES "ddt_suite.xml" "temp_suite.xml") # HOST is the name of the executable we will build. # We assume there are files ${HOST}.meta and ${HOST}.F90 in CMAKE_SOURCE_DIR -SET(HOST "${CMAKE_PROJECT_NAME}") +set(HOST "test_host") #------------------------------------------------------------------------------ # @@ -32,160 +18,45 @@ SET(HOST "${CMAKE_PROJECT_NAME}") # #------------------------------------------------------------------------------ -# By default, no verbose output -SET(VERBOSITY 0 CACHE STRING "Verbosity level of output (default: 0)") # By default, generated caps go in ccpp subdir -SET(CCPP_CAP_FILES "${CMAKE_BINARY_DIR}/ccpp" CACHE - STRING "Location of CCPP-generated cap files") - -SET(CCPP_FRAMEWORK ${CCPP_ROOT}/scripts) - -# Use rpaths on MacOSX -set(CMAKE_MACOSX_RPATH 1) - -#------------------------------------------------------------------------------ -# Set a default build type if none was specified -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - #message(STATUS "Setting build type to 'Debug' as none was specified.") - #set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) - message(STATUS "Setting build type to 'Release' as none was specified.") - set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) - - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" - "MinSizeRel" "RelWithDebInfo") -endif() - -ADD_COMPILE_OPTIONS(-O0) - -if (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") -# gfortran -# MESSAGE("gfortran being used.") - ADD_COMPILE_OPTIONS(-fcheck=all) - ADD_COMPILE_OPTIONS(-fbacktrace) - ADD_COMPILE_OPTIONS(-ffpe-trap=zero) - ADD_COMPILE_OPTIONS(-finit-real=nan) - ADD_COMPILE_OPTIONS(-ggdb) - ADD_COMPILE_OPTIONS(-ffree-line-length-none) - ADD_COMPILE_OPTIONS(-cpp) -elseif (${CMAKE_Fortran_COMPILER_ID} MATCHES "Intel") -# ifort -# MESSAGE("ifort being used.") - #ADD_COMPILE_OPTIONS(-check all) - ADD_COMPILE_OPTIONS(-fpe0) - ADD_COMPILE_OPTIONS(-warn) - ADD_COMPILE_OPTIONS(-traceback) - ADD_COMPILE_OPTIONS(-debug extended) - ADD_COMPILE_OPTIONS(-fpp) -elseif (${CMAKE_Fortran_COMPILER_ID} MATCHES "PGI") -# pgf90 -# MESSAGE("pgf90 being used.") - ADD_COMPILE_OPTIONS(-g) - ADD_COMPILE_OPTIONS(-Mipa=noconst) - ADD_COMPILE_OPTIONS(-traceback) - ADD_COMPILE_OPTIONS(-Mfree) - ADD_COMPILE_OPTIONS(-Mfptrap) - ADD_COMPILE_OPTIONS(-Mpreprocess) -else (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") - message (WARNING "This program has only been compiled with gfortran, pgf90 and ifort. If another compiler is needed, the appropriate flags SHOULD be added in ${CMAKE_SOURCE_DIR}/CMakeLists.txt") -endif (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") - -#------------------------------------------------------------------------------ -# CMake Modules -# Set the CMake module path -list(APPEND CMAKE_MODULE_PATH "${CCPP_FRAMEWORK}/cmake") -#------------------------------------------------------------------------------ -# Set OpenMP flags for C/C++/Fortran -if (OPENMP) - include(detect_openmp) - detect_openmp() - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}") - message(STATUS "Enable OpenMP support for C/C++/Fortran compiler") -else(OPENMP) - message (STATUS "Disable OpenMP support for C/C++/Fortran compiler") -endif() +set(CCPP_CAP_FILES "${CMAKE_CURRENT_BINARY_DIR}/ccpp") # Create metadata and source file lists -FOREACH(FILE ${SCHEME_FILES}) - FILE(STRINGS ${FILE} FILENAMES) - LIST(APPEND SCHEME_FILENAMES ${FILENAMES}) -ENDFOREACH(FILE) -string(REPLACE ";" "," SCHEME_METADATA "${SCHEME_FILES}") - -FOREACH(FILE ${SCHEME_FILENAMES}) +foreach(SCHEME_FILE ${SCHEME_FILES}) + file(STRINGS ${SCHEME_FILE} FILENAMES) + foreach(filename ${FILENAMES}) + string(REPLACE ".meta" ".F90" TEMP "${filename}") + file(REAL_PATH "${TEMP}" ABS_PATH) + list(APPEND DDT_LIBRARY_LIST "${ABS_PATH}") + endforeach() +endforeach() + +foreach(FILE ${HOST_FILES}) + list(APPEND DDT_HOST_METADATA "${FILE}.meta") # target_sources prefers absolute pathnames - string(REPLACE ".meta" ".F90" TEMP "${FILE}") - get_filename_component(ABS_PATH "${TEMP}" ABSOLUTE) - list(APPEND LIBRARY_LIST ${ABS_PATH}) -ENDFOREACH(FILE) + file(REAL_PATH "${FILE}.F90" ABS_PATH) + list(APPEND DDT_LIBRARY_LIST "${ABS_PATH}") +endforeach() -FOREACH(FILE ${HOST_FILES}) - LIST(APPEND HOST_METADATA "${FILE}.meta") - # target_sources prefers absolute pathnames - get_filename_component(ABS_PATH "${FILE}.F90" ABSOLUTE) - LIST(APPEND HOST_SOURCE "${ABS_PATH}") -ENDFOREACH(FILE) -list(APPEND LIBRARY_LIST ${HOST_SOURCE}) -string(REPLACE ";" ".meta," HOST_METADATA "${HOST_FILES}") -set(HOST_METADATA "${HOST_METADATA}.meta,${HOST}.meta") - -string(REPLACE ";" "," SUITE_XML "${SUITE_FILES}") +list(APPEND DDT_HOST_METADATA "${HOST}.meta") # Run ccpp_capgen -set(CAPGEN_CMD "${CCPP_FRAMEWORK}/ccpp_capgen.py") -list(APPEND CAPGEN_CMD "--host-files") -list(APPEND CAPGEN_CMD "${HOST_METADATA}") -list(APPEND CAPGEN_CMD "--scheme-files") -list(APPEND CAPGEN_CMD "${SCHEME_METADATA}") -list(APPEND CAPGEN_CMD "--suites") -list(APPEND CAPGEN_CMD "${SUITE_XML}") -list(APPEND CAPGEN_CMD "--host-name") -list(APPEND CAPGEN_CMD "test_host") -list(APPEND CAPGEN_CMD "--output-root") -list(APPEND CAPGEN_CMD "${CCPP_CAP_FILES}") -string(REPEAT "--verbose;" ${VERBOSITY} VERBOSE_REPEATED) -list(APPEND CAPGEN_CMD ${VERBOSE_REPEATED}) -list(APPEND CAPGEN_CMD "--debug") -string(REPLACE ";" " " CAPGEN_STRING "${CAPGEN_CMD}") -MESSAGE(STATUS "Running: ${CAPGEN_STRING}") -EXECUTE_PROCESS(COMMAND ${CAPGEN_CMD} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE CAPGEN_OUT - ERROR_VARIABLE CAPGEN_OUT - RESULT_VARIABLE RES) -MESSAGE(STATUS "${CAPGEN_OUT}") -if (RES EQUAL 0) - MESSAGE(STATUS "CCPP cap generation completed") -else(RES EQUAL 0) - MESSAGE(FATAL_ERROR "CCPP cap generation FAILED: result = ${RES}") -endif(RES EQUAL 0) +ccpp_capgen(CAPGEN_DEBUG ON + VERBOSITY ${CCPP_VERBOSITY} + HOSTFILES ${DDT_HOST_METADATA} + SCHEMEFILES ${SCHEME_FILES} + SUITES ${SUITE_FILES} + HOST_NAME "test_host" + OUTPUT_ROOT "${CCPP_CAP_FILES}") + +# Retrieve the list of files from datatable.xml and set to CCPP_CAPS_LIST +ccpp_datafile(DATATABLE "${CCPP_CAP_FILES}/datatable.xml" + REPORT_NAME "--ccpp-files") -# Retrieve the list of files from datatable.xml and set to CCPP_CAPS -set(DTABLE_CMD "${CCPP_FRAMEWORK}/ccpp_datafile.py") -list(APPEND DTABLE_CMD "${CCPP_CAP_FILES}/datatable.xml") -list(APPEND DTABLE_CMD "--ccpp-files") -list(APPEND DTABLE_CMD "--separator=\\;") -string(REPLACE ";" " " DTABLE_STRING "${DTABLE_CMD}") -MESSAGE(STATUS "Running: ${DTABLE_STRING}") -EXECUTE_PROCESS(COMMAND ${DTABLE_CMD} - OUTPUT_VARIABLE CCPP_CAPS - RESULT_VARIABLE RES - OUTPUT_STRIP_TRAILING_WHITESPACE - ERROR_STRIP_TRAILING_WHITESPACE) -message(STATUS "CCPP_CAPS = ${CCPP_CAPS}") -if (RES EQUAL 0) - MESSAGE(STATUS "CCPP cap files retrieved") -else(RES EQUAL 0) - MESSAGE(FATAL_ERROR "CCPP cap file retrieval FAILED: result = ${RES}") -endif(RES EQUAL 0) -list(APPEND LIBRARY_LIST ${CCPP_CAPS}) -add_library(TESTLIB OBJECT ${LIBRARY_LIST}) -ADD_EXECUTABLE(${HOST} ${HOST}.F90 $) +list(APPEND DDT_LIBRARY_LIST ${CCPP_CAPS_LIST}) +add_library(DDT_TESTLIB OBJECT ${DDT_LIBRARY_LIST}) +add_executable(ddt_${HOST} ${HOST}.F90 $) -INCLUDE_DIRECTORIES(${CCPP_CAP_FILES}) +target_include_directories(ddt_${HOST} PRIVATE ${CCPP_CAP_FILES}) -set_target_properties(${HOST} PROPERTIES - COMPILE_FLAGS "${CMAKE_Fortran_FLAGS}" - LINK_FLAGS "${CMAKE_Fortran_FLAGS}") +add_test(NAME ddt_${HOST} COMMAND ddt_${HOST}) diff --git a/test/ddthost_test/ddthost_test_reports.py b/test/ddthost_test/ddthost_test_reports.py new file mode 100644 index 00000000..7d5fe474 --- /dev/null +++ b/test/ddthost_test/ddthost_test_reports.py @@ -0,0 +1,278 @@ +#! /usr/bin/env python3 +""" +----------------------------------------------------------------------- + Description: Test capgen database report python interface + + Assumptions: + + Command line arguments: build_dir database_filepath + + Usage: python test_reports +----------------------------------------------------------------------- +""" +import sys +import os +import unittest +import subprocess + +_BUILD_DIR = os.path.join(os.path.abspath(os.environ['BUILD_DIR']), "test", "ddthost_test") + +_TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +_FRAMEWORK_DIR = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir)) +_SCRIPTS_DIR = os.path.join(_FRAMEWORK_DIR, "scripts") +_SRC_DIR = os.path.join(_FRAMEWORK_DIR, "src") + +sys.path.append(_SCRIPTS_DIR) +# pylint: disable=wrong-import-position +from ccpp_datafile import datatable_report, DatatableReport +# pylint: enable=wrong-import-position + +_DATABASE = os.path.abspath(os.path.join(_BUILD_DIR, "ccpp", "datatable.xml")) + +# Check data +_HOST_FILES = [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90")] +_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_ddt_suite_cap.F90"), + os.path.join(_BUILD_DIR, "ccpp", "ccpp_temp_suite_cap.F90")] +_UTILITY_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_kinds.F90"), + os.path.join(_SRC_DIR, "ccpp_constituent_prop_mod.F90"), + os.path.join(_SRC_DIR, "ccpp_hashable.F90"), + os.path.join(_SRC_DIR, "ccpp_hash_table.F90")] +_CCPP_FILES = _UTILITY_FILES + \ + [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90"), + os.path.join(_BUILD_DIR, "ccpp", "ccpp_ddt_suite_cap.F90"), + os.path.join(_BUILD_DIR, "ccpp", "ccpp_temp_suite_cap.F90")] +_DEPENDENCIES = [os.path.join(_TEST_DIR, "adjust", "qux.F90"), + os.path.join(_TEST_DIR, "bar.F90"), + os.path.join(_TEST_DIR, "foo.F90")] +_PROCESS_LIST = ["setter=temp_set", "adjusting=temp_calc_adjust"] +_MODULE_LIST = ["environ_conditions", "make_ddt", "setup_coeffs", "temp_adjust", + "temp_calc_adjust", "temp_set"] +_SUITE_LIST = ["ddt_suite", "temp_suite"] +_INPUT_VARS_DDT = ["model_times", "number_of_model_times", + "horizontal_loop_begin", "horizontal_loop_end", + "surface_air_pressure", "horizontal_dimension"] +_OUTPUT_VARS_DDT = ["ccpp_error_code", "ccpp_error_message", "model_times", + "number_of_model_times", "surface_air_pressure"] +_REQUIRED_VARS_DDT = _INPUT_VARS_DDT + _OUTPUT_VARS_DDT +_PROT_VARS_TEMP = ["horizontal_loop_begin", "horizontal_loop_end", + "horizontal_dimension", "vertical_layer_dimension", + "number_of_tracers", + # Added for --debug + "index_of_water_vapor_specific_humidity", + "vertical_interface_dimension"] +_REQUIRED_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", + "potential_temperature", + "potential_temperature_at_interface", + "coefficients_for_interpolation", + "potential_temperature_increment", + "surface_air_pressure", "time_step_for_physics", + "water_vapor_specific_humidity"] +_INPUT_VARS_TEMP = ["potential_temperature", + "potential_temperature_at_interface", + "coefficients_for_interpolation", + "potential_temperature_increment", + "surface_air_pressure", "time_step_for_physics", + "water_vapor_specific_humidity"] +_OUTPUT_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", + "potential_temperature", + "potential_temperature_at_interface", + "coefficients_for_interpolation", + "surface_air_pressure", "water_vapor_specific_humidity"] +_SEP = "," + +class TestDdtHostDataTables(unittest.TestCase): + def test_host_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("host_files"), _SEP) + self.assertSetEqual(set(_HOST_FILES), set(test_str.split(_SEP))) + + def test_suite_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("suite_files"), _SEP) + self.assertSetEqual(set(_SUITE_FILES), set(test_str.split(_SEP))) + + def test_utility_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("utility_files"), _SEP) + self.assertSetEqual(set(_UTILITY_FILES), set(test_str.split(_SEP))) + + def test_ccpp_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("ccpp_files"), _SEP) + self.assertSetEqual(set(_CCPP_FILES), set(test_str.split(_SEP))) + + def test_process_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("process_list"), _SEP) + self.assertSetEqual(set(_PROCESS_LIST), set(test_str.split(_SEP))) + + def test_module_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("module_list"), _SEP) + self.assertSetEqual(set(_MODULE_LIST), set(test_str.split(_SEP))) + + def test_dependencies_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("dependencies"), _SEP) + self.assertSetEqual(set(_DEPENDENCIES), set(test_str.split(_SEP))) + + def test_suite_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("suite_list"), _SEP) + self.assertSetEqual(set(_SUITE_LIST), set(test_str.split(_SEP))) + + +class CommandLineDdtHostDatafileRequiredFiles(unittest.TestCase): + def test_host_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--host-files"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_HOST_FILES), actualOutput) + + def test_suite_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--suite-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_SUITE_FILES), completedProcess.stdout.strip()) + + def test_utility_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--utility-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_UTILITY_FILES), completedProcess.stdout.strip()) + + def test_ccpp_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--ccpp-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_CCPP_FILES), completedProcess.stdout.strip()) + + def test_process_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--process-list"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_PROCESS_LIST), actualOutput) + + def test_module_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--module-list"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_MODULE_LIST), completedProcess.stdout.strip()) + + def test_dependencies(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--dependencies"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_DEPENDENCIES), completedProcess.stdout.strip()) + + def test_suite_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--suite-list", "--sep=;"], + capture_output=True, + text=True) + # actualOutput = {s.strip() for s in completedProcess.stdout.split(";")} + self.assertEqual(";".join(_SUITE_LIST), completedProcess.stdout.strip()) + + +class TestDdtSuite(unittest.TestCase): + def test_required_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("required_variables", value="ddt_suite"), _SEP) + self.assertSetEqual(set(_REQUIRED_VARS_DDT), set(test_str.split(_SEP))) + + def test_input_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("input_variables", value="ddt_suite"), _SEP) + self.assertSetEqual(set(_INPUT_VARS_DDT), set(test_str.split(_SEP))) + + def test_output_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("output_variables", value="ddt_suite"), _SEP) + self.assertSetEqual(set(_OUTPUT_VARS_DDT), set(test_str.split(_SEP))) + + +class CommandLineDddtSuite(unittest.TestCase): + def test_required_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--required-variables", "ddt_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_REQUIRED_VARS_DDT), actualOutput) + + def test_input_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--input-variables", "ddt_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_INPUT_VARS_DDT), actualOutput) + + def test_output_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--output-variables", "ddt_suite"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_OUTPUT_VARS_DDT), completedProcess.stdout.strip()) + + +class TestTempSuite(unittest.TestCase): + def test_required_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("required_variables", value="temp_suite"), _SEP) + self.assertSetEqual(set(_REQUIRED_VARS_TEMP + _PROT_VARS_TEMP), set(test_str.split(_SEP))) + + def test_required_variables_excluding_protected(self): + test_str = datatable_report(_DATABASE, DatatableReport("required_variables", value="temp_suite"), _SEP, exclude_protected=True) + self.assertSetEqual(set(_REQUIRED_VARS_TEMP), set(test_str.split(_SEP))) + + def test_input_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("input_variables", value="temp_suite"), _SEP) + self.assertSetEqual(set(_INPUT_VARS_TEMP + _PROT_VARS_TEMP), set(test_str.split(_SEP))) + + def test_input_variables_excluding_protected(self): + test_str = datatable_report(_DATABASE, DatatableReport("input_variables", value="temp_suite"), _SEP, exclude_protected=True) + self.assertSetEqual(set(_INPUT_VARS_TEMP), set(test_str.split(_SEP))) + + def test_output_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("output_variables", value="temp_suite"), _SEP) + self.assertSetEqual(set(_OUTPUT_VARS_TEMP), set(test_str.split(_SEP))) + + +class CommandLineTempSuite(unittest.TestCase): + def test_required_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--required-variables", "temp_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_REQUIRED_VARS_TEMP + _PROT_VARS_TEMP), actualOutput) + + def test_input_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--input-variables", "temp_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_INPUT_VARS_TEMP + _PROT_VARS_TEMP), actualOutput) + + def test_output_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--output-variables", "temp_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_OUTPUT_VARS_TEMP), actualOutput) + + +# print("\nChecking variables for DDT suite from python") +# NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", +# value="ddt_suite"), +# _REQUIRED_VARS_DDT) +# NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", +# value="ddt_suite"), +# _INPUT_VARS_DDT) +# NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("output_variables", +# value="ddt_suite"), +# _OUTPUT_VARS_DDT) +# print("\nChecking variables for temp suite from python") +# NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", +# value="temp_suite"), +# _REQUIRED_VARS_TEMP + _PROT_VARS_TEMP) +# NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", +# value="temp_suite"), +# _REQUIRED_VARS_TEMP, exclude_protected=True) +# NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", +# value="temp_suite"), +# _INPUT_VARS_TEMP + _PROT_VARS_TEMP) +# NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", +# value="temp_suite"), +# _INPUT_VARS_TEMP, exclude_protected=True) +# NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("output_variables", +# value="temp_suite"), +# _OUTPUT_VARS_TEMP) + +# sys.exit(NUM_ERRORS) diff --git a/test/ddthost_test/test_reports.py b/test/ddthost_test/test_reports.py deleted file mode 100644 index aae9098b..00000000 --- a/test/ddthost_test/test_reports.py +++ /dev/null @@ -1,178 +0,0 @@ -#! /usr/bin/env python3 -""" ------------------------------------------------------------------------ - Description: Test capgen database report python interface - - Assumptions: - - Command line arguments: build_dir database_filepath - - Usage: python test_reports ------------------------------------------------------------------------ -""" -import sys -import os - -_TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -_FRAMEWORK_DIR = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir)) -_SCRIPTS_DIR = os.path.join(_FRAMEWORK_DIR, "scripts") -_SRC_DIR = os.path.join(_FRAMEWORK_DIR, "src") - -if not os.path.exists(_SCRIPTS_DIR): - raise ImportError("Cannot find scripts directory") -# end if - -sys.path.append(_SCRIPTS_DIR) -# pylint: disable=wrong-import-position -from ccpp_datafile import datatable_report, DatatableReport -# pylint: enable=wrong-import-position - -import argparse - -parser = argparse.ArgumentParser(description="Test capgen database report python interface") -parser.add_argument('build_dir') -parser.add_argument('database_filepath') -if len(sys.argv) > 3: - parser.error("Too many arguments") -# end if -args = parser.parse_args() -_BUILD_DIR = os.path.abspath(args.build_dir) -_DATABASE = os.path.abspath(args.database_filepath) -if not os.path.isdir(_BUILD_DIR): - parser.error(" must be an existing build directory") -# end if -if (not os.path.exists(_DATABASE)) or (not os.path.isfile(_DATABASE)): - parser.error(" must be an existing CCPP database file") -# end if - -# Check data -_HOST_FILES = [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90")] -_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_ddt_suite_cap.F90"), - os.path.join(_BUILD_DIR, "ccpp", "ccpp_temp_suite_cap.F90")] -_UTILITY_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_kinds.F90"), - os.path.join(_SRC_DIR, "ccpp_constituent_prop_mod.F90"), - os.path.join(_SRC_DIR, "ccpp_hashable.F90"), - os.path.join(_SRC_DIR, "ccpp_hash_table.F90")] -_CCPP_FILES = _UTILITY_FILES + \ - [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90"), - os.path.join(_BUILD_DIR, "ccpp", "ccpp_ddt_suite_cap.F90"), - os.path.join(_BUILD_DIR, "ccpp", "ccpp_temp_suite_cap.F90")] -_PROCESS_LIST = ["setter=temp_set", "adjusting=temp_calc_adjust"] -_MODULE_LIST = ["environ_conditions", "make_ddt", "setup_coeffs", "temp_adjust", - "temp_calc_adjust", "temp_set"] -_SUITE_LIST = ["ddt_suite", "temp_suite"] -_INPUT_VARS_DDT = ["model_times", "number_of_model_times", - "horizontal_loop_begin", "horizontal_loop_end", - "surface_air_pressure", "horizontal_dimension"] -_OUTPUT_VARS_DDT = ["ccpp_error_code", "ccpp_error_message", "model_times", - "number_of_model_times", "surface_air_pressure"] -_REQUIRED_VARS_DDT = _INPUT_VARS_DDT + _OUTPUT_VARS_DDT -_PROT_VARS_TEMP = ["horizontal_loop_begin", "horizontal_loop_end", - "horizontal_dimension", "vertical_layer_dimension", - "number_of_tracers", - # Added for --debug - "index_of_water_vapor_specific_humidity", - "vertical_interface_dimension"] -_REQUIRED_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", - "potential_temperature", - "potential_temperature_at_interface", - "coefficients_for_interpolation", - "potential_temperature_increment", - "surface_air_pressure", "time_step_for_physics", - "water_vapor_specific_humidity"] -_INPUT_VARS_TEMP = ["potential_temperature", - "potential_temperature_at_interface", - "coefficients_for_interpolation", - "potential_temperature_increment", - "surface_air_pressure", "time_step_for_physics", - "water_vapor_specific_humidity"] -_OUTPUT_VARS_TEMP = ["ccpp_error_code", "ccpp_error_message", - "potential_temperature", - "potential_temperature_at_interface", - "coefficients_for_interpolation", - "surface_air_pressure", "water_vapor_specific_humidity"] - -def fields_string(field_type, field_list, sep): - """Create an error string for field(s), . - is used to separate items in """ - indent = ' '*11 - fmsg = "" - if field_list: - if len(field_list) > 1: - field_str = f"{field_type} Fields: " - else: - field_str = f"{field_type} Field: " - # end if - fmsg = f"\n{indent}{field_str}{sep.join(sorted(field_list))}" - # end if - return fmsg - -def check_datatable(database, report_type, check_list, - sep=',', exclude_protected=False): - """Run a database report and check the return string. - If an error is found, print an error message. - Return the number of errors""" - if sep is None: - sep = ',' - # end if - test_str = datatable_report(database, report_type, sep, exclude_protected=exclude_protected) - test_list = [x for x in test_str.split(sep) if x] - tests_run = set(test_list) - expected_tests = set(check_list) - missing = expected_tests - tests_run - unexpected = tests_run - expected_tests - if missing or unexpected: - vmsg = f"ERROR in {report_type.action} datafile check:" - vmsg += fields_string("Missing", missing, sep) - vmsg += fields_string("Unexpected", unexpected, sep) - print(vmsg) - else: - print(f"{report_type.action} report okay") - # end if - return len(missing) + len(unexpected) - -NUM_ERRORS = 0 -print("Checking required files from python:") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("host_files"), - _HOST_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_files"), - _SUITE_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("utility_files"), - _UTILITY_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("ccpp_files"), - _CCPP_FILES) -print("\nChecking lists from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("process_list"), - _PROCESS_LIST) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("module_list"), - _MODULE_LIST) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_list"), - _SUITE_LIST) -print("\nChecking variables for DDT suite from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", - value="ddt_suite"), - _REQUIRED_VARS_DDT) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", - value="ddt_suite"), - _INPUT_VARS_DDT) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("output_variables", - value="ddt_suite"), - _OUTPUT_VARS_DDT) -print("\nChecking variables for temp suite from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", - value="temp_suite"), - _REQUIRED_VARS_TEMP + _PROT_VARS_TEMP) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", - value="temp_suite"), - _REQUIRED_VARS_TEMP, exclude_protected=True) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", - value="temp_suite"), - _INPUT_VARS_TEMP + _PROT_VARS_TEMP) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", - value="temp_suite"), - _INPUT_VARS_TEMP, exclude_protected=True) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("output_variables", - value="temp_suite"), - _OUTPUT_VARS_TEMP) - -sys.exit(NUM_ERRORS) diff --git a/test/pylint_test.sh b/test/pylint_test.sh deleted file mode 100755 index a8bf3f90..00000000 --- a/test/pylint_test.sh +++ /dev/null @@ -1,28 +0,0 @@ -#! /bin/bash - -# Script to run pylint tests on CCPP Framework python scripts - -# Add CCPP Framework paths to PYTHONPATH so pylint can find them -SCRIPTDIR="$( cd $( dirname ${0} ); pwd -P )" -SPINROOT="$( dirname ${SCRIPTDIR} )" -CCPPDIR="${SPINROOT}/scripts" -export PYTHONPATH="${CCPPDIR}:$PYTHONPATH" - -pylintcmd="pylint --rcfile=${SCRIPTDIR}/.pylintrc" - -# Test top-level scripts -scripts="${CCPPDIR}/ccpp_capgen.py" -scripts="${scripts} ${CCPPDIR}/ccpp_suite.py" -scripts="${scripts} ${CCPPDIR}/ddt_library.py" -scripts="${scripts} ${CCPPDIR}/host_cap.py" -scripts="${scripts} ${CCPPDIR}/host_model.py" -scripts="${scripts} ${CCPPDIR}/metadata_table.py" -scripts="${scripts} ${CCPPDIR}/metavar.py" -scripts="${scripts} ${CCPPDIR}/state_machine.py" -${pylintcmd} ${scripts} -# Test the fortran_tools module -${pylintcmd} ${CCPPDIR}/fortran_tools -# Test the parse_tools module -${pylintcmd} ${CCPPDIR}/parse_tools -# Test the fortran to metadata converter tool -${pylintcmd} ${CCPPDIR}/ccpp_fortran_to_metadata.py diff --git a/test/var_compatibility_test/.gitignore b/test/var_compatibility_test/.gitignore deleted file mode 100644 index 378eac25..00000000 --- a/test/var_compatibility_test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build diff --git a/test/var_compatibility_test/CMakeLists.txt b/test/var_compatibility_test/CMakeLists.txt index 8cbd7e44..a549ef56 100644 --- a/test/var_compatibility_test/CMakeLists.txt +++ b/test/var_compatibility_test/CMakeLists.txt @@ -1,30 +1,16 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -PROJECT(test_host) -ENABLE_LANGUAGE(Fortran) -include(CMakeForceCompiler) - -SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules) - -#------------------------------------------------------------------------------ -# -# Set where the CCPP Framework lives -# -#------------------------------------------------------------------------------ -get_filename_component(TEST_ROOT "${CMAKE_SOURCE_DIR}" DIRECTORY) -get_filename_component(CCPP_ROOT "${TEST_ROOT}" DIRECTORY) #------------------------------------------------------------------------------ # # Create list of SCHEME_FILES, HOST_FILES, and SUITE_FILES # Paths should be relative to CMAKE_SOURCE_DIR (this file's directory) # #------------------------------------------------------------------------------ -LIST(APPEND SCHEME_FILES "var_compatibility_files.txt") -LIST(APPEND HOST_FILES "test_host_data" "test_host_mod") -LIST(APPEND SUITE_FILES "var_compatibility_suite.xml") +set(SCHEME_FILES "var_compatibility_files.txt") +set(HOST_FILES "test_host_data" "test_host_mod") +set(SUITE_FILES "var_compatibility_suite.xml") # HOST is the name of the executable we will build. # We assume there are files ${HOST}.meta and ${HOST}.F90 in CMAKE_SOURCE_DIR -SET(HOST "${CMAKE_PROJECT_NAME}") +set(HOST "test_host") #------------------------------------------------------------------------------ # @@ -32,157 +18,45 @@ SET(HOST "${CMAKE_PROJECT_NAME}") # #------------------------------------------------------------------------------ -# By default, no verbose output -SET(VERBOSITY 0 CACHE STRING "Verbosity level of output (default: 0)") # By default, generated caps go in ccpp subdir -SET(CCPP_CAP_FILES "${CMAKE_BINARY_DIR}/ccpp" CACHE - STRING "Location of CCPP-generated cap files") - -SET(CCPP_FRAMEWORK ${CCPP_ROOT}/scripts) - -# Use rpaths on MacOSX -set(CMAKE_MACOSX_RPATH 1) - -#------------------------------------------------------------------------------ -# Set a default build type if none was specified -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - #message(STATUS "Setting build type to 'Debug' as none was specified.") - #set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) - message(STATUS "Setting build type to 'Release' as none was specified.") - set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) - - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" - "MinSizeRel" "RelWithDebInfo") -endif() - -ADD_COMPILE_OPTIONS(-O0) - -if (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") -# gfortran -# MESSAGE("gfortran being used.") - ADD_COMPILE_OPTIONS(-fcheck=all) - ADD_COMPILE_OPTIONS(-fbacktrace) - ADD_COMPILE_OPTIONS(-ffpe-trap=zero) - ADD_COMPILE_OPTIONS(-finit-real=nan) - ADD_COMPILE_OPTIONS(-ggdb) - ADD_COMPILE_OPTIONS(-ffree-line-length-none) - ADD_COMPILE_OPTIONS(-cpp) -elseif (${CMAKE_Fortran_COMPILER_ID} MATCHES "Intel") -# ifort -# MESSAGE("ifort being used.") - #ADD_COMPILE_OPTIONS(-check all) - ADD_COMPILE_OPTIONS(-fpe0) - ADD_COMPILE_OPTIONS(-warn) - ADD_COMPILE_OPTIONS(-traceback) - ADD_COMPILE_OPTIONS(-debug extended) - ADD_COMPILE_OPTIONS(-fpp) -elseif (${CMAKE_Fortran_COMPILER_ID} MATCHES "PGI") -# pgf90 -# MESSAGE("pgf90 being used.") - ADD_COMPILE_OPTIONS(-g) - ADD_COMPILE_OPTIONS(-Mipa=noconst) - ADD_COMPILE_OPTIONS(-traceback) - ADD_COMPILE_OPTIONS(-Mfree) - ADD_COMPILE_OPTIONS(-Mfptrap) - ADD_COMPILE_OPTIONS(-Mpreprocess) -else (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") - message (WARNING "This program has only been compiled with gfortran, pgf90 and ifort. If another compiler is needed, the appropriate flags SHOULD be added in ${CMAKE_SOURCE_DIR}/CMakeLists.txt") -endif (${CMAKE_Fortran_COMPILER_ID} MATCHES "GNU") - -#------------------------------------------------------------------------------ -# CMake Modules -# Set the CMake module path -list(APPEND CMAKE_MODULE_PATH "${CCPP_FRAMEWORK}/cmake") -#------------------------------------------------------------------------------ -# Set OpenMP flags for C/C++/Fortran -if (OPENMP) - include(detect_openmp) - detect_openmp() - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${OpenMP_Fortran_FLAGS}") - message(STATUS "Enable OpenMP support for C/C++/Fortran compiler") -else(OPENMP) - message (STATUS "Disable OpenMP support for C/C++/Fortran compiler") -endif() +set(CCPP_CAP_FILES "${CMAKE_CURRENT_BINARY_DIR}/ccpp") # Create metadata and source file lists -FOREACH(FILE ${SCHEME_FILES}) - FILE(STRINGS ${FILE} FILENAMES) - LIST(APPEND SCHEME_FILENAMES ${FILENAMES}) -ENDFOREACH(FILE) -string(REPLACE ";" "," SCHEME_METADATA "${SCHEME_FILES}") - -FOREACH(FILE ${SCHEME_FILENAMES}) +foreach(SCHEME_FILE ${SCHEME_FILES}) + file(STRINGS ${SCHEME_FILE} FILENAMES) + foreach(filename ${FILENAMES}) + string(REPLACE ".meta" ".F90" TEMP "${filename}") + file(REAL_PATH "${TEMP}" ABS_PATH) + list(APPEND VAR_COMPATIBILITY_LIBRARY_LIST "${ABS_PATH}") + endforeach() +endforeach() + +foreach(FILE ${HOST_FILES}) + list(APPEND VAR_COMPATIBILITY_HOST_METADATA "${FILE}.meta") # target_sources prefers absolute pathnames - string(REPLACE ".meta" ".F90" TEMP "${FILE}") - get_filename_component(ABS_PATH "${TEMP}" ABSOLUTE) - list(APPEND LIBRARY_LIST ${ABS_PATH}) -ENDFOREACH(FILE) + file(REAL_PATH "${FILE}.F90" ABS_PATH) + list(APPEND VAR_COMPATIBILITY_LIBRARY_LIST "${ABS_PATH}") +endforeach() -FOREACH(FILE ${HOST_FILES}) - LIST(APPEND HOST_METADATA "${FILE}.meta") - # target_sources prefers absolute pathnames - get_filename_component(ABS_PATH "${FILE}.F90" ABSOLUTE) - LIST(APPEND HOST_SOURCE "${ABS_PATH}") -ENDFOREACH(FILE) -list(APPEND LIBRARY_LIST ${HOST_SOURCE}) -string(REPLACE ";" ".meta," HOST_METADATA "${HOST_FILES}") -set(HOST_METADATA "${HOST_METADATA}.meta,${HOST}.meta") - -string(REPLACE ";" "," SUITE_XML "${SUITE_FILES}") +list(APPEND VAR_COMPATIBILITY_HOST_METADATA "${HOST}.meta") # Run ccpp_capgen -set(CAPGEN_CMD "${CCPP_FRAMEWORK}/ccpp_capgen.py") -list(APPEND CAPGEN_CMD "--host-files") -list(APPEND CAPGEN_CMD "${HOST_METADATA}") -list(APPEND CAPGEN_CMD "--scheme-files") -list(APPEND CAPGEN_CMD "${SCHEME_METADATA}") -list(APPEND CAPGEN_CMD "--suites") -list(APPEND CAPGEN_CMD "${SUITE_XML}") -list(APPEND CAPGEN_CMD "--host-name") -list(APPEND CAPGEN_CMD "test_host") -list(APPEND CAPGEN_CMD "--output-root") -list(APPEND CAPGEN_CMD "${CCPP_CAP_FILES}") -while (VERBOSITY GREATER 0) - list(APPEND CAPGEN_CMD "--verbose") - MATH(EXPR VERBOSITY "${VERBOSITY} - 1") -endwhile () -list(APPEND CAPGEN_CMD "--debug") -string(REPLACE ";" " " CAPGEN_STRING "${CAPGEN_CMD}") -MESSAGE(STATUS "Running: ${CAPGEN_STRING}") -EXECUTE_PROCESS(COMMAND ${CAPGEN_CMD} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - OUTPUT_VARIABLE CAPGEN_OUT ERROR_VARIABLE CAPGEN_OUT RESULT_VARIABLE RES) -MESSAGE(STATUS "${CAPGEN_OUT}") -if (RES EQUAL 0) - MESSAGE(STATUS "CCPP cap generation completed") -else(RES EQUAL 0) - MESSAGE(FATAL_ERROR "CCPP cap generation FAILED: result = ${RES}") -endif(RES EQUAL 0) +ccpp_capgen(CAPGEN_DEBUG ON + VERBOSITY ${CCPP_VERBOSITY} + HOSTFILES ${VAR_COMPATIBILITY_HOST_METADATA} + SCHEMEFILES ${SCHEME_FILES} + SUITES ${SUITE_FILES} + HOST_NAME "test_host" + OUTPUT_ROOT "${CCPP_CAP_FILES}") # Retrieve the list of files from datatable.xml and set to CCPP_CAPS -set(DTABLE_CMD "${CCPP_FRAMEWORK}/ccpp_datafile.py") -list(APPEND DTABLE_CMD "${CCPP_CAP_FILES}/datatable.xml") -list(APPEND DTABLE_CMD "--ccpp-files") -list(APPEND DTABLE_CMD "--separator=\\;") -string(REPLACE ";" " " DTABLE_STRING "${DTABLE_CMD}") -MESSAGE(STATUS "Running: ${DTABLE_STRING}") -EXECUTE_PROCESS(COMMAND ${DTABLE_CMD} OUTPUT_VARIABLE CCPP_CAPS - RESULT_VARIABLE RES - OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE) -message(STATUS "CCPP_CAPS = ${CCPP_CAPS}") -if (RES EQUAL 0) - MESSAGE(STATUS "CCPP cap files retrieved") -else(RES EQUAL 0) - MESSAGE(FATAL_ERROR "CCPP cap file retrieval FAILED: result = ${RES}") -endif(RES EQUAL 0) -list(APPEND LIBRARY_LIST ${CCPP_CAPS}) -add_library(TESTLIB OBJECT ${LIBRARY_LIST}) -ADD_EXECUTABLE(${HOST} ${HOST}.F90 $) +ccpp_datafile(DATATABLE "${CCPP_CAP_FILES}/datatable.xml" + REPORT_NAME "--ccpp-files") + +list(APPEND VAR_COMPATIBILITY_LIBRARY_LIST ${CCPP_CAPS_LIST}) +add_library(VAR_COMPATIBILITY_TESTLIB OBJECT ${VAR_COMPATIBILITY_LIBRARY_LIST}) +add_executable(var_compatibility_${HOST} ${HOST}.F90 $) -INCLUDE_DIRECTORIES(${CCPP_CAP_FILES}) +target_include_directories(var_compatibility_${HOST} PRIVATE ${CCPP_CAP_FILES}) -set_target_properties(${HOST} PROPERTIES - COMPILE_FLAGS "${CMAKE_Fortran_FLAGS}" - LINK_FLAGS "${CMAKE_Fortran_FLAGS}") +add_test(NAME var_compatibility_${HOST} COMMAND var_compatibility_${HOST}) diff --git a/test/var_compatibility_test/run_test b/test/var_compatibility_test/run_test deleted file mode 100755 index 5a1d6b5c..00000000 --- a/test/var_compatibility_test/run_test +++ /dev/null @@ -1,261 +0,0 @@ -#! /bin/bash - -currdir="`pwd -P`" -scriptdir="$( cd $( dirname $0 ); pwd -P )" - -## -## Option default values -## -defdir="ct_build" -build_dir="${currdir}/${defdir}" -cleanup="PASS" # Other supported options are ALWAYS and NEVER -verbosity=0 - -## -## General syntax help function -## Usage: help -## -help () { - local hname="Usage: `basename ${0}`" - local hprefix="`echo ${hname} | tr '[!-~]' ' '`" - echo "${hname} [ --build-dir ] [ --cleanup ]" - echo "${hprefix} [ --verbosity <#> ]" - hprefix=" " - echo "" - echo "${hprefix} : Directory for building and running the test" - echo "${hprefix} default is /${defdir}" - echo "${hprefix} : Cleanup option is ALWAYS, NEVER, or PASS" - echo "${hprefix} default is PASS" - echo "${hprefix} verbosity: 0, 1, or 2" - echo "${hprefix} default is 0" - exit $1 -} - -## -## Error output function (should be handed a string) -## -perr() { - >&2 echo -e "\nERROR: ${@}\n" - exit 1 -} - -## -## Cleanup the build and test directory -## -docleanup() { - # We start off in the build directory - if [ "${build_dir}" == "${currdir}" ]; then - echo "WARNING: Cannot clean ${build_dir}" - else - cd ${currdir} - rm -rf ${build_dir} - fi -} - -## Process our input arguments -while [ $# -gt 0 ]; do - case $1 in - --h | -h | --help | -help) - help 0 - ;; - --build-dir) - if [ $# -lt 2 ]; then - perr "${1} requires a build directory" - fi - build_dir="${2}" - shift - ;; - --cleanup) - if [ $# -lt 2 ]; then - perr "${1} requies a cleanup option (ALWAYS, NEVER, PASS)" - fi - if [ "${2}" == "ALWAYS" -o "${2}" == "NEVER" -o "${2}" == "PASS" ]; then - cleanup="${2}" - else - perr "Allowed cleanup options: ALWAYS, NEVER, PASS" - fi - shift - ;; - --verbosity) - if [ $# -lt 2 ]; then - perr "${1} requires a verbosity value (0, 1, or 2)" - fi - if [ "${2}" == "0" -o "${2}" == "1" -o "${2}" == "2" ]; then - verbosity=$2 - else - perr "allowed verbosity levels are 0, 1, 2" - fi - shift - ;; - *) - perr "Unrecognized option, \"${1}\"" - ;; - esac - shift -done - -# Create the build directory, if necessary -if [ -d "${build_dir}" ]; then - # Always make sure build_dir is not in the test dir - if [ "$( cd ${build_dir}; pwd -P )" == "${currdir}" ]; then - build_dir="${build_dir}/${defdir}" - fi -else - mkdir -p ${build_dir} - res=$? - if [ $res -ne 0 ]; then - perr "Unable to create build directory, '${build_dir}'" - fi -fi -build_dir="$( cd ${build_dir}; pwd -P )" - -## framework is the CCPP Framework root dir -framework="$( cd $( dirname $( dirname ${scriptdir} ) ); pwd -P )" -frame_src="${framework}/src" - -## -## check strings for datafile command-list test -## NB: This has to be after build_dir is finalized -## -host_files="${build_dir}/ccpp/test_host_ccpp_cap.F90" -suite_files="${build_dir}/ccpp/ccpp_var_compatibility_suite_cap.F90" -utility_files="${build_dir}/ccpp/ccpp_kinds.F90" -utility_files="${utility_files},${frame_src}/ccpp_constituent_prop_mod.F90" -utility_files="${utility_files},${frame_src}/ccpp_hashable.F90" -utility_files="${utility_files},${frame_src}/ccpp_hash_table.F90" -ccpp_files="${utility_files}" -ccpp_files="${ccpp_files},${build_dir}/ccpp/test_host_ccpp_cap.F90" -ccpp_files="${ccpp_files},${build_dir}/ccpp/ccpp_var_compatibility_suite_cap.F90" -#process_list="" -module_list="effr_calc,effr_diag,effr_post,effr_pre" -#dependencies="" -suite_list="var_compatibility_suite" -required_vars_var_compatibility="ccpp_error_code,ccpp_error_message" -required_vars_var_compatibility="${required_vars_var_compatibility},cloud_graupel_number_concentration" -required_vars_var_compatibility="${required_vars_var_compatibility},cloud_ice_number_concentration" -required_vars_var_compatibility="${required_vars_var_compatibility},effective_radius_of_stratiform_cloud_graupel" -required_vars_var_compatibility="${required_vars_var_compatibility},effective_radius_of_stratiform_cloud_ice_particle" -required_vars_var_compatibility="${required_vars_var_compatibility},effective_radius_of_stratiform_cloud_liquid_water_particle" -required_vars_var_compatibility="${required_vars_var_compatibility},effective_radius_of_stratiform_cloud_rain_particle" -required_vars_var_compatibility="${required_vars_var_compatibility},effective_radius_of_stratiform_cloud_snow_particle" -required_vars_var_compatibility="${required_vars_var_compatibility},flag_indicating_cloud_microphysics_has_graupel" -required_vars_var_compatibility="${required_vars_var_compatibility},flag_indicating_cloud_microphysics_has_ice" -required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_dimension" -required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_loop_begin" -required_vars_var_compatibility="${required_vars_var_compatibility},horizontal_loop_end" -required_vars_var_compatibility="${required_vars_var_compatibility},scalar_variable_for_testing" -required_vars_var_compatibility="${required_vars_var_compatibility},vertical_layer_dimension" -input_vars_var_compatibility="cloud_graupel_number_concentration" -#input_vars_var_compatibility="${input_vars_var_compatibility},cloud_ice_number_concentration" -input_vars_var_compatibility="${input_vars_var_compatibility},effective_radius_of_stratiform_cloud_graupel" -input_vars_var_compatibility="${input_vars_var_compatibility},effective_radius_of_stratiform_cloud_liquid_water_particle" -input_vars_var_compatibility="${input_vars_var_compatibility},effective_radius_of_stratiform_cloud_rain_particle" -input_vars_var_compatibility="${input_vars_var_compatibility},effective_radius_of_stratiform_cloud_snow_particle" -input_vars_var_compatibility="${input_vars_var_compatibility},flag_indicating_cloud_microphysics_has_graupel" -input_vars_var_compatibility="${input_vars_var_compatibility},flag_indicating_cloud_microphysics_has_ice" -input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_dimension" -input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_loop_begin" -input_vars_var_compatibility="${input_vars_var_compatibility},horizontal_loop_end" -input_vars_var_compatibility="${input_vars_var_compatibility},scalar_variable_for_testing" -input_vars_var_compatibility="${input_vars_var_compatibility},vertical_layer_dimension" -output_vars_var_compatibility="ccpp_error_code,ccpp_error_message" -output_vars_var_compatibility="${output_vars_var_compatibility},cloud_ice_number_concentration" -output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_ice_particle" -output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_liquid_water_particle" -output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_rain_particle" -output_vars_var_compatibility="${output_vars_var_compatibility},effective_radius_of_stratiform_cloud_snow_particle" -output_vars_var_compatibility="${output_vars_var_compatibility},scalar_variable_for_testing" - -## -## Run a database report and check the return string -## $1 is the report program file -## $2 is the database file -## $3 is the report string -## $4 is the check string -## $5+ are any optional arguments -## -check_datatable() { - local checkstr=${4} - local teststr - local prog=${1} - local database=${2} - local report=${3} - shift 4 - echo "Checking ${report} report" - teststr="`${prog} ${database} ${report} $@`" - if [ "${teststr}" != "${checkstr}" ]; then - perr "datatable check:\nExpected: '${checkstr}'\nGot: '${teststr}'" - fi -} - -# cd to the build directory -cd ${build_dir} -res=$? -if [ $res -ne 0 ]; then - perr "Unable to cd to build directory, '${build_dir}'" -fi -# Clean build directory -rm -rf * -res=$? -if [ $res -ne 0 ]; then - perr "Unable to clean build directory, '${build_dir}'" -fi -# Run CMake -opts="" -if [ $verbosity -gt 0 ]; then - opts="${opts} -DVERBOSITY=${verbosity}" -fi -# Run cmake -cmake ${scriptdir} ${opts} -res=$? -if [ $res -ne 0 ]; then - perr "CMake failed with exit code, ${res}" -fi -# Test the datafile user interface -report_prog="${framework}/scripts/ccpp_datafile.py" -datafile="${build_dir}/ccpp/datatable.xml" -echo "Running python interface tests" -python3 ${scriptdir}/test_reports.py ${build_dir} ${datafile} -res=$? -if [ $res -ne 0 ]; then - perr "python interface tests failed" -fi -echo "Running command line tests" -echo "Checking required files from command line:" -check_datatable ${report_prog} ${datafile} "--host-files" ${host_files} -check_datatable ${report_prog} ${datafile} "--suite-files" ${suite_files} -check_datatable ${report_prog} ${datafile} "--utility-files" ${utility_files} -check_datatable ${report_prog} ${datafile} "--ccpp-files" ${ccpp_files} -echo -e "\nChecking lists from command line" -#check_datatable ${report_prog} ${datafile} "--process-list" ${process_list} -check_datatable ${report_prog} ${datafile} "--module-list" ${module_list} -#check_datatable ${report_prog} ${datafile} "--dependencies" ${dependencies} -check_datatable ${report_prog} ${datafile} "--suite-list" ${suite_list} \ - --sep ";" -echo -e "\nChecking variables for var_compatibility suite from command line" -check_datatable ${report_prog} ${datafile} "--required-variables" \ - ${required_vars_var_compatibility} "var_compatibility_suite" -check_datatable ${report_prog} ${datafile} "--input-variables" \ - ${input_vars_var_compatibility} "var_compatibility_suite" -check_datatable ${report_prog} ${datafile} "--output-variables" \ - ${output_vars_var_compatibility} "var_compatibility_suite" -# Run make -make -res=$? -if [ $res -ne 0 ]; then - perr "make failed with exit code, ${res}" -fi -# Run test -./test_host -res=$? -if [ $res -ne 0 ]; then - perr "test_host failed with exit code, ${res}" -fi - -if [ "${cleanup}" == "ALWAYS" ]; then - docleanup -elif [ $res -eq 0 -a "${cleanup}" == "PASS" ]; then - docleanup -fi - -exit $res diff --git a/test/var_compatibility_test/test_reports.py b/test/var_compatibility_test/test_reports.py deleted file mode 100755 index 6f10fc6d..00000000 --- a/test/var_compatibility_test/test_reports.py +++ /dev/null @@ -1,162 +0,0 @@ -#! /usr/bin/env python3 -""" ------------------------------------------------------------------------ - Description: Test capgen database report python interface - - Assumptions: - - Command line arguments: build_dir database_filepath - - Usage: python test_reports ------------------------------------------------------------------------ -""" -import sys -import os - -_TEST_DIR = os.path.dirname(os.path.abspath(__file__)) -_FRAMEWORK_DIR = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir)) -_SCRIPTS_DIR = os.path.join(_FRAMEWORK_DIR, "scripts") -_SRC_DIR = os.path.join(_FRAMEWORK_DIR, "src") - -if not os.path.exists(_SCRIPTS_DIR): - raise ImportError("Cannot find scripts directory") -# end if - -if ((sys.version_info[0] < 3) or - (sys.version_info[0] == 3) and (sys.version_info[1] < 8)): - raise Exception("Python 3.8 or greater required") -# end if - -sys.path.append(_SCRIPTS_DIR) -# pylint: disable=wrong-import-position -from ccpp_datafile import datatable_report, DatatableReport -# pylint: enable=wrong-import-position - -def usage(errmsg=None): - """Raise an exception with optional error message and usage message""" - emsg = "usage: {} " - if errmsg: - emsg = errmsg + '\n' + emsg - # end if - raise ValueError(emsg.format(sys.argv[0])) - -if len(sys.argv) != 3: - usage() -# end if - -_BUILD_DIR = os.path.abspath(sys.argv[1]) -_DATABASE = os.path.abspath(sys.argv[2]) -if not os.path.isdir(_BUILD_DIR): - _EMSG = " must be an existing build directory" - usage(_EMSG) -# end if -if (not os.path.exists(_DATABASE)) or (not os.path.isfile(_DATABASE)): - _EMSG = " must be an existing CCPP database file" - usage(_EMSG) -# end if - -# Check data -_HOST_FILES = [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90")] -_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatibility_suite_cap.F90")] -_UTILITY_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_kinds.F90"), - os.path.join(_SRC_DIR, "ccpp_constituent_prop_mod.F90"), - os.path.join(_SRC_DIR, "ccpp_hashable.F90"), - os.path.join(_SRC_DIR, "ccpp_hash_table.F90")] -_CCPP_FILES = _UTILITY_FILES + \ - [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90"), - os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatibility_suite_cap.F90")] -_MODULE_LIST = ["effr_calc", "effr_diag", "effr_post", "effr_pre"] -_SUITE_LIST = ["var_compatibility_suite"] -_INPUT_VARS_VAR_ACTION = ["horizontal_loop_begin", "horizontal_loop_end", "horizontal_dimension", "vertical_layer_dimension", - "effective_radius_of_stratiform_cloud_liquid_water_particle", - "effective_radius_of_stratiform_cloud_rain_particle", - "effective_radius_of_stratiform_cloud_snow_particle", - "effective_radius_of_stratiform_cloud_graupel", - "cloud_graupel_number_concentration", - "scalar_variable_for_testing", - "flag_indicating_cloud_microphysics_has_graupel", - "flag_indicating_cloud_microphysics_has_ice"] -_OUTPUT_VARS_VAR_ACTION = ["ccpp_error_code", "ccpp_error_message", - "effective_radius_of_stratiform_cloud_ice_particle", - "effective_radius_of_stratiform_cloud_liquid_water_particle", - "effective_radius_of_stratiform_cloud_snow_particle", - "cloud_ice_number_concentration", - "effective_radius_of_stratiform_cloud_rain_particle", - "scalar_variable_for_testing"] -_REQUIRED_VARS_VAR_ACTION = _INPUT_VARS_VAR_ACTION + _OUTPUT_VARS_VAR_ACTION - -def fields_string(field_type, field_list, sep): - """Create an error string for field(s), . - is used to separate items in """ - indent = ' '*11 - if field_list: - if len(field_list) > 1: - field_str = "{} Fields: ".format(field_type) - else: - field_str = "{} Field: ".format(field_type) - # end if - fmsg = "\n{}{}{}".format(indent, field_str, sep.join(field_list)) - else: - fmsg = "" - # end if - return fmsg - -def check_datatable(database, report_type, check_list, - sep=',', exclude_protected=False): - """Run a database report and check the return string. - If an error is found, print an error message. - Return the number of errors""" - if sep is None: - sep = ',' - # end if - test_str = datatable_report(database, report_type, sep, exclude_protected=exclude_protected) - test_list = [x for x in test_str.split(sep) if x] - missing = list() - unexpected = list() - for item in check_list: - if item not in test_list: - missing.append(item) - # end if - # end for - for item in test_list: - if item not in check_list: - unexpected.append(item) - # end if - # end for - if missing or unexpected: - vmsg = "ERROR in {} datafile check:".format(report_type.action) - vmsg += fields_string("Missing", missing, sep) - vmsg += fields_string("Unexpected", unexpected, sep) - print(vmsg) - else: - print("{} report okay".format(report_type.action)) - # end if - return len(missing) + len(unexpected) - -NUM_ERRORS = 0 -print("Checking required files from python:") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("host_files"), - _HOST_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_files"), - _SUITE_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("utility_files"), - _UTILITY_FILES) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("ccpp_files"), - _CCPP_FILES) -print("\nChecking lists from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("module_list"), - _MODULE_LIST) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("suite_list"), - _SUITE_LIST) -print("\nChecking variables for var_compatibility suite from python") -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("required_variables", - value="var_compatibility_suite"), - _REQUIRED_VARS_VAR_ACTION) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("input_variables", - value="var_compatibility_suite"), - _INPUT_VARS_VAR_ACTION) -NUM_ERRORS += check_datatable(_DATABASE, DatatableReport("output_variables", - value="var_compatibility_suite"), - _OUTPUT_VARS_VAR_ACTION) - -sys.exit(NUM_ERRORS) diff --git a/test/var_compatibility_test/var_compatibility_test_reports.py b/test/var_compatibility_test/var_compatibility_test_reports.py new file mode 100755 index 00000000..9b8207bb --- /dev/null +++ b/test/var_compatibility_test/var_compatibility_test_reports.py @@ -0,0 +1,187 @@ +#! /usr/bin/env python3 +""" +----------------------------------------------------------------------- + Description: Test capgen database report python interface + + Assumptions: + + Command line arguments: build_dir database_filepath + + Usage: python test_reports +----------------------------------------------------------------------- +""" +import sys +import os +import unittest +import subprocess + +_BUILD_DIR = os.path.join(os.path.abspath(os.environ['BUILD_DIR']), "test", "var_compatibility_test") + +_TEST_DIR = os.path.dirname(os.path.abspath(__file__)) +_FRAMEWORK_DIR = os.path.abspath(os.path.join(_TEST_DIR, os.pardir, os.pardir)) +_SCRIPTS_DIR = os.path.join(_FRAMEWORK_DIR, "scripts") +_SRC_DIR = os.path.join(_FRAMEWORK_DIR, "src") + +sys.path.append(_SCRIPTS_DIR) +# pylint: disable=wrong-import-position +from ccpp_datafile import datatable_report, DatatableReport +# pylint: enable=wrong-import-position + +_DATABASE = os.path.abspath(os.path.join(_BUILD_DIR, "ccpp", "datatable.xml")) + +# Check data +_HOST_FILES = [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90")] +_SUITE_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatibility_suite_cap.F90")] +_UTILITY_FILES = [os.path.join(_BUILD_DIR, "ccpp", "ccpp_kinds.F90"), + os.path.join(_SRC_DIR, "ccpp_constituent_prop_mod.F90"), + os.path.join(_SRC_DIR, "ccpp_hashable.F90"), + os.path.join(_SRC_DIR, "ccpp_hash_table.F90")] +_CCPP_FILES = _UTILITY_FILES + \ + [os.path.join(_BUILD_DIR, "ccpp", "test_host_ccpp_cap.F90"), + os.path.join(_BUILD_DIR, "ccpp", "ccpp_var_compatibility_suite_cap.F90")] +_DEPENDENCIES = [""] +_PROCESS_LIST = [""] +_MODULE_LIST = ["effr_calc", "effr_diag", "effr_post", "effr_pre"] +_SUITE_LIST = ["var_compatibility_suite"] +_INPUT_VARS_VAR_ACTION = ["horizontal_loop_begin", "horizontal_loop_end", "horizontal_dimension", "vertical_layer_dimension", + "effective_radius_of_stratiform_cloud_liquid_water_particle", + "effective_radius_of_stratiform_cloud_rain_particle", + "effective_radius_of_stratiform_cloud_snow_particle", + "effective_radius_of_stratiform_cloud_graupel", + "cloud_graupel_number_concentration", + "scalar_variable_for_testing", + "flag_indicating_cloud_microphysics_has_graupel", + "flag_indicating_cloud_microphysics_has_ice"] +_OUTPUT_VARS_VAR_ACTION = ["ccpp_error_code", "ccpp_error_message", + "effective_radius_of_stratiform_cloud_ice_particle", + "effective_radius_of_stratiform_cloud_liquid_water_particle", + "effective_radius_of_stratiform_cloud_snow_particle", + "cloud_ice_number_concentration", + "effective_radius_of_stratiform_cloud_rain_particle", + "scalar_variable_for_testing"] +_REQUIRED_VARS_VAR_ACTION = _INPUT_VARS_VAR_ACTION + _OUTPUT_VARS_VAR_ACTION +_SEP = "," + +class TestVarCompatibilityDataTables(unittest.TestCase): + def test_host_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("host_files"), _SEP) + self.assertSetEqual(set(_HOST_FILES), set(test_str.split(_SEP))) + + def test_suite_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("suite_files"), _SEP) + self.assertSetEqual(set(_SUITE_FILES), set(test_str.split(_SEP))) + + def test_utility_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("utility_files"), _SEP) + self.assertSetEqual(set(_UTILITY_FILES), set(test_str.split(_SEP))) + + def test_ccpp_files(self): + test_str = datatable_report(_DATABASE, DatatableReport("ccpp_files"), _SEP) + self.assertSetEqual(set(_CCPP_FILES), set(test_str.split(_SEP))) + + def test_process_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("process_list"), _SEP) + self.assertSetEqual(set(_PROCESS_LIST), set(test_str.split(_SEP))) + + def test_module_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("module_list"), _SEP) + self.assertSetEqual(set(_MODULE_LIST), set(test_str.split(_SEP))) + + def test_dependencies_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("dependencies"), _SEP) + self.assertSetEqual(set(_DEPENDENCIES), set(test_str.split(_SEP))) + + def test_suite_list(self): + test_str = datatable_report(_DATABASE, DatatableReport("suite_list"), _SEP) + self.assertSetEqual(set(_SUITE_LIST), set(test_str.split(_SEP))) + + +class CommandLineVarCompatibilityDatafileRequiredFiles(unittest.TestCase): + def test_host_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--host-files"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_HOST_FILES), actualOutput) + + def test_suite_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--suite-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_SUITE_FILES), completedProcess.stdout.strip()) + + def test_utility_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--utility-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_UTILITY_FILES), completedProcess.stdout.strip()) + + def test_ccpp_files(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--ccpp-files"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_CCPP_FILES), completedProcess.stdout.strip()) + + def test_process_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--process-list"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_PROCESS_LIST), actualOutput) + + def test_module_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--module-list"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_MODULE_LIST), completedProcess.stdout.strip()) + + def test_dependencies(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--dependencies"], + capture_output=True, + text=True) + self.assertEqual(_SEP.join(_DEPENDENCIES), completedProcess.stdout.strip()) + + def test_suite_list(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--suite-list", "--sep=;"], + capture_output=True, + text=True) + # actualOutput = {s.strip() for s in completedProcess.stdout.split(";")} + self.assertEqual(";".join(_SUITE_LIST), completedProcess.stdout.strip()) + + +class TestVarCompatibilitySuite(unittest.TestCase): + def test_required_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("required_variables", value="var_compatibility_suite"), _SEP) + self.assertSetEqual(set(_REQUIRED_VARS_VAR_ACTION), set(test_str.split(_SEP))) + + def test_input_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("input_variables", value="var_compatibility_suite"), _SEP) + self.assertSetEqual(set(_INPUT_VARS_VAR_ACTION), set(test_str.split(_SEP))) + + def test_output_variables(self): + test_str = datatable_report(_DATABASE, DatatableReport("output_variables", value="var_compatibility_suite"), _SEP) + self.assertSetEqual(set(_OUTPUT_VARS_VAR_ACTION), set(test_str.split(_SEP))) + + +class CommandLineVarCompatibilitySuite(unittest.TestCase): + def test_required_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--required-variables", "var_compatibility_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_REQUIRED_VARS_VAR_ACTION), actualOutput) + + def test_input_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--input-variables", "var_compatibility_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_INPUT_VARS_VAR_ACTION), actualOutput) + + def test_output_variables(self): + completedProcess = subprocess.run([f"{_SCRIPTS_DIR}/ccpp_datafile.py", _DATABASE, "--output-variables", "var_compatibility_suite"], + capture_output=True, + text=True) + actualOutput = {s.strip() for s in completedProcess.stdout.split(_SEP)} + self.assertSetEqual(set(_OUTPUT_VARS_VAR_ACTION), actualOutput) +