Program Listing for File Model.cpp¶
↰ Return to documentation for file (core/src/Model.cpp)
#include "include/Model.hpp"
#include "include/Configurator.hpp"
#include "include/ConfiguredModule.hpp"
#include "include/DevStep.hpp"
#include "include/Finalizer.hpp"
#include "include/IDiagnosticOutput.hpp"
#include "include/MissingData.hpp"
#include "include/NextsimModule.hpp"
#include "include/StructureFactory.hpp"
#ifdef USE_XIOS
#include "include/Xios.hpp"
#endif
#include <string>
// TODO Replace with real logging
#include <iostream>
namespace Nextsim {
// Map of configuration that will be written to the restart file
const std::string Model::restartOptionName = "model.init_file";
// Map of all configuration keys for the main model, including those not to be
// written to the restart file.
static const std::map<int, std::string> keyMap = {
{ Model::RESTARTFILE_KEY, Model::restartOptionName },
#ifdef USE_MPI
{ Model::PARTITIONFILE_KEY, "model.partition_file" },
#endif
{ Model::STARTTIME_KEY, "model.start" },
{ Model::STOPTIME_KEY, "model.stop" },
{ Model::RUNLENGTH_KEY, "model.run_length" },
{ Model::TIMESTEP_KEY, "model.time_step" },
{ Model::MISSINGVALUE_KEY, "model.missing_value" },
{ Model::RESTARTPERIOD_KEY, "model.restart_period" },
{ Model::RESTARTOUTFILE_KEY, "model.restart_file" },
};
Model::Model()
: iterator(modelStep)
{
#ifdef USE_MPI
std::string partitionFile
= Configured::getConfiguration(keyMap.at(PARTITIONFILE_KEY), std::string("partition.nc"));
auto& metadata = ModelMetadata::getInstance(partitionFile);
#else
auto& metadata = ModelMetadata::getInstance();
#endif
metadata.finalFileName = "restart" + TimePoint::ymdhmsFormat + ".nc";
}
Model::~Model() { }
void Model::configureRestarts()
{
// Ensure configureRestarts is only called once
if (configuredRestarts) {
return;
}
ModelMetadata& metadata = ModelMetadata::getInstance();
// Parse the initial restart file name and the pattern for output restart files
metadata.initialFileName
= Configured::getConfiguration(keyMap.at(RESTARTFILE_KEY), std::string());
metadata.finalFileName
= Configured::getConfiguration(keyMap.at(RESTARTOUTFILE_KEY), metadata.finalFileName);
// The period with which to write restart files.
std::string restartPeriodStr
= Configured::getConfiguration(keyMap.at(RESTARTPERIOD_KEY), std::string("0"));
metadata.restartPeriod = Duration(restartPeriodStr);
// Set global dimensions with an initial read of the input file
metadata.setDimensionsFromFile(metadata.initialFileName);
configuredRestarts = true;
}
void Model::configureTime()
{
// Ensure configureTime is only called once
if (configuredTime) {
return;
}
ModelMetadata& metadata = ModelMetadata::getInstance();
#ifdef USE_XIOS
// Enable XIOS in the config
std::stringstream config;
config << "[xios]" << std::endl << "enable = true" << std::endl;
Configurator::addStream(std::unique_ptr<std::istream>(new std::stringstream(config.str())));
#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());
configuredTime = true;
}
void Model::configure()
{
// Configure logging
Logged::configure();
// Configure the missing data value
MissingData::setValue(
Configured::getConfiguration(keyMap.at(MISSINGVALUE_KEY), MissingData::defaultValue));
configureRestarts();
// Configure parameters related to the temporal discretisation
configureTime();
// Configure prognostic data
pData.configure();
auto& metadata = ModelMetadata::getInstance();
modelStep.init();
modelStep.setInitFile(metadata.initialFileName);
// Read the initial state from file
ModelState initialState(StructureFactory::stateFromFile(metadata.initialFileName));
// Get the coordinates from the ModelState for persistence
metadata.extractCoordinates(initialState);
modelStep.setData(pData);
modelStep.setRestartDetails(metadata.restartPeriod, metadata.finalFileName);
pData.setData(initialState.data);
}
Model::HelpMap& Model::getHelpText(HelpMap& map, bool getAll)
{
map["Model"] = {
{ keyMap.at(STARTTIME_KEY), ConfigType::STRING, {}, "", "",
"Model start time, formatted as an ISO8601 date. "
"Non-calendretical runs can start from year 0 or 1. " },
{ keyMap.at(STOPTIME_KEY), ConfigType::STRING, {}, "", "",
"Model stop time, formatted as an ISO8601 date. "
" Will be overridden if a model run length is set. " },
{ keyMap.at(RUNLENGTH_KEY), ConfigType::STRING, {}, "", "",
"Model run length, formatted as an ISO8601 duration (P prefix) or an integer number of "
"seconds. "
"Overrides the stop time if set. " },
{ keyMap.at(TIMESTEP_KEY), ConfigType::STRING, {}, "", "",
"Model physics timestep, formatted as an ISO8601 duration (P prefix) or an integer "
"number of seconds. " },
{ keyMap.at(RESTARTFILE_KEY), ConfigType::STRING, {}, "", "",
"The file path to the initial restart file to be used for the run." },
{ keyMap.at(RESTARTPERIOD_KEY), ConfigType::STRING, {}, "0", "",
"The period between restart file outputs, formatted as an ISO8601 "
"duration (P prefix) or number of seconds. A value of zero "
"ensures no intermediate restart files are written." },
{ keyMap.at(RESTARTOUTFILE_KEY), ConfigType::STRING, {}, "restart%Y-%m-%dT%H:%M:%SZ.nc", "",
"The file name or file name pattern to be used for the output restart files. A fixed "
"name can be used, which will be overwritten every time a restart checkpoint is "
"created. Otherwise the file name may include formatting codes supported by the C/C++ "
"time library to create a new file at every restart checkpoint." },
{ keyMap.at(MISSINGVALUE_KEY), ConfigType::NUMERIC, { "-∞", "∞" }, "-2³⁰⁰", "",
"Missing data indicator used for input and output." },
#ifdef USE_MPI
{ keyMap.at(PARTITIONFILE_KEY), ConfigType::STRING, {}, "", "",
"The file path to the file describing MPI domain decomposition to use for the run." },
#endif
};
return map;
}
Model::HelpMap& Model::getHelpRecursive(HelpMap& map, bool getAll)
{
getHelpText(map, getAll);
PrognosticData::getHelpRecursive(map, getAll);
Module::getHelpRecursive<IDiagnosticOutput>(map, getAll);
#ifdef USE_XIOS
Xios::getHelpRecursive(map, getAll);
#endif
return map;
}
void Model::run()
{
Nextsim::ModelComponent::getStore().checkAllRegistered();
#ifdef USE_XIOS
Xios& xiosHandler = Xios::getInstance();
#endif
try {
iterator.run();
} catch (const std::exception& e) {
writeRestartFile();
#ifdef USE_XIOS
xiosHandler.context_finalize();
#endif
Finalizer::finalize();
throw;
}
writeRestartFile();
#ifdef USE_XIOS
xiosHandler.context_finalize();
#endif
Finalizer::finalize();
}
void Model::writeRestartFile()
{
auto& metadata = ModelMetadata::getInstance();
std::string formattedFileName = metadata.time().format(metadata.finalFileName);
pData.writeRestartFile(formattedFileName);
}
} /* namespace Nextsim */