Skip to content

Commit 911a0ee

Browse files
authored
Reuse time metadata config in XIOS (#939)
# Use model config in XIOS Fixes #925 Follows #936 Second attempt following #932 ~~Merges into #913~~ ### Task List - [x] Defined the tests that specify a complete and functioning change (*It may help to create a [design specification & test specification](../../../wiki/Specification-Template)*) - [x] Implemented the source code change that satisfies the tests - [x] Documented the feature by providing worked example - [x] Updated the README or other documentation - [x] Completed the pre-Request checklist below --- # Change Description This PR reuses the time metadata set as part of the config set in the XIOS handler. --- # Test Description For the purposes of testing, a separate `Model.configureTime` member function is created to avoid having to configure *everything*. I also needed to get the build system to create partition metadata files for 1 and 3 MPI ranks for the XIOS tests and to extend the configuration for all of them. --- # Documentation Impact The XIOS doc pages are updated to reflect these changes. --- ### Pre-Request Checklist - [x] The requirements of this pull request are fully captured in an issue or design specification and are linked and summarised in the description of this PR - [x] No new warnings are generated - [x] The documentation has been updated (or an issue has been created to track the corresponding change) - [x] Methods and Tests are commented such that they can be understood without having to obtain additional context - [x] This PR/Issue is labelled as a bug/feature/enhancement/breaking change - [x] This change conforms to the conventions described in the README
2 parents 24a73bb + 326c552 commit 911a0ee

14 files changed

+190
-106
lines changed

core/src/Model.cpp

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,31 @@ Model::Model()
5050

5151
Model::~Model() { }
5252

53+
void Model::configureTime()
54+
{
55+
ModelMetadata& metadata = ModelMetadata::getInstance();
56+
57+
// Start/stop times. Run length will override stop time, if present.
58+
std::string startTimeStr
59+
= Configured::getConfiguration(keyMap.at(STARTTIME_KEY), std::string());
60+
std::string stopTimeStr = Configured::getConfiguration(keyMap.at(STOPTIME_KEY), std::string());
61+
std::string runLengthStr
62+
= Configured::getConfiguration(keyMap.at(RUNLENGTH_KEY), std::string());
63+
std::string stepStr = Configured::getConfiguration(keyMap.at(TIMESTEP_KEY), std::string());
64+
65+
if (runLengthStr.empty()) {
66+
if (stopTimeStr.empty()) {
67+
throw std::invalid_argument(std::string("At least one of ") + keyMap.at(STOPTIME_KEY)
68+
+ " or " + keyMap.at(RUNLENGTH_KEY) + " must be set");
69+
} else {
70+
metadata.setTimes(startTimeStr, TimePoint(stopTimeStr), stepStr);
71+
}
72+
} else {
73+
metadata.setTimes(startTimeStr, Duration(runLengthStr), stepStr);
74+
}
75+
iterator.setStartStopStep(metadata.startTime(), metadata.stopTime(), metadata.stepLength());
76+
}
77+
5378
void Model::configure()
5479
{
5580
// Configure logging
@@ -76,25 +101,7 @@ void Model::configure()
76101
auto& metadata = ModelMetadata::getInstance();
77102
#endif
78103

79-
// Start/stop times. Run length will override stop time, if present.
80-
std::string startTimeStr
81-
= Configured::getConfiguration(keyMap.at(STARTTIME_KEY), std::string());
82-
std::string stopTimeStr = Configured::getConfiguration(keyMap.at(STOPTIME_KEY), std::string());
83-
std::string runLengthStr
84-
= Configured::getConfiguration(keyMap.at(RUNLENGTH_KEY), std::string());
85-
std::string stepStr = Configured::getConfiguration(keyMap.at(TIMESTEP_KEY), std::string());
86-
87-
if (runLengthStr.empty()) {
88-
if (stopTimeStr.empty()) {
89-
throw std::invalid_argument(std::string("At least one of ") + keyMap.at(STOPTIME_KEY)
90-
+ " or " + keyMap.at(RUNLENGTH_KEY) + " must be set");
91-
} else {
92-
metadata.setTimes(startTimeStr, TimePoint(stopTimeStr), stepStr);
93-
}
94-
} else {
95-
metadata.setTimes(startTimeStr, Duration(runLengthStr), stepStr);
96-
}
97-
iterator.setStartStopStep(metadata.startTime(), metadata.stopTime(), metadata.stepLength());
104+
configureTime();
98105

99106
ModelState initialState(StructureFactory::stateFromFile(initialFileName));
100107

core/src/Xios.cpp

Lines changed: 6 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,6 @@ bool Xios::doOnce()
121121
return true;
122122
}
123123

124-
//! Get the configuration for the XIOS handler
125-
ConfigMap Xios::getConfig() const { return ConfigMap(); }
126-
127124
Xios::HelpMap& Xios::getHelpText(HelpMap& map, bool getAll)
128125
{
129126
map["Xios"] = {
@@ -217,40 +214,6 @@ void Xios::configure()
217214
istringstream(Configured::getConfiguration(keyMap.at(ENABLED_KEY), std::string()))
218215
>> std::boolalpha >> isEnabled;
219216

220-
// Extract the start time from the model configuration
221-
// TODO: Deduce from Model.iterator rather than duplicating here?
222-
std::string startTimeStr;
223-
istringstream(Configured::getConfiguration(keyMap.at(STARTTIME_KEY), std::string()))
224-
>> startTimeStr;
225-
if (startTimeStr.length() == 0) {
226-
Logged::warning("Xios: Setting default start: 1970-01-01T00:00:00Z");
227-
startTimeStr = "1970-01-01T00:00:00Z";
228-
}
229-
startTime = TimePoint(startTimeStr);
230-
231-
// Extract the timestep from the model configuration
232-
// TODO: Deduce from Model.iterator rather than duplicating here?
233-
std::string timeStepStr;
234-
istringstream(Configured::getConfiguration(keyMap.at(TIME_STEP_KEY), std::string()))
235-
>> timeStepStr;
236-
if (timeStepStr.length() == 0) {
237-
Logged::warning("Xios: Setting default time_step: P0-0T01:00:00");
238-
timeStepStr = "P0-0T01:00:00";
239-
}
240-
timestep = Duration(timeStepStr);
241-
242-
// Extract the stop time from the model configuration
243-
// TODO: Deduce from Model.iterator rather than duplicating here?
244-
std::string stopTimeStr;
245-
istringstream(Configured::getConfiguration(keyMap.at(STOPTIME_KEY), std::string()))
246-
>> stopTimeStr;
247-
if (stopTimeStr.length() == 0) {
248-
Logged::warning("Xios: Setting default stop: start time plus P0-0T01:00:00");
249-
stopTime = startTime + timestep;
250-
} else {
251-
stopTime = TimePoint(stopTimeStr);
252-
}
253-
254217
if (isEnabled) {
255218
configureServer();
256219
}
@@ -275,15 +238,17 @@ void Xios::configureServer()
275238
// Initialize calendar wrapper for 'nextSIM-DG' context
276239
cxios_get_current_calendar_wrapper(&clientCalendar);
277240
cxios_set_calendar_wrapper_type(clientCalendar, calendarType.c_str(), calendarType.length());
278-
cxios_set_calendar_wrapper_timestep(clientCalendar, convertDurationToXios(timestep));
241+
ModelMetadata& metadata = ModelMetadata::getInstance();
242+
cxios_set_calendar_wrapper_timestep(
243+
clientCalendar, convertDurationToXios(metadata.stepLength()));
279244
cxios_create_calendar(clientCalendar);
280245
cxios_update_calendar_timestep(clientCalendar);
281246

282247
// Set default calendar origin
283248
setCalendarOrigin(TimePoint("1970-01-01T00:00:00Z")); // Unix epoch
284249

285250
// Set start time from configuration file
286-
setCalendarStart(TimePoint(startTime));
251+
setCalendarStart(metadata.startTime());
287252
}
288253

289254
/*!
@@ -413,17 +378,6 @@ void Xios::setCalendarStart(const TimePoint start)
413378
cxios_set_calendar_wrapper_date_start_date(clientCalendar, datetime);
414379
}
415380

416-
/*!
417-
* Set calendar timestep
418-
*
419-
* @param timestep
420-
*/
421-
void Xios::setCalendarTimestep(const Duration timestep)
422-
{
423-
cxios_set_calendar_wrapper_timestep(clientCalendar, convertDurationToXios(timestep));
424-
cxios_update_calendar_timestep(clientCalendar);
425-
}
426-
427381
/*!
428382
* Update XIOS calendar iteration/step number to some value
429383
*
@@ -1412,7 +1366,8 @@ void Xios::createFile(const std::string fileId)
14121366
// TODO: Account for diagnostics (#917)
14131367
}
14141368
if (periodStr.length() == 0 || periodStr == "0") {
1415-
setFileOutputFreq(fileId, stopTime - startTime);
1369+
ModelMetadata& metadata = ModelMetadata::getInstance();
1370+
setFileOutputFreq(fileId, metadata.runLength());
14161371
} else {
14171372
setFileOutputFreq(fileId, Duration(periodStr));
14181373
}

core/src/include/Model.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class Model : public Configured<Model> {
2626
// environment and configuration to the model
2727
~Model(); // Finalize the model. Collect data and so on.
2828

29+
void configureTime();
2930
void configure() override;
3031

3132
enum {

core/src/include/Xios.hpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ class Xios : public Configured<Xios> {
5656
};
5757

5858
/* Help config */
59-
ConfigMap getConfig() const;
6059
static HelpMap& getHelpText(HelpMap& map, bool getAll);
6160
static HelpMap& getHelpRecursive(HelpMap& map, bool getAll);
6261

@@ -78,7 +77,6 @@ class Xios : public Configured<Xios> {
7877
void setCalendarType(const std::string type);
7978
void setCalendarOrigin(const TimePoint origin);
8079
void setCalendarStart(const TimePoint start);
81-
void setCalendarTimestep(const Duration timestep);
8280
void setCalendarStep(const int stepNumber);
8381
void incrementCalendar();
8482
std::string getCalendarType();
@@ -168,9 +166,6 @@ class Xios : public Configured<Xios> {
168166

169167
/* Calendar, date and duration */
170168
std::string calendarType;
171-
Duration timestep;
172-
TimePoint startTime;
173-
TimePoint stopTime;
174169
xios::CCalendarWrapper* clientCalendar;
175170
std::string convertXiosDatetimeToString(const cxios_date datetime, const bool isoFormat = true);
176171
cxios_date convertStringToXiosDatetime(const std::string datetime, const bool isoFormat = true);

core/src/include/indexer.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Indexer {
1414
/*!
1515
* @brief Produces a one-dimensional index of an array given a multi-dimensional location.
1616
*
17-
* @detail Given the dimensions of a mulit-dimensional array and a vector of positions across those
17+
* @details Given the dimensions of a mulit-dimensional array and a vector of positions across those
1818
* dimensions, this function returns the corresponding index of that location within the flattened,
1919
* one-dimensional representation of the array, as it would typically be stored in memory, or when
2020
* a multi-dimensional spatial array is flattened into a single logical dimension.

core/test/CMakeLists.txt

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -136,54 +136,91 @@ if(ENABLE_MPI)
136136
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/xios_test_mask.cdl
137137
)
138138
add_custom_target(generate_xios_masks ALL DEPENDS xios_test_mask.nc)
139+
add_custom_command(
140+
OUTPUT xios_test_partition_metadata_1.nc
141+
COMMAND
142+
${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 1 decomp -m mask -o xy
143+
-g xios_test_mask.nc --output-prefix xios_test
144+
DEPENDS xios_test_mask.nc
145+
)
139146
add_custom_command(
140147
OUTPUT xios_test_partition_metadata_2.nc
141148
COMMAND
142149
${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2 decomp -m mask -o xy
143150
-g xios_test_mask.nc --output-prefix xios_test
144151
DEPENDS xios_test_mask.nc
145152
)
153+
add_custom_command(
154+
OUTPUT xios_test_partition_metadata_3.nc
155+
COMMAND
156+
${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 3 decomp -m mask -o xy
157+
-g xios_test_mask.nc --output-prefix xios_test
158+
DEPENDS xios_test_mask.nc
159+
)
146160
add_custom_target(generate_xios_partition_metadata ALL
147-
DEPENDS xios_test_partition_metadata_2.nc
161+
DEPENDS
162+
xios_test_partition_metadata_1.nc
163+
xios_test_partition_metadata_2.nc
164+
xios_test_partition_metadata_3.nc
148165
)
149166

150167
add_executable(testXiosCalendar_MPI1 "XiosCalendar_test.cpp" "MainMPI.cpp")
151168
target_compile_definitions(testXiosCalendar_MPI1 PRIVATE USE_XIOS)
152169
target_include_directories(
153170
testXiosCalendar_MPI1
154-
PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule"
171+
PRIVATE
172+
${PHYSICS_INCLUDE_DIRS}
173+
"${MODEL_INCLUDE_DIR}"
174+
"${XIOS_INCLUDE_LIST}"
175+
"${ModulesRoot}/StructureModule"
155176
)
156177
target_link_libraries(testXiosCalendar_MPI1 PRIVATE nextsimlib doctest::doctest)
157178

158179
add_executable(testXiosAxis_MPI3 "XiosAxis_test.cpp" "MainMPI.cpp")
159180
target_compile_definitions(testXiosAxis_MPI3 PRIVATE USE_XIOS)
160181
target_include_directories(
161182
testXiosAxis_MPI3
162-
PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule"
183+
PRIVATE
184+
${PHYSICS_INCLUDE_DIRS}
185+
"${MODEL_INCLUDE_DIR}"
186+
"${XIOS_INCLUDE_LIST}"
187+
"${ModulesRoot}/StructureModule"
163188
)
164189
target_link_libraries(testXiosAxis_MPI3 PRIVATE nextsimlib doctest::doctest)
165190

166191
add_executable(testXiosGrid_MPI2 "XiosGrid_test.cpp" "MainMPI.cpp")
167192
target_compile_definitions(testXiosGrid_MPI2 PRIVATE USE_XIOS)
168193
target_include_directories(
169194
testXiosGrid_MPI2
170-
PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule"
195+
PRIVATE
196+
${PHYSICS_INCLUDE_DIRS}
197+
"${MODEL_INCLUDE_DIR}"
198+
"${XIOS_INCLUDE_LIST}"
199+
"${ModulesRoot}/StructureModule"
171200
)
172201
target_link_libraries(testXiosGrid_MPI2 PRIVATE nextsimlib doctest::doctest)
173202

174203
add_executable(testXiosField_MPI3 "XiosField_test.cpp" "MainMPI.cpp")
175204
target_compile_definitions(testXiosField_MPI3 PRIVATE USE_XIOS)
176205
target_include_directories(
177206
testXiosField_MPI3
178-
PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule"
207+
PRIVATE
208+
${PHYSICS_INCLUDE_DIRS}
209+
"${MODEL_INCLUDE_DIR}"
210+
"${XIOS_INCLUDE_LIST}"
211+
"${ModulesRoot}/StructureModule"
179212
)
180213
target_link_libraries(testXiosField_MPI3 PRIVATE nextsimlib doctest::doctest)
181214

182215
add_executable(testXiosFile_MPI2 "XiosFile_test.cpp" "MainMPI.cpp")
183216
target_compile_definitions(testXiosFile_MPI2 PRIVATE USE_XIOS)
184217
target_include_directories(
185218
testXiosFile_MPI2
186-
PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule"
219+
PRIVATE
220+
${PHYSICS_INCLUDE_DIRS}
221+
"${MODEL_INCLUDE_DIR}"
222+
"${XIOS_INCLUDE_LIST}"
223+
"${ModulesRoot}/StructureModule"
187224
)
188225
target_link_libraries(testXiosFile_MPI2 PRIVATE nextsimlib doctest::doctest)
189226

@@ -195,15 +232,23 @@ if(ENABLE_MPI)
195232
)
196233
target_include_directories(
197234
testXiosRead_MPI2
198-
PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule"
235+
PRIVATE
236+
${PHYSICS_INCLUDE_DIRS}
237+
"${MODEL_INCLUDE_DIR}"
238+
"${XIOS_INCLUDE_LIST}"
239+
"${ModulesRoot}/StructureModule"
199240
)
200241
target_link_libraries(testXiosRead_MPI2 PRIVATE nextsimlib doctest::doctest)
201242

202243
add_executable(testXiosWrite_MPI2 "XiosWrite_test.cpp" "MainMPI.cpp")
203244
target_compile_definitions(testXiosWrite_MPI2 PRIVATE USE_XIOS)
204245
target_include_directories(
205246
testXiosWrite_MPI2
206-
PRIVATE "${MODEL_INCLUDE_DIR}" "${XIOS_INCLUDE_LIST}" "${ModulesRoot}/StructureModule"
247+
PRIVATE
248+
${PHYSICS_INCLUDE_DIRS}
249+
"${MODEL_INCLUDE_DIR}"
250+
"${XIOS_INCLUDE_LIST}"
251+
"${ModulesRoot}/StructureModule"
207252
)
208253
target_link_libraries(testXiosWrite_MPI2 PRIVATE nextsimlib doctest::doctest)
209254

core/test/XiosAxis_test.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#include "StructureModule/include/ParametricGrid.hpp"
1313
#include "include/Finalizer.hpp"
14+
#include "include/Model.hpp"
15+
#include "include/ModelMPI.hpp"
1416
#include "include/Xios.hpp"
1517

1618
namespace Nextsim {
@@ -26,7 +28,23 @@ namespace Nextsim {
2628
*/
2729
MPI_TEST_CASE("TestXiosAxis", 3)
2830
{
31+
// Enable XIOS in the 'config' and provide parameters to configure it
2932
enableXios();
33+
std::stringstream config;
34+
config << "[model]" << std::endl;
35+
config << "start = 2023-03-17T17:11:00Z" << std::endl;
36+
config << "stop = 2023-03-17T18:11:00Z" << std::endl;
37+
config << "time_step = P0-0T01:00:00" << std::endl;
38+
std::unique_ptr<std::istream> pcstream(new std::stringstream(config.str()));
39+
Configurator::addStream(std::move(pcstream));
40+
41+
// Create ModelMetadata instance based off a partition metadata file
42+
auto& modelMPI = ModelMPI::getInstance(test_comm);
43+
auto& metadata = ModelMetadata::getInstance("xios_test_partition_metadata_3.nc");
44+
45+
// Create a Model and configure it so that time options are parsed
46+
Model model;
47+
model.configureTime();
3048

3149
// Get the Xios singleton instance and check it's initialized
3250
Xios& xiosHandler = Xios::getInstance();

0 commit comments

Comments
 (0)