Skip to content

Commit

Permalink
Generalise Restart Representation of UDQs
Browse files Browse the repository at this point in the history
This commit reimplements the RestartIO::RstUDQ type with a view
towards introducing support for restarting simulation runs
containing user defined quantities (UDQs) associated to the segments
of multi-segmented wells.  In particular, we replace the current
value container with a back-end based on the CSRGraphFromCoordinates
helper class.  This, in turn, enables supporting UDQ values at the
sub-entity level of a top-level entity such as the segments of a
multi-segmented well.

We more clearly distinguish the producing side--i.e., the layer
which loads information from a restart file--from the consuming
side--i.e., the client code which forms UDQConfig and UDQState
objects based on the restart file information, and require the
producing side to signal when the restart information has been fully
loaded.  To this end, the producing side is expected to

  1. Call member function prepareValues() to signal that new values
     are being loaded
  2. Call member function addValue(), typically in a loop, to
     include new UDQ values from the restart file
  3. Call member function commitValues() to signal that all values
     have been loaded.

As an alternative to step 2, the producing side may call member
function addScalarValue() if the quantity in question is
scalar--typically a field level UDQ.

The producing should also include any relevant entity names, usually
well or group names, by calling the addEntityName() member function.

The consuming side is expected to interact with the information
through operator[]() which returns a specialised ValueRange type
that supports forward iteration, for instance in a range-for() loop.

This new interface begets a significant update to the UDQAssign
class.  In particular, we no longer need the 'rst_selector' and
instead add new constructor and add_record interfaces which take a
RestartIO::RstUDQ object and a report step index.  The previous
interface based on the 'rst_selector' implicitly assumed that all
assignment statements applied a constant value to a collection of
wells or groups, but this assumption does not generally hold when we
load information from a restart file.  The new interface removes
this assumption.  While here, also make the AssignRecord into a
private data type since client code does not generally need to know
how we represent the assignment information.

Finally, add Doxygen-style documentation to the types

  * RestartIO::RstUDQ
  * UDQAssign
  * UDQConfig

While not much, this may help future maintainers understand the
relationships between these types a little better.
  • Loading branch information
bska committed Oct 9, 2024
1 parent 2e94d1e commit 381cbd6
Show file tree
Hide file tree
Showing 10 changed files with 2,014 additions and 655 deletions.
93 changes: 67 additions & 26 deletions opm/input/eclipse/Schedule/UDQ/UDQAssign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>

#include <opm/io/eclipse/rst/udq.hpp>

#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>

