-
Notifications
You must be signed in to change notification settings - Fork 22
Fixes and metadata changes to make ocean work with mtg2 keys #277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,8 +69,8 @@ message::Message Mask::createMasked(message::Message msg) const { | |
| } | ||
|
|
||
| message::Metadata& md = msg.modifyMetadata(); | ||
| md.set("missingValue", missingValue_); | ||
| md.set("bitmapPresent", true); | ||
| md.set("misc-missingValue", missingValue_); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This lines were only used by NEMO throug the IO server so far. As the metadata has changed in iom.F90, this metadata is now consistent with the other actions. |
||
| md.set("misc-bitmapPresent", true); | ||
|
|
||
| return msg; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -65,7 +65,7 @@ void SingleFieldSink::write(Message msg) { | |
|
|
||
|
|
||
| std::ostringstream oss; | ||
| oss << rootPath_ << msg.metadata().get<std::int64_t>("level") << "::" << paramOrId | ||
| oss << rootPath_ << msg.metadata().get<std::int64_t>("levelist") << "::" << paramOrId | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The key "level" is not used in mtg2 anymore. "levelist" is the appropriate mars key. |
||
| << "::" << msg.metadata().get<std::int64_t>("step"); | ||
| eckit::LocalConfiguration config; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -61,7 +61,8 @@ eckit::DateTime yyyymmdd_hhmmss2DateTime(uint64_t yyyymmdd, uint64_t hhmmss) { | |
|
|
||
| OperationWindow make_window(const std::unique_ptr<PeriodUpdater>& periodUpdater, const StatisticsConfiguration& cfg) { | ||
| // Note: A subtraction eckit::DateTime - eckit::Second yields eckit::Second instead of eckit::DateTime | ||
| // We do our calculations based on a difference since an arbitrary epoch (1st of January in the year 0) as a workarounds | ||
| // We do our calculations based on a difference since an arbitrary epoch (1st of January in the year 0) as a | ||
| // workarounds | ||
| eckit::DateTime epoch{eckit::Date{0000, 01, 01}, eckit::Time{00, 00, 00}}; | ||
| eckit::Second deltaCurr = cfg.curr() - epoch; | ||
| eckit::Second deltaStart = deltaCurr - eckit::Second{cfg.timespan().value_or(0) * 3600.0}; | ||
|
|
@@ -70,7 +71,8 @@ OperationWindow make_window(const std::unique_ptr<PeriodUpdater>& periodUpdater, | |
| eckit::DateTime startPoint{periodUpdater->computeWinStartTime(epoch + deltaStart)}; | ||
| eckit::DateTime creationPoint{periodUpdater->computeWinCreationTime(epoch + deltaStart)}; | ||
| eckit::DateTime endPoint{periodUpdater->computeWinEndTime(startPoint)}; | ||
| return OperationWindow{epochPoint, startPoint, creationPoint, endPoint, cfg.timeIncrementInSeconds(), cfg.options().windowType()}; | ||
| return OperationWindow{ | ||
| epochPoint, startPoint, creationPoint, endPoint, cfg.timeIncrementInSeconds(), cfg.options().windowType()}; | ||
| }; | ||
|
|
||
| OperationWindow load_window(std::shared_ptr<StatisticsIO>& IOmanager, const StatisticsOptions& opt) { | ||
|
|
@@ -195,21 +197,21 @@ bool OperationWindow::isWithin(const eckit::DateTime& dt) const { | |
| } | ||
|
|
||
| bool OperationWindow::gtLowerBound(const eckit::DateTime& dt, bool throw_error) const { | ||
| if (throw_error && creationPoint_ >= dt) { | ||
| if (throw_error && startPoint_ >= dt) { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These changes are important and correct. The window ranges from startPoint to endPoint. The creationPoint can be the same as startPoint, but is more likely just to be within the window. For ocean, no initial condition is send, after the first message arrives with time 1h. This was not passing through here. |
||
| std::ostringstream os; | ||
| os << *this << " : " << dt << " is outside of current period : lower Bound violation" << std::endl; | ||
| throw eckit::SeriousBug(os.str(), Here()); | ||
| } | ||
| return dt > creationPoint_; | ||
| return dt > startPoint_; | ||
| }; | ||
|
|
||
| bool OperationWindow::geLowerBound(const eckit::DateTime& dt, bool throw_error) const { | ||
| if (throw_error && creationPoint_ > dt) { | ||
| if (throw_error && startPoint_ > dt) { | ||
| std::ostringstream os; | ||
| os << *this << " : " << dt << " is outside of current period : lower Bound violation" << std::endl; | ||
| throw eckit::SeriousBug(os.str(), Here()); | ||
| } | ||
| return dt >= creationPoint_; | ||
| return dt >= startPoint_; | ||
| }; | ||
|
|
||
| bool OperationWindow::leUpperBound(const eckit::DateTime& dt, bool throw_error) const { | ||
|
|
@@ -463,7 +465,8 @@ void OperationWindow::serialize(IOBuffer& currState, const std::string& fname, c | |
| outFile << "timeIncrementInSeconds_ :: " << timeIncrementInSeconds_ << std::endl; | ||
| outFile << "count_ :: " << count_ << std::endl; | ||
| outFile << "counts_.size() :: " << counts_.size() << std::endl; | ||
| outFile << "windowType_ :: " << (windowType_ == WindowType::ForwardOffset ? "forward-offset" : "backward-offset") << std::endl; | ||
| outFile << "windowType_ :: " | ||
| << (windowType_ == WindowType::ForwardOffset ? "forward-offset" : "backward-offset") << std::endl; | ||
| outFile.close(); | ||
| } | ||
|
|
||
|
|
@@ -495,7 +498,7 @@ void OperationWindow::serialize(IOBuffer& currState, const std::string& fname, c | |
| const size_t countsSize = counts_.size(); | ||
| currState[17] = static_cast<std::uint64_t>(countsSize); | ||
| for (size_t i = 0; i < countsSize; ++i) { | ||
| currState[i+18] = static_cast<std::uint64_t>(counts_[i]); | ||
| currState[i + 18] = static_cast<std::uint64_t>(counts_[i]); | ||
| } | ||
|
|
||
| currState.computeChecksum(); | ||
|
|
@@ -520,7 +523,7 @@ void OperationWindow::deserialize(const IOBuffer& currState, const std::string& | |
| const auto countsSize = static_cast<size_t>(currState[17]); | ||
| counts_.resize(countsSize); | ||
| for (size_t i = 0; i < countsSize; ++i) { | ||
| counts_[i] = static_cast<long>(currState[i+18]); | ||
| counts_[i] = static_cast<long>(currState[i + 18]); | ||
| } | ||
|
|
||
| if (opt.debugRestart()) { | ||
|
|
@@ -535,7 +538,8 @@ void OperationWindow::deserialize(const IOBuffer& currState, const std::string& | |
| outFile << "timeIncrementInSeconds_ :: " << timeIncrementInSeconds_ << std::endl; | ||
| outFile << "count_ :: " << count_ << std::endl; | ||
| outFile << "counts_.size() :: " << counts_.size() << std::endl; | ||
| outFile << "windowType_ :: " << (windowType_ == WindowType::ForwardOffset ? "forward-offset" : "backward-offset") << std::endl; | ||
| outFile << "windowType_ :: " | ||
| << (windowType_ == WindowType::ForwardOffset ? "forward-offset" : "backward-offset") << std::endl; | ||
| outFile.close(); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -45,7 +45,8 @@ Statistics::Statistics(const ComponentConfiguration& compConf) : | |
| operationMapping_{StatisticsOperationMapping::makeStatisticsOperationMapping()}, | ||
| IOmanager_{StatisticsIOFactory::instance().build(opt_.restartLib(), opt_.restartPath(), opt_.restartPrefix())} {} | ||
|
|
||
| std::string Statistics::generateRestartNameFromFlush(const message::Message& msg, const FlushMetadataKeys& flush) const { | ||
| std::string Statistics::generateRestartNameFromFlush(const message::Message& msg, | ||
| const FlushMetadataKeys& flush) const { | ||
|
|
||
| std::string folderName; | ||
|
|
||
|
|
@@ -241,8 +242,6 @@ bool Statistics::HasRestartKey(const std::string& key) { | |
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
| void Statistics::updateLatestDateTime(const StatisticsConfiguration& cfg) { | ||
|
|
||
| std::ostringstream tmp; | ||
|
|
@@ -318,10 +317,10 @@ void Statistics::executeImpl(message::Message msg) { | |
| } | ||
|
|
||
| // The incomming message must occur AFTER the current point in the window! | ||
| if (cfg.curr() <= ts.cwin().currPoint()) { | ||
| if (cfg.curr() < ts.cwin().currPoint()) { | ||
|
Comment on lines
319
to
+320
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The window may be created such that The comments and the message still needs an update. |
||
| std::ostringstream os; | ||
| os << "Current time is before or equal to the current point in the window :: " << cfg.curr() << " > " | ||
| << ts.cwin().currPoint() << std::endl; | ||
| os << "Current time is before or equal to the current point in the window :: " << cfg.curr() | ||
| << " <= " << ts.cwin().currPoint() << ". Message: " << msg << std::endl; | ||
| throw eckit::SeriousBug(os.str(), Here()); | ||
| } | ||
|
|
||
|
|
@@ -331,6 +330,7 @@ void Statistics::executeImpl(message::Message msg) { | |
| ts.updateWindow(msg, cfg); | ||
| } | ||
|
|
||
|
|
||
| // Update data | ||
| ts.updateData(msg, cfg); | ||
|
|
||
|
|
@@ -412,7 +412,10 @@ void Statistics::emitStatistics(TemporalStatistics& ts, message::Peer source, me | |
| auto opname = (*it)->operation(); | ||
| if (opname != "instant") { | ||
| if (currentLoop == 1) { | ||
| const std::int64_t timespan = ts.win().currPointInHours() - ts.win().creationPointInHours(); | ||
| const std::int64_t timespan | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The probably less intuitive change - the time span computation depends whether the window is viewed from the starting point or the creation point. For monthly output, the decision is made to use the creation point - notably to explicitly avoid having "full" months if the forecast started in the middle of a month. For daily statistics the starting point is of interest, i.e. time 0000 of a day instead of 0100. |
||
| = ts.win().currPointInHours() | ||
| - ((ts.periodUpdater().timeUnit() == "month") ? ts.win().creationPointInHours() | ||
| : ts.win().startPointInHours()); | ||
| dm::dumpEntry(dm::TIMESPAN, dm::TIMESPAN.makeEntry(timespan), md); | ||
| paramMapping_.applyMapping(md, opname, !opt_.disableStrictMapping()); | ||
| } | ||
|
|
@@ -430,7 +433,9 @@ void Statistics::emitStatistics(TemporalStatistics& ts, message::Peer source, me | |
| Here()); | ||
| } | ||
| // Squash means we don't map (already done in previous loop), but extend the timespan | ||
| timespan.set(ts.win().currPointInHours() - ts.win().creationPointInHours()); | ||
| timespan.set(ts.win().currPointInHours() | ||
| - ((ts.periodUpdater().timeUnit() == "month") ? ts.win().creationPointInHours() | ||
| : ts.win().startPointInHours())); | ||
| dm::dumpEntry(dm::TIMESPAN, timespan, md); | ||
| } | ||
| else { | ||
|
|
@@ -460,29 +465,41 @@ void Statistics::emitStatistics(TemporalStatistics& ts, message::Peer source, me | |
|
|
||
| // For instant fields or on flushes, timespan is not set yet | ||
| if (!lengthOfWindow.isSet()) { | ||
| // The window spaws between creationPoint to endPoint | ||
| // The window spaws between startingPoint, creationPoint to endPoint. | ||
| // Prev & Current point describe the last updated data points. | ||
| // In this case we are explicitly interested in creation to current point | ||
| lengthOfWindow.set(ts.win().currPointInHours() - ts.win().creationPointInHours()); | ||
| // CreationPoint describes the time which the window is created - this can lay within a window (i.e. | ||
| // mid of a day, or month) whereas the startingPoint is explicitly the start of the window that can | ||
| // then at time 0 of a day or explicitly the first day of a month etc... | ||
| if (ts.periodUpdater().timeUnit() == "month") { | ||
| // For months we emit from the creation point - if a simulation is started in the mid, not the | ||
| // whole month should be considered. | ||
| lengthOfWindow.set(ts.win().currPointInHours() - ts.win().creationPointInHours()); | ||
| } | ||
| else { | ||
| // For days we emit from the starting point - if the initial condition is not send (i.e. for | ||
| // ocean), the window often starts at hour 1 instead of 0 In this case we explicitly want it to | ||
| // start at 0 although first data arrived at hour 1 | ||
| lengthOfWindow.set(ts.win().currPointInHours() - ts.win().startPointInHours()); | ||
| } | ||
| } | ||
|
|
||
| dm::dumpEntry(dm::STEP, dm::STEP.makeEntry(lengthOfWindow.get().toHours()), md); | ||
| // We explicitly take the creation point - alternative would be the start point. | ||
| // The start point may be different for the first window, i.e. if the simulation starts in the mid of a month. | ||
| // To not confuse the output, we explicitly just output the window for which data has been received. | ||
| // As discussed with DGOV and scientist, half months are typically not of interest and should be ignored. | ||
| // Some additional mechanism has to make sure that these do not occur in the output (i.e. additional action). | ||
| auto dt = ts.win().creationPoint(); | ||
| // We explicitly take the creation point for months and the start point for days (read comment above). | ||
| // The start point may be different for the first window, i.e. if the simulation starts in the mid of a | ||
| // month. To not confuse the output, we explicitly just output the window for which data has been | ||
| // received. As discussed with DGOV and scientist, half months are typically not of interest and should | ||
| // be ignored. Some additional mechanism has to make sure that these do not occur in the output (i.e. | ||
| // additional action). | ||
| auto dt = (ts.periodUpdater().timeUnit() == "month") ? ts.win().creationPoint() : ts.win().startPoint(); | ||
|
|
||
| dm::dumpEntry(dm::DATE, dm::DATE.makeEntry(dt.date().yyyymmdd()), md); | ||
| dm::dumpEntry(dm::TIME, dm::TIME.makeEntry(dt.time().hhmmss()), md); // Official MARS time is in hhmm, in multio hhmmss is used | ||
| dm::dumpEntry(dm::TIME, dm::TIME.makeEntry(dt.time().hhmmss()), | ||
| md); // Official MARS time is in hhmm, in multio hhmmss is used | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| for (const auto& kv : opt_.setMetadata()) { | ||
| md.set(kv.first, kv.second); | ||
| } | ||
| md.updateOverwrite(opt_.setMetadata()); | ||
|
|
||
| (*it)->compute(payload, cfg); | ||
| executeNext( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -41,6 +41,10 @@ TemporalStatistics::TemporalStatistics(std::shared_ptr<StatisticsIO>& IOmanager, | |
| LOG_DEBUG_LIB(LibMultio) << opt.logPrefix() << " *** Load restart files" << std::endl; | ||
| } | ||
|
|
||
| const PeriodUpdater& TemporalStatistics::periodUpdater() const { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Allow accessing the period updater to get information on the window size categorization. |
||
| return *periodUpdater_.get(); | ||
| } | ||
|
|
||
|
|
||
| void TemporalStatistics::dump(std::shared_ptr<StatisticsIO>& IOmanager, const StatisticsOptions& opt) const { | ||
| LOG_DEBUG_LIB(LibMultio) << opt.logPrefix() << " *** Dump restart files" << std::endl; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -138,18 +138,11 @@ std::optional<OutputTimeReference> parseOutputTimeRef(const eckit::LocalConfigur | |
| throw eckit::UserError(os.str(), Here()); | ||
| } | ||
|
|
||
| std::vector<std::pair<std::string, std::string>> parseSetMetadata(const eckit::LocalConfiguration& cfg) { | ||
| message::Metadata parseSetMetadata(const eckit::LocalConfiguration& cfg) { | ||
| if (!cfg.has("set-metadata")) { | ||
| return {}; | ||
| } | ||
|
|
||
| auto subCfg = cfg.getSubConfiguration("set-metadata"); | ||
| std::vector<std::pair<std::string, std::string>> res; | ||
| for (auto key : subCfg.keys()) { | ||
| auto value = subCfg.getString(key); | ||
| res.emplace_back(std::pair<std::string, std::string>(key, value)); | ||
| } | ||
| return res; | ||
| return message::toMetadata(cfg.getSubConfiguration("set-metadata")); | ||
| } | ||
|
|
||
|
|
||
|
|
@@ -214,7 +207,7 @@ bool StatisticsOptions::disableStrictMapping() const { | |
| bool StatisticsOptions::disableSquashing() const { | ||
| return disableSquashing_; | ||
| } | ||
| const std::vector<std::pair<std::string, std::string>>& StatisticsOptions::setMetadata() const { | ||
| const message::Metadata& StatisticsOptions::setMetadata() const { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changing from |
||
| return setMetadata_; | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,9 +33,7 @@ class HourPeriodUpdater final : public PeriodUpdater { | |
| }; | ||
|
|
||
| const std::string timeUnit() const { | ||
| std::ostringstream os; | ||
| os << "hour"; | ||
| return os.str(); | ||
| return "hour"; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Removing the ostringstream is obvious. Further refactorings should consider using a proper enum. |
||
| }; | ||
|
|
||
| eckit::DateTime computeWinStartTime(const eckit::DateTime& nextTime) const { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is also provided by a separate hotfix:
#275
Without that change, misc keys are not passed through.