diff --git a/core/src/Model.cpp b/core/src/Model.cpp index 240a2358a..ec10187cb 100644 --- a/core/src/Model.cpp +++ b/core/src/Model.cpp @@ -50,6 +50,31 @@ Model::Model() Model::~Model() { } +void Model::configureTime() +{ + ModelMetadata& metadata = ModelMetadata::getInstance(); + + // Start/stop times. Run length will override stop time, if present. + std::string startTimeStr + = Configured::getConfiguration(keyMap.at(STARTTIME_KEY), std::string()); + std::string stopTimeStr = Configured::getConfiguration(keyMap.at(STOPTIME_KEY), std::string()); + std::string runLengthStr + = Configured::getConfiguration(keyMap.at(RUNLENGTH_KEY), std::string()); + std::string stepStr = Configured::getConfiguration(keyMap.at(TIMESTEP_KEY), std::string()); + + if (runLengthStr.empty()) { + if (stopTimeStr.empty()) { + throw std::invalid_argument(std::string("At least one of ") + keyMap.at(STOPTIME_KEY) + + " or " + keyMap.at(RUNLENGTH_KEY) + " must be set"); + } else { + metadata.setTimes(startTimeStr, TimePoint(stopTimeStr), stepStr); + } + } else { + metadata.setTimes(startTimeStr, Duration(runLengthStr), stepStr); + } + iterator.setStartStopStep(metadata.startTime(), metadata.stopTime(), metadata.stepLength()); +} + void Model::configure() { // Configure logging @@ -76,25 +101,7 @@ void Model::configure() auto& metadata = ModelMetadata::getInstance(); #endif - // Start/stop times. Run length will override stop time, if present. - std::string startTimeStr - = Configured::getConfiguration(keyMap.at(STARTTIME_KEY), std::string()); - std::string stopTimeStr = Configured::getConfiguration(keyMap.at(STOPTIME_KEY), std::string()); - std::string runLengthStr - = Configured::getConfiguration(keyMap.at(RUNLENGTH_KEY), std::string()); - std::string stepStr = Configured::getConfiguration(keyMap.at(TIMESTEP_KEY), std::string()); - - if (runLengthStr.empty()) { - if (stopTimeStr.empty()) { - throw std::invalid_argument(std::string("At least one of ") + keyMap.at(STOPTIME_KEY) - + " or " + keyMap.at(RUNLENGTH_KEY) + " must be set"); - } else { - metadata.setTimes(startTimeStr, TimePoint(stopTimeStr), stepStr); - } - } else { - metadata.setTimes(startTimeStr, Duration(runLengthStr), stepStr); - } - iterator.setStartStopStep(metadata.startTime(), metadata.stopTime(), metadata.stepLength()); + configureTime(); ModelState initialState(StructureFactory::stateFromFile(initialFileName)); diff --git a/core/src/Xios.cpp b/core/src/Xios.cpp index eb634a8f1..b0dc2ee63 100644 --- a/core/src/Xios.cpp +++ b/core/src/Xios.cpp @@ -121,9 +121,6 @@ bool Xios::doOnce() return true; } -//! Get the configuration for the XIOS handler -ConfigMap Xios::getConfig() const { return ConfigMap(); } - Xios::HelpMap& Xios::getHelpText(HelpMap& map, bool getAll) { map["Xios"] = { @@ -217,40 +214,6 @@ void Xios::configure() istringstream(Configured::getConfiguration(keyMap.at(ENABLED_KEY), std::string())) >> std::boolalpha >> isEnabled; - // Extract the start time from the model configuration - // TODO: Deduce from Model.iterator rather than duplicating here? - std::string startTimeStr; - istringstream(Configured::getConfiguration(keyMap.at(STARTTIME_KEY), std::string())) - >> startTimeStr; - if (startTimeStr.length() == 0) { - Logged::warning("Xios: Setting default start: 1970-01-01T00:00:00Z"); - startTimeStr = "1970-01-01T00:00:00Z"; - } - startTime = TimePoint(startTimeStr); - - // Extract the timestep from the model configuration - // TODO: Deduce from Model.iterator rather than duplicating here? - std::string timeStepStr; - istringstream(Configured::getConfiguration(keyMap.at(TIME_STEP_KEY), std::string())) - >> timeStepStr; - if (timeStepStr.length() == 0) { - Logged::warning("Xios: Setting default time_step: P0-0T01:00:00"); - timeStepStr = "P0-0T01:00:00"; - } - timestep = Duration(timeStepStr); - - // Extract the stop time from the model configuration - // TODO: Deduce from Model.iterator rather than duplicating here? - std::string stopTimeStr; - istringstream(Configured::getConfiguration(keyMap.at(STOPTIME_KEY), std::string())) - >> stopTimeStr; - if (stopTimeStr.length() == 0) { - Logged::warning("Xios: Setting default stop: start time plus P0-0T01:00:00"); - stopTime = startTime + timestep; - } else { - stopTime = TimePoint(stopTimeStr); - } - if (isEnabled) { configureServer(); } @@ -275,7 +238,9 @@ void Xios::configureServer() // Initialize calendar wrapper for 'nextSIM-DG' context cxios_get_current_calendar_wrapper(&clientCalendar); cxios_set_calendar_wrapper_type(clientCalendar, calendarType.c_str(), calendarType.length()); - cxios_set_calendar_wrapper_timestep(clientCalendar, convertDurationToXios(timestep)); + ModelMetadata& metadata = ModelMetadata::getInstance(); + cxios_set_calendar_wrapper_timestep( + clientCalendar, convertDurationToXios(metadata.stepLength())); cxios_create_calendar(clientCalendar); cxios_update_calendar_timestep(clientCalendar); @@ -283,7 +248,7 @@ void Xios::configureServer() setCalendarOrigin(TimePoint("1970-01-01T00:00:00Z")); // Unix epoch // Set start time from configuration file - setCalendarStart(TimePoint(startTime)); + setCalendarStart(metadata.startTime()); } /*! @@ -413,17 +378,6 @@ void Xios::setCalendarStart(const TimePoint start) cxios_set_calendar_wrapper_date_start_date(clientCalendar, datetime); } -/*! - * Set calendar timestep - * - * @param timestep - */ -void Xios::setCalendarTimestep(const Duration timestep) -{ - cxios_set_calendar_wrapper_timestep(clientCalendar, convertDurationToXios(timestep)); - cxios_update_calendar_timestep(clientCalendar); -} - /*! * Update XIOS calendar iteration/step number to some value * @@ -1412,7 +1366,8 @@ void Xios::createFile(const std::string fileId) // TODO: Account for diagnostics (#917) } if (periodStr.length() == 0 || periodStr == "0") { - setFileOutputFreq(fileId, stopTime - startTime); + ModelMetadata& metadata = ModelMetadata::getInstance(); + setFileOutputFreq(fileId, metadata.runLength()); } else { setFileOutputFreq(fileId, Duration(periodStr)); } diff --git a/core/src/include/Model.hpp b/core/src/include/Model.hpp index 3072f16b4..e5c2d1764 100644 --- a/core/src/include/Model.hpp +++ b/core/src/include/Model.hpp @@ -26,6 +26,7 @@ class Model : public Configured { // environment and configuration to the model ~Model(); // Finalize the model. Collect data and so on. + void configureTime(); void configure() override; enum { diff --git a/core/src/include/Xios.hpp b/core/src/include/Xios.hpp index 2eb7c1162..8ba44c347 100644 --- a/core/src/include/Xios.hpp +++ b/core/src/include/Xios.hpp @@ -56,7 +56,6 @@ class Xios : public Configured { }; /* Help config */ - ConfigMap getConfig() const; static HelpMap& getHelpText(HelpMap& map, bool getAll); static HelpMap& getHelpRecursive(HelpMap& map, bool getAll); @@ -78,7 +77,6 @@ class Xios : public Configured { void setCalendarType(const std::string type); 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(); @@ -168,9 +166,6 @@ class Xios : public Configured { /* Calendar, date and duration */ std::string calendarType; - Duration timestep; - TimePoint startTime; - TimePoint stopTime; xios::CCalendarWrapper* clientCalendar; std::string convertXiosDatetimeToString(const cxios_date datetime, const bool isoFormat = true); cxios_date convertStringToXiosDatetime(const std::string datetime, const bool isoFormat = true); diff --git a/core/src/include/indexer.hpp b/core/src/include/indexer.hpp index b03bea186..663779f4b 100644 --- a/core/src/include/indexer.hpp +++ b/core/src/include/indexer.hpp @@ -14,7 +14,7 @@ namespace Indexer { /*! * @brief Produces a one-dimensional index of an array given a multi-dimensional location. * - * @detail Given the dimensions of a mulit-dimensional array and a vector of positions across those + * @details Given the dimensions of a mulit-dimensional array and a vector of positions across those * dimensions, this function returns the corresponding index of that location within the flattened, * one-dimensional representation of the array, as it would typically be stored in memory, or when * a multi-dimensional spatial array is flattened into a single logical dimension. diff --git a/core/test/CMakeLists.txt b/core/test/CMakeLists.txt index 6b0eb2c60..20cbb0bd0 100644 --- a/core/test/CMakeLists.txt +++ b/core/test/CMakeLists.txt @@ -136,6 +136,13 @@ if(ENABLE_MPI) DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/xios_test_mask.cdl ) add_custom_target(generate_xios_masks ALL DEPENDS xios_test_mask.nc) + add_custom_command( + OUTPUT xios_test_partition_metadata_1.nc + COMMAND + ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 1 decomp -m mask -o xy + -g xios_test_mask.nc --output-prefix xios_test + DEPENDS xios_test_mask.nc + ) add_custom_command( OUTPUT xios_test_partition_metadata_2.nc COMMAND @@ -143,15 +150,29 @@ if(ENABLE_MPI) -g xios_test_mask.nc --output-prefix xios_test DEPENDS xios_test_mask.nc ) + add_custom_command( + OUTPUT xios_test_partition_metadata_3.nc + COMMAND + ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 3 decomp -m mask -o xy + -g xios_test_mask.nc --output-prefix xios_test + DEPENDS xios_test_mask.nc + ) add_custom_target(generate_xios_partition_metadata ALL - DEPENDS xios_test_partition_metadata_2.nc + DEPENDS + xios_test_partition_metadata_1.nc + xios_test_partition_metadata_2.nc + xios_test_partition_metadata_3.nc ) add_executable(testXiosCalendar_MPI1 "XiosCalendar_test.cpp" "MainMPI.cpp") target_compile_definitions(testXiosCalendar_MPI1 PRIVATE USE_XIOS) target_include_directories( testXiosCalendar_MPI1 - PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule" + PRIVATE + ${PHYSICS_INCLUDE_DIRS} + "${MODEL_INCLUDE_DIR}" + "${XIOS_INCLUDE_LIST}" + "${ModulesRoot}/StructureModule" ) target_link_libraries(testXiosCalendar_MPI1 PRIVATE nextsimlib doctest::doctest) @@ -159,7 +180,11 @@ if(ENABLE_MPI) target_compile_definitions(testXiosAxis_MPI3 PRIVATE USE_XIOS) target_include_directories( testXiosAxis_MPI3 - PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule" + PRIVATE + ${PHYSICS_INCLUDE_DIRS} + "${MODEL_INCLUDE_DIR}" + "${XIOS_INCLUDE_LIST}" + "${ModulesRoot}/StructureModule" ) target_link_libraries(testXiosAxis_MPI3 PRIVATE nextsimlib doctest::doctest) @@ -167,7 +192,11 @@ if(ENABLE_MPI) target_compile_definitions(testXiosGrid_MPI2 PRIVATE USE_XIOS) target_include_directories( testXiosGrid_MPI2 - PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule" + PRIVATE + ${PHYSICS_INCLUDE_DIRS} + "${MODEL_INCLUDE_DIR}" + "${XIOS_INCLUDE_LIST}" + "${ModulesRoot}/StructureModule" ) target_link_libraries(testXiosGrid_MPI2 PRIVATE nextsimlib doctest::doctest) @@ -175,7 +204,11 @@ if(ENABLE_MPI) target_compile_definitions(testXiosField_MPI3 PRIVATE USE_XIOS) target_include_directories( testXiosField_MPI3 - PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule" + PRIVATE + ${PHYSICS_INCLUDE_DIRS} + "${MODEL_INCLUDE_DIR}" + "${XIOS_INCLUDE_LIST}" + "${ModulesRoot}/StructureModule" ) target_link_libraries(testXiosField_MPI3 PRIVATE nextsimlib doctest::doctest) @@ -183,7 +216,11 @@ if(ENABLE_MPI) target_compile_definitions(testXiosFile_MPI2 PRIVATE USE_XIOS) target_include_directories( testXiosFile_MPI2 - PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule" + PRIVATE + ${PHYSICS_INCLUDE_DIRS} + "${MODEL_INCLUDE_DIR}" + "${XIOS_INCLUDE_LIST}" + "${ModulesRoot}/StructureModule" ) target_link_libraries(testXiosFile_MPI2 PRIVATE nextsimlib doctest::doctest) @@ -195,7 +232,11 @@ if(ENABLE_MPI) ) target_include_directories( testXiosRead_MPI2 - PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule" + PRIVATE + ${PHYSICS_INCLUDE_DIRS} + "${MODEL_INCLUDE_DIR}" + "${XIOS_INCLUDE_LIST}" + "${ModulesRoot}/StructureModule" ) target_link_libraries(testXiosRead_MPI2 PRIVATE nextsimlib doctest::doctest) @@ -203,7 +244,11 @@ if(ENABLE_MPI) target_compile_definitions(testXiosWrite_MPI2 PRIVATE USE_XIOS) target_include_directories( testXiosWrite_MPI2 - PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule" + PRIVATE + ${PHYSICS_INCLUDE_DIRS} + "${MODEL_INCLUDE_DIR}" + "${XIOS_INCLUDE_LIST}" + "${ModulesRoot}/StructureModule" ) target_link_libraries(testXiosWrite_MPI2 PRIVATE nextsimlib doctest::doctest) diff --git a/core/test/XiosAxis_test.cpp b/core/test/XiosAxis_test.cpp index 0c57f4571..6c5175cff 100644 --- a/core/test/XiosAxis_test.cpp +++ b/core/test/XiosAxis_test.cpp @@ -11,6 +11,8 @@ #include "StructureModule/include/ParametricGrid.hpp" #include "include/Finalizer.hpp" +#include "include/Model.hpp" +#include "include/ModelMPI.hpp" #include "include/Xios.hpp" namespace Nextsim { @@ -26,7 +28,23 @@ namespace Nextsim { */ MPI_TEST_CASE("TestXiosAxis", 3) { + // Enable XIOS in the 'config' and provide parameters to configure it enableXios(); + std::stringstream config; + config << "[model]" << std::endl; + config << "start = 2023-03-17T17:11:00Z" << std::endl; + config << "stop = 2023-03-17T18:11:00Z" << std::endl; + config << "time_step = P0-0T01:00:00" << std::endl; + std::unique_ptr pcstream(new std::stringstream(config.str())); + Configurator::addStream(std::move(pcstream)); + + // Create ModelMetadata instance based off a partition metadata file + auto& modelMPI = ModelMPI::getInstance(test_comm); + auto& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_3.nc"); + + // Create a Model and configure it so that time options are parsed + Model model; + model.configureTime(); // Get the Xios singleton instance and check it's initialized Xios& xiosHandler = Xios::getInstance(); diff --git a/core/test/XiosCalendar_test.cpp b/core/test/XiosCalendar_test.cpp index 593b99402..e3f495696 100644 --- a/core/test/XiosCalendar_test.cpp +++ b/core/test/XiosCalendar_test.cpp @@ -12,6 +12,8 @@ #include "StructureModule/include/ParametricGrid.hpp" #include "include/Configurator.hpp" #include "include/Finalizer.hpp" +#include "include/Model.hpp" +#include "include/ModelMPI.hpp" #include "include/Xios.hpp" namespace Nextsim { @@ -32,10 +34,19 @@ MPI_TEST_CASE("TestXiosCalendar", 1) std::stringstream config; config << "[model]" << std::endl; config << "start = 2023-03-17T17:11:00Z" << std::endl; + config << "stop = 2023-03-17T18:11:00Z" << std::endl; config << "time_step = P0-0T01:00:00" << std::endl; std::unique_ptr pcstream(new std::stringstream(config.str())); Configurator::addStream(std::move(pcstream)); + // Create ModelMetadata instance based off a partition metadata file + auto& modelMPI = ModelMPI::getInstance(test_comm); + auto& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_1.nc"); + + // Create a Model and configure it so that time options are parsed + Model model; + model.configureTime(); + // Get the Xios singleton instance and check it's initialized Xios& xiosHandler = Xios::getInstance(); REQUIRE(xiosHandler.isInitialized()); @@ -57,11 +68,7 @@ MPI_TEST_CASE("TestXiosCalendar", 1) REQUIRE(start == xiosHandler.getCalendarStart()); REQUIRE(start.format() == "2023-03-17T17:11:00Z"); // Timestep - REQUIRE(xiosHandler.getCalendarTimestep().seconds() == 3600.0); // Default - Duration timestep("P0-0T01:30:00"); - REQUIRE(timestep.seconds() == 5400.0); - xiosHandler.setCalendarTimestep(timestep); - REQUIRE(xiosHandler.getCalendarTimestep().seconds() == 5400.0); + REQUIRE(xiosHandler.getCalendarTimestep().seconds() == 3600.0); // Read from config xiosHandler.close_context_definition(); @@ -72,7 +79,7 @@ MPI_TEST_CASE("TestXiosCalendar", 1) // -- Tests that the timestep is set up correctly xiosHandler.setCalendarStep(1); REQUIRE(xiosHandler.getCalendarStep() == 1); - REQUIRE(xiosHandler.getCurrentDate().format() == "2023-03-17T18:41:00Z"); + REQUIRE(xiosHandler.getCurrentDate().format() == "2023-03-17T18:11:00Z"); xiosHandler.context_finalize(); Finalizer::finalize(); diff --git a/core/test/XiosField_test.cpp b/core/test/XiosField_test.cpp index ed5b0e985..29d8d937c 100644 --- a/core/test/XiosField_test.cpp +++ b/core/test/XiosField_test.cpp @@ -11,6 +11,8 @@ #include "StructureModule/include/ParametricGrid.hpp" #include "include/Finalizer.hpp" +#include "include/Model.hpp" +#include "include/ModelMPI.hpp" #include "include/Xios.hpp" namespace Nextsim { @@ -29,6 +31,10 @@ MPI_TEST_CASE("TestXiosField", 3) // Enable XIOS in the 'config' and provide parameters to configure it enableXios(); std::stringstream config; + config << "[model]" << std::endl; + config << "start = 2023-03-17T17:11:00Z" << std::endl; + config << "stop = 2023-03-17T18:11:00Z" << std::endl; + config << "time_step = P0-0T01:00:00" << std::endl; config << "[XiosOutput]" << std::endl; config << "period = P0-0T03:00:00" << std::endl; config << "filename = xios_test_output" << std::endl; @@ -36,6 +42,14 @@ MPI_TEST_CASE("TestXiosField", 3) std::unique_ptr pcstream(new std::stringstream(config.str())); Configurator::addStream(std::move(pcstream)); + // Create ModelMetadata instance based off a partition metadata file + auto& modelMPI = ModelMPI::getInstance(test_comm); + auto& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_3.nc"); + + // Create a Model and configure it so that time options are parsed + Model model; + model.configureTime(); + // Get the Xios singleton instance and check it's initialized Xios& xiosHandler = Xios::getInstance(); REQUIRE(xiosHandler.isInitialized()); diff --git a/core/test/XiosFile_test.cpp b/core/test/XiosFile_test.cpp index f183a156c..c5279dc72 100644 --- a/core/test/XiosFile_test.cpp +++ b/core/test/XiosFile_test.cpp @@ -12,8 +12,8 @@ #include "StructureModule/include/ParametricGrid.hpp" #include "include/Configurator.hpp" #include "include/Finalizer.hpp" +#include "include/Model.hpp" #include "include/ModelMPI.hpp" -#include "include/ModelMetadata.hpp" #include "include/Xios.hpp" using namespace doctest; @@ -36,6 +36,7 @@ MPI_TEST_CASE("TestXiosFile", 2) std::stringstream config; config << "[model]" << std::endl; config << "start = 2023-03-17T17:11:00Z" << std::endl; + config << "stop = 2023-03-17T18:41:00Z" << std::endl; config << "time_step = P0-0T01:30:00" << std::endl; config << "[XiosInput]" << std::endl; config << "period = P0-0T03:00:00" << std::endl; @@ -52,9 +53,12 @@ MPI_TEST_CASE("TestXiosFile", 2) auto& modelMPI = ModelMPI::getInstance(test_comm); auto& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_2.nc"); + // Create a Model and configure it so that time options are parsed + Model model; + model.configureTime(); // TODO: Use Model.configure to parse restart files this way, too? + // Get the Xios singleton instance and check it's initialized Xios& xiosHandler = Xios::getInstance(); - xiosHandler.affixModelMetadata(); REQUIRE(xiosHandler.isInitialized()); REQUIRE(xiosHandler.getClientMPISize() == 2); @@ -63,6 +67,10 @@ MPI_TEST_CASE("TestXiosFile", 2) xiosHandler.setFieldType("mask", ModelArray::Type::H); xiosHandler.setFieldType("hice", ModelArray::Type::DG); + // Affix ModelMetadata to Xios handler + // TODO: Automate this - can't be inlined in Xios::getInstance because need set field types + xiosHandler.affixModelMetadata(); + // --- Tests for file API const std::string inFileId = "xios_test_input"; const std::string outFileId = "xios_test_output"; diff --git a/core/test/XiosGrid_test.cpp b/core/test/XiosGrid_test.cpp index baed00c44..ab79d93db 100644 --- a/core/test/XiosGrid_test.cpp +++ b/core/test/XiosGrid_test.cpp @@ -10,8 +10,8 @@ #undef INFO #include "include/Finalizer.hpp" +#include "include/Model.hpp" #include "include/ModelMPI.hpp" -#include "include/ModelMetadata.hpp" #include "include/Xios.hpp" namespace Nextsim { @@ -27,18 +27,33 @@ namespace Nextsim { */ MPI_TEST_CASE("TestXiosGrid", 2) { + // Enable XIOS in the 'config' and provide parameters to configure it enableXios(); + std::stringstream config; + config << "[model]" << std::endl; + config << "start = 2023-03-17T17:11:00Z" << std::endl; + config << "stop = 2023-03-17T18:11:00Z" << std::endl; + config << "time_step = P0-0T01:00:00" << std::endl; + std::unique_ptr pcstream(new std::stringstream(config.str())); + Configurator::addStream(std::move(pcstream)); // Create ModelMetadata instance based off a partition metadata file auto& modelMPI = ModelMPI::getInstance(test_comm); auto& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_2.nc"); + // Create a Model and configure it so that time options are parsed + Model model; + model.configureTime(); + // Get the Xios singleton instance and check it's initialized Xios& xiosHandler = Xios::getInstance(); - xiosHandler.affixModelMetadata(); REQUIRE(xiosHandler.isInitialized()); REQUIRE(xiosHandler.getClientMPISize() == 2); + // Affix ModelMetadata to Xios handler + // TODO: Automate this - can't be inlined in Xios::getInstance because need set field types + xiosHandler.affixModelMetadata(); + const std::string gridId = "HGrid"; REQUIRE_THROWS_WITH(xiosHandler.createGrid(gridId), "Xios: Grid 'HGrid' already exists"); diff --git a/core/test/XiosRead_test.cpp b/core/test/XiosRead_test.cpp index 0515c4a89..45d26fbca 100644 --- a/core/test/XiosRead_test.cpp +++ b/core/test/XiosRead_test.cpp @@ -10,8 +10,8 @@ #include "StructureModule/include/ParametricGrid.hpp" #include "include/Finalizer.hpp" +#include "include/Model.hpp" #include "include/ModelMPI.hpp" -#include "include/ModelMetadata.hpp" #include "include/NextsimModule.hpp" #include "include/ParaGridIO.hpp" #include "include/Xios.hpp" @@ -53,6 +53,14 @@ MPI_TEST_CASE("TestXiosRead", 2) std::unique_ptr pcstream(new std::stringstream(config.str())); Configurator::addStream(std::move(pcstream)); + // Create ModelMetadata instance based off a partition metadata file + auto& modelMPI = ModelMPI::getInstance(test_comm); + auto& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_2.nc"); + + // Create a Model and configure it so that time options are parsed + Model model; + model.configureTime(); // TODO: Use Model.configure to parse restart files this way, too? + // Create ParametricGrid and ParaGridIO instances Module::setImplementation("Nextsim::ParametricGrid"); ParametricGrid grid; @@ -70,10 +78,8 @@ MPI_TEST_CASE("TestXiosRead", 2) REQUIRE(ModelArray::nComponents(ModelArray::Type::DG) == DG); REQUIRE(ModelArray::nComponents(ModelArray::Type::VERTEX) == ModelArray::nCoords); - // Create ModelMetadata instance based off a partition metadata file - // NOTE: ModelArray dimensions are determined from the input file, if present - ModelMPI& modelMPI = ModelMPI::getInstance(test_comm); - ModelMetadata& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_2.nc"); + // Affix ModelMetadata to Xios handler + // TODO: Automate this - can't be inlined in Xios::getInstance because need set field types xiosHandler.affixModelMetadata(); xiosHandler.close_context_definition(); diff --git a/core/test/XiosWrite_test.cpp b/core/test/XiosWrite_test.cpp index b9d5d8ed9..799586a32 100644 --- a/core/test/XiosWrite_test.cpp +++ b/core/test/XiosWrite_test.cpp @@ -10,8 +10,8 @@ #include "StructureModule/include/ParametricGrid.hpp" #include "include/Finalizer.hpp" +#include "include/Model.hpp" #include "include/ModelMPI.hpp" -#include "include/ModelMetadata.hpp" #include "include/NextsimModule.hpp" #include "include/ParaGridIO.hpp" #include "include/Xios.hpp" @@ -45,6 +45,14 @@ MPI_TEST_CASE("TestXiosWrite", 2) std::unique_ptr pcstream(new std::stringstream(config.str())); Configurator::addStream(std::move(pcstream)); + // Create ModelMetadata instance based off a partition metadata file + auto& modelMPI = ModelMPI::getInstance(test_comm); + auto& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_2.nc"); + + // Create a Model and configure it so that time options are parsed + Model model; + model.configureTime(); // TODO: Use Model.configure to parse restart files this way, too? + // Create ParametricGrid and ParaGridIO instances Module::setImplementation("Nextsim::ParametricGrid"); ParametricGrid grid; @@ -70,9 +78,8 @@ MPI_TEST_CASE("TestXiosWrite", 2) REQUIRE(ModelArray::nComponents(ModelArray::Type::DG) == DG); REQUIRE(ModelArray::nComponents(ModelArray::Type::VERTEX) == ModelArray::nCoords); - // Create ModelMetadata instance based off a partition metadata file - ModelMPI& modelMPI = ModelMPI::getInstance(test_comm); - ModelMetadata& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_2.nc"); + // Affix ModelMetadata to Xios handler + // TODO: Automate this - can't be inlined in Xios::getInstance because need set field types xiosHandler.affixModelMetadata(); // Set field types diff --git a/docs/xios.rst b/docs/xios.rst index e9a5ffa01..7c1ec3888 100644 --- a/docs/xios.rst +++ b/docs/xios.rst @@ -27,13 +27,14 @@ build nextSIM-DG with XIOS as the I/O driver. [xios] enable = true -The ``model`` section, which is used elsewhere in nextSIM-DG, contains two -entries relevant to XIOS: ``start`` and ``time_step``. These are used to -configure the calendar used by XIOS and take the following default values. +The ``model`` section, which is used elsewhere in nextSIM-DG, contains three +entries relevant to XIOS: ``start``, ``stop``, and ``time_step``. These are +used to configure the calendar used by XIOS. For example, .. code-block:: [model] start = 1970-01-01T00:00:00Z + stop = 1970-01-01T01:00:00Z time_step = P0-0T01:00:00 Files and fields to be read and written to files are configured via the @@ -53,6 +54,11 @@ The ``field_names`` entry may contain a single field name or a comma-separated list. Note that all of the ``XiosInput``, ``XiosOutput``, and ``XiosForcing`` sections are optional. +As elsewhere in the model, these configuration values are parsed by calling the +``Model.configure`` member function. Since building with XIOS implies also +building with MPI, you will need to pass the MPI communicator to this member +function when calling it. + Developer notes ^^^^^^^^^^^^^^^