Expand All @@ -36,19 +38,13 @@ namespace Opm {
void UDQAssign::AssignRecord::eval(UDQSet& values) const
{
if (this->input_selector.empty() &&
this->rst_selector.empty() &&
this->numbered_selector.empty())
{
values.assign(this->value);
}
else if (! this->input_selector.empty()) {
values.assign(this->input_selector[0], this->value);
}
else if (! this->rst_selector.empty()) {
for (const auto& wgname : this->rst_selector) {
values.assign(wgname, this->value);
}
}
else {
for (const auto& item : this->numbered_selector) {
for (const auto& number : item.numbers) {
Expand All @@ -61,12 +57,13 @@ void UDQAssign::AssignRecord::eval(UDQSet& values) const
bool UDQAssign::AssignRecord::operator==(const AssignRecord& data) const
{
return (this->input_selector == data.input_selector)
&& (this->rst_selector == data.rst_selector)
&& (this->numbered_selector == data.numbered_selector)
&& (this->report_step == data.report_step)
&& (this->value == data.value);
}

// ---------------------------------------------------------------------------

UDQAssign::UDQAssign(const std::string& keyword,
const std::vector<std::string>& input_selector,
const double value,
Expand All @@ -77,16 +74,6 @@ UDQAssign::UDQAssign(const std::string& keyword,
this->add_record(input_selector, value, report_step);
}

UDQAssign::UDQAssign(const std::string& keyword,
const std::unordered_set<std::string>& rst_selector,
const double value,
const std::size_t report_step)
: m_keyword (keyword)
, m_var_type(UDQ::varType(keyword))
{
this->add_record(rst_selector, value, report_step);
}

UDQAssign::UDQAssign(const std::string& keyword,
const std::vector<UDQSet::EnumeratedItems>& selector,
double value,
Expand All @@ -107,15 +94,22 @@ UDQAssign::UDQAssign(const std::string& keyword,
this->add_record(std::move(selector), value, report_step);
}

UDQAssign::UDQAssign(const std::string& keyword,
const RestartIO::RstUDQ& assignRst,
const std::size_t report_step)
: m_keyword { keyword }
, m_var_type { assignRst.category }
{
this->add_record(assignRst, report_step);
}

UDQAssign UDQAssign::serializationTestObject()
{
UDQAssign result;
result.m_keyword = "test";
result.m_var_type = UDQVarType::CONNECTION_VAR;
result.records.emplace_back(std::vector<std::string>{"test1"}, 1.0, 0);

result.records.emplace_back(std::unordered_set<std::string>{ "I-45" }, 3.1415, 3);

// Class-template argument deduction for the vector element type.
result.records.emplace_back(std::vector { UDQSet::EnumeratedItems::serializationTestObject() }, 2.71828, 42);

Expand All @@ -129,13 +123,6 @@ void UDQAssign::add_record(const std::vector<std::string>& input_selector,
this->records.emplace_back(input_selector, value, report_step);
}

void UDQAssign::add_record(const std::unordered_set<std::string>& rst_selector,
const double value,
const std::size_t report_step)
{
this->records.emplace_back(rst_selector, value, report_step);
}

void UDQAssign::add_record(const std::vector<UDQSet::EnumeratedItems>& selector,
const double value,
const std::size_t report_step)
Expand All @@ -150,6 +137,34 @@ void UDQAssign::add_record(std::vector<UDQSet::EnumeratedItems>&& selector,
this->records.emplace_back(std::move(selector), value, report_step);
}

void UDQAssign::add_record(const RestartIO::RstUDQ& assignRst,
const std::size_t report_step)
{
if (assignRst.name != this->m_keyword) {
throw std::invalid_argument {
fmt::format("ASSIGN UDQ '{}' must not attempt to include "
"information for unrelated UDQ '{}' from restart file.",
this->m_keyword, assignRst.name)
};
}

switch (assignRst.category) {
case UDQVarType::SCALAR:
case UDQVarType::FIELD_VAR:
this->add_record(assignRst.entityNames(),
assignRst.scalarValue(), report_step);
break;

case UDQVarType::WELL_VAR:
case UDQVarType::GROUP_VAR:
this->add_well_or_group_records(assignRst, report_step);
break;

default:
break;
}
}

const std::string& UDQAssign::keyword() const
{
return this->m_keyword;
Expand Down Expand Up @@ -225,4 +240,30 @@ bool UDQAssign::operator==(const UDQAssign& data) const
&& (this->records == data.records);
}

// ---------------------------------------------------------------------------
// Private member functions below separator
// ---------------------------------------------------------------------------

void UDQAssign::add_well_or_group_records(const RestartIO::RstUDQ& assignRst,
const std::size_t report_step)
{
const auto& wgnames = assignRst.entityNames();
const auto& nameIdx = assignRst.nameIndex();
const auto n = assignRst.numEntities();

// Note: We intentionally allocate a single selector string and reuse
// that for every add_record() call. The loop here guarantees that we
// handle the case of different values for well or group, albeit at the
// cost of the 'records' data member being larger than necessary if all
// entities do have the same value.
auto selector = std::vector<std::string>(1);

for (auto i = 0*n; i < n; ++i) {
for (const auto& subValuePair : assignRst[i]) {
selector.front() = wgnames[nameIdx[i]];
this->add_record(selector, subValuePair.second, report_step);
}
}
}

} // namespace Opm
Loading

0 comments on commit 381cbd6

Please sign in to comment.