diff --git a/.github/workflows/test_suite.yml b/.github/workflows/test_suite.yml index 3056b53e5..f7c502653 100644 --- a/.github/workflows/test_suite.yml +++ b/.github/workflows/test_suite.yml @@ -50,9 +50,43 @@ jobs: cd test python3 ThermoIntegration_test.py ./run_test_jan2010_integration_test.sh python3 - cd - - test-ubuntu-mpi: + test-ubuntu-mpi-noxios: + + runs-on: ubuntu-22.04 + container: + image: ghcr.io/nextsimhub/nextsimdg-dev-env:latest + + steps: + - uses: actions/checkout@v2 + + - name: build and compile with MPI but not XIOS + run: | + . /opt/spack-environment/activate.sh + mkdir -p build && cd build + cmake -DENABLE_MPI=ON -DENABLE_XIOS=OFF -DCMAKE_CXX_COMPILER="$(which mpic++)" .. + make -j 4 + + - name: run MPI tests + run: | + . /opt/spack-environment/activate.sh + apt update + apt install -y wget + cd build + (cd core/test && wget "ftp://ftp.nersc.no/nextsim/netCDF/partition_metadata_1.nc") + for component in core physics dynamics + do + cd $component/test + for file in $(find test* -maxdepth 0 -type f) + do + echo $file + nprocs=$(echo $file | sed -r "s/.*MPI([0-9]+)/\1/") + mpirun --allow-run-as-root --oversubscribe -n $nprocs ./$file + done + cd - + done + + test-ubuntu-mpi-xios: runs-on: ubuntu-22.04 container: @@ -86,7 +120,6 @@ jobs: done cd - done - cd - test-mac-serial: @@ -138,4 +171,3 @@ jobs: cd test python ThermoIntegration_test.py ./run_test_jan2010_integration_test.sh python - cd - diff --git a/Dockerfiles/install-xios.sh b/Dockerfiles/install-xios.sh index e089ae39e..450d575d4 100755 --- a/Dockerfiles/install-xios.sh +++ b/Dockerfiles/install-xios.sh @@ -69,7 +69,12 @@ cat <arch/arch-GCC_LINUX.fcm %MAKE gmake EOF -./make_xios --arch GCC_LINUX --job 8 --full --debug +# Hack to remove a line that stops calendar attributes being accessed after the +# context definition has been closed. +# This should be fixed when we update to XIOS3 (see #761). +sed -i "s/if (hasClient) CleanTree/\/\/if (hasClient) CleanTree/" src/node/context.cpp + +./make_xios --arch GCC_LINUX --job 8 --debug rm -r /xios/obj /xios/bin/generic_testcase.exe /xios/src /xios/tools \ /xios/inputs /xios/doc /xios/arch /xios/xios_test_suite /xios/flags \ /xios/generic_testcase /xios/ppsrc /xios/done diff --git a/core/src/CMakeLists.txt b/core/src/CMakeLists.txt index b3d973f76..2f841c848 100644 --- a/core/src/CMakeLists.txt +++ b/core/src/CMakeLists.txt @@ -1,5 +1,14 @@ # Sources for the main neXtSIM model +if(ENABLE_XIOS) + set(XIOS_INCLUDE_LIST + "${xios_INCLUDES}" + "${xios_EXTERNS}/blitz/" + "${xios_EXTERNS}/rapidxml/include" + ) + set(NextsimIncludeDirs "${NextsimIncludeDirs}" "${XIOS_INCLUDE_LIST}") +endif() + set(BaseSources "Logged.cpp" "ModelConfig.cpp" diff --git a/core/src/ModelMetadata.cpp b/core/src/ModelMetadata.cpp index 65fbbb23f..f6f332672 100644 --- a/core/src/ModelMetadata.cpp +++ b/core/src/ModelMetadata.cpp @@ -1,7 +1,7 @@ /*! * @file ModelMetadata.cpp * - * @date 21 August 2024 + * @date 10 Dec 2024 * @author Tim Spain */ @@ -103,4 +103,28 @@ ModelState& ModelMetadata::affixCoordinates(ModelState& state) const } return state; } + +void ModelMetadata::setTime(const TimePoint& time) +{ + m_time = time; +#ifdef USE_XIOS + if (!xiosHandler->isInitialized()) { + throw std::runtime_error("ModelMetadata: Xios handler has not been initialized"); + } + xiosHandler->setCalendarStep(0); + xiosHandler->setCalendarStart(time); +#endif +} + +void ModelMetadata::incrementTime(const Duration& step) +{ + m_time += step; +#ifdef USE_XIOS + if (!xiosHandler->isInitialized()) { + throw std::runtime_error("ModelMetadata: Xios handler has not been initialized"); + } + xiosHandler->incrementCalendar(); +#endif +} + } /* namespace Nextsim */ diff --git a/core/src/ParaGridIO.cpp b/core/src/ParaGridIO.cpp index 63f47cb48..a6feaf874 100644 --- a/core/src/ParaGridIO.cpp +++ b/core/src/ParaGridIO.cpp @@ -1,7 +1,7 @@ /*! * @file ParaGridIO.cpp * - * @date Oct 24, 2022 + * @date 09 Dec 2024 * @author Tim Spain */ @@ -227,7 +227,7 @@ ModelState ParaGridIO::readForcingTimeStatic( std::vector timeVec(timeDim.getSize()); timeVar.getVar(timeVec.data()); // Get the index of the largest TimePoint less than the target. - targetTIndex = std::find_if(begin(timeVec), end(timeVec), [time](double t) { + targetTIndex = std::find_if(std::begin(timeVec), std::end(timeVec), [time](double t) { return (TimePoint() + Duration(t)) > time; }) - timeVec.begin(); // Rather than the first that is greater than, get the last that is less diff --git a/core/src/Xios.cpp b/core/src/Xios.cpp index 68d8b257e..91a08f3fe 100644 --- a/core/src/Xios.cpp +++ b/core/src/Xios.cpp @@ -2,7 +2,7 @@ * @file Xios.cpp * @author Tom Meltzer * @author Joe Wallwork - * @date 09 Dec 2024 + * @date 10 Dec 2024 * @brief XIOS interface implementation * @details * @@ -37,7 +37,6 @@ static const std::map keyMap = { { Xios::ENABLED_KEY, "xios.en //! Enable XIOS in the 'config' void enableXios() { - Configurator::clearStreams(); std::stringstream config; config << "[xios]" << std::endl << "enable = true" << std::endl; std::unique_ptr pcstream(new std::stringstream(config.str())); @@ -271,6 +270,18 @@ void Xios::setCalendarTimestep(const Duration timestep) cxios_update_calendar_timestep(clientCalendar); } +/*! + * Update XIOS calendar iteration/step number to some value + * + * @param Step number to update to + */ +void Xios::setCalendarStep(const int stepNumber) { cxios_update_calendar(stepNumber); } + +/*! + * Increment XIOS' calendar iteration/step number by one. + */ +void Xios::incrementCalendar() { setCalendarStep(getCalendarStep() + 1); } + /*! * Get calendar type * @@ -347,13 +358,6 @@ std::string Xios::getCurrentDate(const bool isoFormat) return convertXiosDatetimeToString(xiosDate, isoFormat); } -/*! - * Update XIOS calendar iteration/step number - * - * @param current step number - */ -void Xios::updateCalendar(const int stepNumber) { cxios_update_calendar(stepNumber); } - /*! * Get the axis_definition group * diff --git a/core/src/include/ModelMetadata.hpp b/core/src/include/ModelMetadata.hpp index ad4956c7a..e0b2c6419 100644 --- a/core/src/include/ModelMetadata.hpp +++ b/core/src/include/ModelMetadata.hpp @@ -1,7 +1,7 @@ /*! * @file ModelMetadata.hpp * - * @date Jun 29, 2022 + * @date 09 Dec 2024 * @author Tim Spain */ @@ -12,6 +12,9 @@ #include "include/ModelArray.hpp" #include "include/ModelState.hpp" #include "include/Time.hpp" +#ifdef USE_XIOS +#include "include/Xios.hpp" +#endif #include @@ -47,13 +50,13 @@ class ModelMetadata { * * @param time TimePoint instance encoding the current time. */ - inline void setTime(const TimePoint& time) { m_time = time; } + void setTime(const TimePoint& time); /*! * @brief Increments the model time metadata value. * * @param step Duration of the time increment to add. */ - inline void incrementTime(const Duration& step) { m_time += step; } + void incrementTime(const Duration& step); //! Returns the current model time. inline const TimePoint& time() const { return m_time; } @@ -99,6 +102,15 @@ class ModelMetadata { int localCornerX, localCornerY, localExtentX, localExtentY, globalExtentX, globalExtentY; #endif +#ifdef USE_XIOS + /* + * @brief Set pointer to Xios handler instance. + * + * @param xiosPtr Pointer to set + */ + inline void setXiosHandler(Xios* xiosPtr) { xiosHandler = xiosPtr; } +#endif + private: TimePoint m_time; ConfigMap m_config; @@ -117,6 +129,9 @@ class ModelMetadata { #ifdef USE_MPI const std::string bboxName = "bounding_boxes"; #endif +#ifdef USE_XIOS + Xios* xiosHandler = nullptr; +#endif }; } /* namespace Nextsim */ diff --git a/core/src/include/Xios.hpp b/core/src/include/Xios.hpp index cd846ded7..4db7b6f47 100644 --- a/core/src/include/Xios.hpp +++ b/core/src/include/Xios.hpp @@ -2,7 +2,7 @@ * @file Xios.hpp * @author Tom Meltzer * @author Joe Wallwork - * @date 04 Dec 2024 + * @date 10 Dec 2024 * @brief XIOS interface header * @details * @@ -55,13 +55,14 @@ class Xios : public Configured { void setCalendarOrigin(const TimePoint origin); void setCalendarStart(const TimePoint start); void setCalendarTimestep(const Duration timestep); + void setCalendarStep(const int stepNumber); + void incrementCalendar(); std::string getCalendarType(); TimePoint getCalendarOrigin(); TimePoint getCalendarStart(); Duration getCalendarTimestep(); int getCalendarStep(); std::string getCurrentDate(const bool isoFormat = true); - void updateCalendar(const int stepNumber); /* Axis */ void createAxis(const std::string axisId); diff --git a/core/test/CMakeLists.txt b/core/test/CMakeLists.txt index ed8e02992..15ae0c2c3 100644 --- a/core/test/CMakeLists.txt +++ b/core/test/CMakeLists.txt @@ -19,59 +19,13 @@ include_directories(${COMMON_INCLUDE_DIRS}) set(MODEL_INCLUDE_DIR "../../core/src/discontinuousgalerkin") if(ENABLE_MPI) - # Generate partition files needed for MPI test from respective cdl files - add_custom_command( - OUTPUT partition_metadata_3.nc - COMMAND - ncgen -b -o partition_metadata_3.nc ${CMAKE_CURRENT_SOURCE_DIR}/partition_metadata_3.cdl - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/partition_metadata_3.cdl - ) - add_custom_command( - OUTPUT partition_metadata_2.nc - COMMAND - ncgen -b -o partition_metadata_2.nc ${CMAKE_CURRENT_SOURCE_DIR}/partition_metadata_2.cdl - DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/partition_metadata_2.cdl - ) - add_custom_target( - generate_partition_files - ALL - DEPENDS partition_metadata_3.nc partition_metadata_2.nc - ) - - add_executable(testRectGrid_MPI3 "RectGrid_test.cpp" "MainMPI.cpp") - target_compile_definitions( - testRectGrid_MPI3 - PRIVATE TEST_FILES_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\" - ) - target_include_directories( - testRectGrid_MPI3 - PRIVATE ${MODEL_INCLUDE_DIR} "${ModulesRoot}/StructureModule" - ) - target_link_libraries(testRectGrid_MPI3 PRIVATE nextsimlib doctest::doctest) - - add_executable(testParaGrid_MPI2 "ParaGrid_test.cpp" "MainMPI.cpp") - target_compile_definitions( - testParaGrid_MPI2 - PRIVATE - USE_MPI - TEST_FILES_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\" - TEST_FILE_SOURCE=\"${CMAKE_CURRENT_SOURCE_DIR}\" - ) - target_include_directories( - testParaGrid_MPI2 - PRIVATE ${MODEL_INCLUDE_DIR} "${ModulesRoot}/StructureModule" - ) - target_link_libraries(testParaGrid_MPI2 PRIVATE nextsimlib doctest::doctest) - - add_executable(testConfigOutput_MPI2 "ConfigOutput_test.cpp" "MainMPI.cpp") - target_compile_definitions( - testConfigOutput_MPI2 - PRIVATE USE_MPI TEST_FILES_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\" - ) - target_include_directories(testConfigOutput_MPI2 PRIVATE ${MODEL_INCLUDE_DIR}) - target_link_libraries(testConfigOutput_MPI2 PRIVATE nextsimlib doctest::doctest) - if(ENABLE_XIOS) + set(XIOS_INCLUDE_LIST + "${xios_INCLUDES}" + "${xios_EXTERNS}/blitz/" + "${xios_EXTERNS}/rapidxml/include" + ) + set(MODEL_INCLUDE_DIR "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}") file( CREATE_LINK "${CMAKE_SOURCE_DIR}/core/test/iodef.xml" @@ -84,11 +38,6 @@ if(ENABLE_MPI) DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/xios_test_input.cdl ) add_custom_target(generate_xios_input_file ALL DEPENDS xios_test_input.nc) - set(XIOS_INCLUDE_LIST - "${xios_INCLUDES}" - "${xios_EXTERNS}/blitz/" - "${xios_EXTERNS}/rapidxml/include" - ) add_executable(testXiosCalendar_MPI2 "XiosCalendar_test.cpp" "MainMPI.cpp") target_compile_definitions(testXiosCalendar_MPI2 PRIVATE USE_XIOS) @@ -145,7 +94,59 @@ if(ENABLE_MPI) PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule" ) target_link_libraries(testXiosReadWrite_MPI2 PRIVATE nextsimlib doctest::doctest) + else() + add_executable(testRectGrid_MPI3 "RectGrid_test.cpp" "MainMPI.cpp") + target_compile_definitions( + testRectGrid_MPI3 + PRIVATE TEST_FILES_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\" + ) + target_include_directories( + testRectGrid_MPI3 + PRIVATE ${MODEL_INCLUDE_DIR} "${ModulesRoot}/StructureModule" + ) + target_link_libraries(testRectGrid_MPI3 PRIVATE nextsimlib doctest::doctest) endif() + + # Generate partition files needed for MPI test from respective cdl files + add_custom_command( + OUTPUT partition_metadata_3.nc + COMMAND + ncgen -b -o partition_metadata_3.nc ${CMAKE_CURRENT_SOURCE_DIR}/partition_metadata_3.cdl + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/partition_metadata_3.cdl + ) + add_custom_command( + OUTPUT partition_metadata_2.nc + COMMAND + ncgen -b -o partition_metadata_2.nc ${CMAKE_CURRENT_SOURCE_DIR}/partition_metadata_2.cdl + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/partition_metadata_2.cdl + ) + add_custom_target( + generate_partition_files + ALL + DEPENDS partition_metadata_3.nc partition_metadata_2.nc + ) + + add_executable(testParaGrid_MPI2 "ParaGrid_test.cpp" "MainMPI.cpp") + target_compile_definitions( + testParaGrid_MPI2 + PRIVATE + USE_MPI + TEST_FILES_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\" + TEST_FILE_SOURCE=\"${CMAKE_CURRENT_SOURCE_DIR}\" + ) + target_include_directories( + testParaGrid_MPI2 + PRIVATE ${MODEL_INCLUDE_DIR} "${ModulesRoot}/StructureModule" + ) + target_link_libraries(testParaGrid_MPI2 PRIVATE nextsimlib doctest::doctest) + + add_executable(testConfigOutput_MPI2 "ConfigOutput_test.cpp" "MainMPI.cpp") + target_compile_definitions( + testConfigOutput_MPI2 + PRIVATE USE_MPI TEST_FILES_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\" + ) + target_include_directories(testConfigOutput_MPI2 PRIVATE ${MODEL_INCLUDE_DIR}) + target_link_libraries(testConfigOutput_MPI2 PRIVATE nextsimlib doctest::doctest) else() add_executable(testRectGrid "RectGrid_test.cpp") target_compile_definitions(testRectGrid PRIVATE TEST_FILES_DIR=\"${CMAKE_CURRENT_BINARY_DIR}\") diff --git a/core/test/ConfigOutput_test.cpp b/core/test/ConfigOutput_test.cpp index facbc8e57..b06282205 100644 --- a/core/test/ConfigOutput_test.cpp +++ b/core/test/ConfigOutput_test.cpp @@ -1,12 +1,13 @@ /*! * @file ConfigOutput_test.cpp * - * @date 24 Sep 2024 + * @date 11 Dec 2024 * @author Tim Spain */ #ifdef USE_MPI #include +#undef INFO #else #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include @@ -21,8 +22,8 @@ #include "include/ModelComponent.hpp" #include "include/ModelMetadata.hpp" #include "include/ModelState.hpp" -#include "include/NextsimModule.hpp" #include "include/NZLevels.hpp" +#include "include/NextsimModule.hpp" #include "include/gridNames.hpp" #include @@ -97,6 +98,13 @@ TEST_CASE("Test periodic output") ModelComponent::getStore().registerArray(Protected::T_ICE, &tice); ModelMetadata meta; +#ifdef USE_XIOS + enableXios(); + Xios xiosHandler("P0-0T01:00:00", "test1"); + xiosHandler.setCalendarOrigin(TimePoint("1970-01-01T00:00:00Z")); + meta.setXiosHandler(&xiosHandler); + xiosHandler.close_context_definition(); +#endif meta.setTime(TimePoint("2020-01-01T00:00:00Z")); #ifdef USE_MPI diff --git a/core/test/ParaGrid_test.cpp b/core/test/ParaGrid_test.cpp index f4e41e0c1..8b598ec4d 100644 --- a/core/test/ParaGrid_test.cpp +++ b/core/test/ParaGrid_test.cpp @@ -1,7 +1,7 @@ /*! * @file ParaGrid_test.cpp * - * @date 24 Sep 2024 + * @date 10 Dec 2024 * @author Tim Spain */ @@ -9,6 +9,7 @@ #include #ifdef USE_MPI #include +#undef INFO #else #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include @@ -16,11 +17,11 @@ #include "include/Configurator.hpp" #include "include/ConfiguredModule.hpp" +#include "include/IStructure.hpp" #include "include/NZLevels.hpp" +#include "include/NextsimModule.hpp" #include "include/ParaGridIO.hpp" #include "include/ParametricGrid.hpp" -#include "include/IStructure.hpp" -#include "include/NextsimModule.hpp" #include "include/gridNames.hpp" #include @@ -207,6 +208,13 @@ TEST_CASE("Write and read a ModelState-based ParaGrid restart file") {} }; ModelMetadata metadata; +#ifdef USE_XIOS + enableXios(); + Xios xiosHandler("P0-0T01:00:00", "test1a"); + xiosHandler.setCalendarOrigin(TimePoint("1970-01-01T00:00:00Z")); + metadata.setXiosHandler(&xiosHandler); + xiosHandler.close_context_definition(); +#endif metadata.setTime(TimePoint("2000-01-01T00:00:00Z")); // The coordinates are passed through the metadata object as affix // coordinates is the correct way to add coordinates to a ModelState @@ -250,6 +258,9 @@ TEST_CASE("Write and read a ModelState-based ParaGrid restart file") #ifdef USE_MPI ModelMetadata metadataIn(partitionFilename, test_comm); +#ifdef USE_XIOS + metadataIn.setXiosHandler(&xiosHandler); +#endif metadataIn.setTime(TimePoint(dateString)); ModelState ms = gridIn.getModelState(filename, metadataIn); #else @@ -400,6 +411,13 @@ TEST_CASE("Write a diagnostic ParaGrid file") {} }; ModelMetadata metadata; +#ifdef USE_XIOS + enableXios(); + Xios xiosHandler("P0-0T01:00:00", "test2"); + xiosHandler.setCalendarOrigin(TimePoint("1970-01-01T00:00:00Z")); + metadata.setXiosHandler(&xiosHandler); + xiosHandler.close_context_definition(); +#endif metadata.setTime(TimePoint("2000-01-01T00:00:00Z")); // The coordinates are passed through the metadata object as affix // coordinates is the correct way to add coordinates to a ModelState @@ -536,6 +554,13 @@ TEST_CASE("Check an exception is thrown for an invalid file name") std::string longRandomFilename("a44f5cc1f7934a8ae8dd03a95308745d.nc"); #ifdef USE_MPI ModelMetadata metadataIn(partitionFilename, test_comm); +#ifdef USE_XIOS + enableXios(); + Xios xiosHandler("P0-0T01:00:00", "test4"); + xiosHandler.setCalendarOrigin(TimePoint("1970-01-01T00:00:00Z")); + metadataIn.setXiosHandler(&xiosHandler); + xiosHandler.close_context_definition(); +#endif metadataIn.setTime(TimePoint(dateString)); REQUIRE_THROWS(state = gridIn.getModelState(longRandomFilename, metadataIn)); #else @@ -587,6 +612,13 @@ TEST_CASE("Check if a file with the old dimension names can be read") #ifdef USE_MPI ModelMetadata metadata; +#ifdef USE_XIOS + enableXios(); + Xios xiosHandler("P0-0T01:00:00", "test5"); + xiosHandler.setCalendarOrigin(TimePoint("1970-01-01T00:00:00Z")); + metadata.setXiosHandler(&xiosHandler); + xiosHandler.close_context_definition(); +#endif metadata.setMpiMetadata(test_comm); if (metadata.mpiMyRank == 0) { metadata.localCornerX = 0; diff --git a/core/test/RectGrid_test.cpp b/core/test/RectGrid_test.cpp index a2d2e8c76..ec6c0c296 100644 --- a/core/test/RectGrid_test.cpp +++ b/core/test/RectGrid_test.cpp @@ -1,12 +1,13 @@ /*! * @file RectGrid_test.cpp * - * @date 24 Sep 2024 + * @date 09 Dec 2024 * @author Tim Spain */ #ifdef USE_MPI #include +#undef INFO #else #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include diff --git a/core/test/XiosCalendar_test.cpp b/core/test/XiosCalendar_test.cpp index 6dcd0a7cc..6fe41dae5 100644 --- a/core/test/XiosCalendar_test.cpp +++ b/core/test/XiosCalendar_test.cpp @@ -1,7 +1,7 @@ /*! * @file XiosCalendar_test.cpp * @author Joe Wallwork - * @date 04 Dec 2024 + * @date 10 Dec 2024 * @brief Tests for XIOS calandars * @details * This test is designed to test calendar functionality of the C++ interface @@ -64,7 +64,7 @@ MPI_TEST_CASE("TestXiosInitialization", 2) REQUIRE(xios_handler.getCurrentDate(false) == "2023-03-17 17:11:00"); // -- Tests that the timestep is set up correctly - xios_handler.updateCalendar(1); + xios_handler.setCalendarStep(1); REQUIRE(xios_handler.getCurrentDate() == "2023-03-17T18:41:00Z"); xios_handler.context_finalize(); diff --git a/core/test/XiosReadWrite_test.cpp b/core/test/XiosReadWrite_test.cpp index d746216a8..e9bfe5d70 100644 --- a/core/test/XiosReadWrite_test.cpp +++ b/core/test/XiosReadWrite_test.cpp @@ -1,7 +1,7 @@ /*! * @file XiosReadWrite_test.cpp * @author Joe Wallwork - * @date 04 Dec 2024 + * @date 11 Dec 2024 * @brief Tests for XIOS write method * @details * This test is designed to test the read and write methods of the C++ @@ -12,9 +12,9 @@ #undef INFO #include "StructureModule/include/ParametricGrid.hpp" +#include "include/ModelMetadata.hpp" #include "include/NextsimModule.hpp" #include "include/ParaGridIO.hpp" -#include "include/Xios.hpp" #include @@ -47,6 +47,8 @@ Xios setupXiosHandler(int dim, bool read) throw std::invalid_argument("Test only implemented for 2D and 3D cases"); } + enableXios(); + // Create ParametricGrid and ParaGridIO instances Module::setImplementation("Nextsim::ParametricGrid"); ParametricGrid grid; @@ -145,28 +147,22 @@ void readFile(Xios* xios_handler, HField& field_A, const std::string fieldId) // Check the input file exists REQUIRE(std::filesystem::exists("xios_test_input.nc")); + // Create ModelMetadata instance + ModelMetadata metadata; + metadata.setXiosHandler(xios_handler); + metadata.setTime(xios_handler->getCalendarStart()); + // Simulate 4 iterations (timesteps) + Duration timestep = xios_handler->getCalendarTimestep(); for (int ts = 1; ts <= 4; ts++) { - // Update the current timestep - xios_handler->updateCalendar(ts); + // Update the current timestep and verify it's updated in XIOS + metadata.incrementTime(timestep); + REQUIRE(xios_handler->getCalendarStep() == ts); // Receive data from XIOS that is read from disk xios_handler->read(fieldId, field_A); - // Verify timestep - REQUIRE(xios_handler->getCalendarStep() == ts); } } -/*! - * Utility for checking that two double values are approximately equal. - * - * Without this (i.e., if it's inlined below) the first test passes but the second one fails. The - * same is true with any REQUIRE call. - * - * @param val1 the first double - * @param val2 the second double - */ -void assertIsClose(double val1, double val2) { REQUIRE(val1 == doctest::Approx(val2)); } - /*! * TestXiosRead_2D * @@ -187,7 +183,7 @@ MPI_TEST_CASE("TestXiosRead_2D", 2) const size_t ny = xios_handler.getDomainLocalYSize("xy_domain"); for (size_t j = 0; j < ny; ++j) { for (size_t i = 0; i < nx; ++i) { - assertIsClose(field_2D(i, j), i + nx * j); + REQUIRE(field_2D(i, j) == doctest::Approx(i + nx * j)); } } xios_handler.context_finalize(); @@ -215,7 +211,7 @@ MPI_TEST_CASE("TestXiosRead_3D", 2) for (size_t k = 0; k < nz; ++k) { for (size_t j = 0; j < ny; ++j) { for (size_t i = 0; i < nx; ++i) { - assertIsClose(field_3D(i, j, k), i + nx * (j + ny * k)); + REQUIRE(field_3D(i, j, k) == doctest::Approx(i + nx * (j + ny * k))); } } } @@ -236,14 +232,19 @@ void testFileWrite(Xios* xios_handler, HField& field_A, const std::string fieldI // Check a file with the expected name doesn't exist yet REQUIRE_FALSE(std::filesystem::exists("xios_test_output*.nc")); + // Create ModelMetadata instance + ModelMetadata metadata; + metadata.setXiosHandler(xios_handler); + metadata.setTime(xios_handler->getCalendarStart()); + // Simulate 4 iterations (timesteps) + Duration timestep = xios_handler->getCalendarTimestep(); for (int ts = 1; ts <= 4; ts++) { - // Update the current timestep - xios_handler->updateCalendar(ts); + // Update the current timestep and verify it's updated in XIOS + metadata.incrementTime(timestep); + REQUIRE(xios_handler->getCalendarStep() == ts); // Send data to XIOS to be written to disk xios_handler->write(fieldId, field_A); - // Verify timestep - REQUIRE(xios_handler->getCalendarStep() == ts); } // Check the files have indeed been created then remove it