Maintain insert order in UDQINput
This commit is contained in:
parent
2fb64e21d9
commit
11fe1d6e03
@ -29,19 +29,30 @@
|
||||
|
||||
namespace Opm {
|
||||
|
||||
|
||||
class UDQAssign{
|
||||
public:
|
||||
|
||||
/*
|
||||
If the same keyword is assigned several times the different assignment
|
||||
records are assembled in one UDQAssign instance. This is an attempt to
|
||||
support restart in a situation where a full UDQ ASSIGN statement can be
|
||||
swapped with a UDQ DEFINE statement.
|
||||
*/
|
||||
struct AssignRecord {
|
||||
std::vector<std::string> selector;
|
||||
double value;
|
||||
};
|
||||
|
||||
UDQAssign(const std::string& keyword, const std::vector<std::string>& selector, double value);
|
||||
const std::string& keyword() const;
|
||||
double value() const;
|
||||
UDQVarType var_type() const;
|
||||
const std::vector<std::string>& selector() const;
|
||||
void add_record(const std::vector<std::string>& selector, double value);
|
||||
UDQSet eval(const std::vector<std::string>& wells) const;
|
||||
private:
|
||||
std::string m_keyword;
|
||||
UDQVarType m_var_type;
|
||||
std::vector<std::string> m_selector;
|
||||
double m_value;
|
||||
std::vector<AssignRecord> records;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,8 @@ enum class UDQAction {
|
||||
ASSIGN,
|
||||
DEFINE,
|
||||
UNITS,
|
||||
UPDATE};
|
||||
UPDATE
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQParams.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunctionTable.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Util/OrderedMap.hpp>
|
||||
|
||||
|
||||
namespace Opm {
|
||||
@ -46,20 +47,60 @@ namespace Opm {
|
||||
void add_record(const DeckRecord& record);
|
||||
void assign_unit(const std::string& keyword, const std::string& unit);
|
||||
|
||||
const std::vector<UDQDefine>& definitions() const;
|
||||
std::vector<UDQDefine> definitions() const;
|
||||
std::vector<UDQDefine> definitions(UDQVarType var_type) const;
|
||||
|
||||
const std::vector<UDQAssign>& assignments() const;
|
||||
/*
|
||||
The input_definitions() function is written to supply the information
|
||||
needed when writing the restart file. The return value is a list of
|
||||
pairs, where the first element in the pair is the index in the deck
|
||||
for a particular UDQ keyword, and then the corresponding keyword.
|
||||
Assume a deck keyword which looks like this:
|
||||
|
||||
UDQ
|
||||
ASSIGN WUX 10 /
|
||||
UNITS WUX 'BARSA' /
|
||||
DEFINE WUPR SUM(WOPR) * 0.75 /
|
||||
DEFINE FUCK MAX(WOPR) * 1.25 /
|
||||
ASSIGN FUX 100 /
|
||||
DEFINE BUPR ?? /
|
||||
/
|
||||
|
||||
Then the return value from input_definitions() will be:
|
||||
|
||||
{{1, UDQDefine("WUPR")},
|
||||
{2, UDQDefine("FUCK")},
|
||||
{4, UDQDefine("BUPR")}
|
||||
|
||||
|
||||
Where the the numerical index is the index in a fictious vector
|
||||
consisting of only the ASSIGN and DEFINE keywords, in input order.
|
||||
*/
|
||||
std::vector<std::pair<size_t, UDQDefine>> input_definitions() const;
|
||||
|
||||
std::vector<UDQAssign> assignments() const;
|
||||
std::vector<UDQAssign> assignments(UDQVarType var_type) const;
|
||||
const UDQParams& params() const;
|
||||
const UDQFunctionTable& function_table() const;
|
||||
private:
|
||||
UDQParams udq_params;
|
||||
UDQFunctionTable udqft;
|
||||
std::vector<UDQDefine> m_definitions;
|
||||
std::vector<UDQAssign> m_assignments;
|
||||
|
||||
|
||||
/*
|
||||
The choices of datastructures are strongly motivated by the
|
||||
constraints imposed by the Eclipse formatted restart files; for
|
||||
writing restart files it is essential to keep meticolous control over
|
||||
the ordering of the keywords. In this class the ordering is mainly
|
||||
maintained by the input_index map which keeps track of the insert
|
||||
order of each keyword, and whether the keyword is currently DEFINE'ed
|
||||
or ASSIGN'ed.
|
||||
*/
|
||||
std::unordered_map<std::string, UDQDefine> m_definitions;
|
||||
std::unordered_map<std::string, UDQAssign> m_assignments;
|
||||
std::unordered_map<std::string, std::string> units;
|
||||
std::unordered_set<std::string> keywords;
|
||||
|
||||
OrderedMap<std::string, std::pair<size_t, UDQAction>> input_index;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -24,36 +24,35 @@ namespace Opm {
|
||||
|
||||
UDQAssign::UDQAssign(const std::string& keyword, const std::vector<std::string>& selector, double value) :
|
||||
m_keyword(keyword),
|
||||
m_var_type(UDQ::varType(keyword)),
|
||||
m_selector(selector),
|
||||
m_value(value)
|
||||
{}
|
||||
m_var_type(UDQ::varType(keyword))
|
||||
{
|
||||
this->add_record(selector, value);
|
||||
}
|
||||
|
||||
void UDQAssign::add_record(const std::vector<std::string>& selector, double value) {
|
||||
this->records.push_back({selector, value});
|
||||
}
|
||||
|
||||
const std::string& UDQAssign::keyword() const {
|
||||
return this->m_keyword;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& UDQAssign::selector() const {
|
||||
return this->m_selector;
|
||||
}
|
||||
|
||||
double UDQAssign::value() const {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
UDQVarType UDQAssign::var_type() const {
|
||||
return this->m_var_type;
|
||||
}
|
||||
|
||||
UDQSet UDQAssign::eval(const std::vector<std::string>& wells) const {
|
||||
if (this->m_var_type == UDQVarType::WELL_VAR) {
|
||||
UDQSet ws= UDQSet::wells(this->m_keyword, wells);
|
||||
UDQSet ws = UDQSet::wells(this->m_keyword, wells);
|
||||
|
||||
if (this->m_selector.empty())
|
||||
ws.assign(this->m_value);
|
||||
else
|
||||
ws.assign(this->m_selector[0], this->m_value);
|
||||
for (const auto& record : this->records) {
|
||||
const auto& selector = record.selector;
|
||||
double value = record.value;
|
||||
if (selector.empty())
|
||||
ws.assign(value);
|
||||
else
|
||||
ws.assign(selector[0], value);
|
||||
}
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
@ -45,57 +45,105 @@ namespace Opm {
|
||||
return this->udq_params;
|
||||
}
|
||||
|
||||
|
||||
void UDQInput::add_record(const DeckRecord& record) {
|
||||
auto action = UDQ::actionType(record.getItem("ACTION").get<std::string>(0));
|
||||
const auto& quantity = record.getItem("QUANTITY").get<std::string>(0);
|
||||
const auto& data = record.getItem("DATA").getData<std::string>();
|
||||
|
||||
if (action == UDQAction::UPDATE)
|
||||
throw std::invalid_argument("The UDQ action UPDATE is not yet implemented in opm/flow");
|
||||
|
||||
if (action == UDQAction::UNITS)
|
||||
this->assign_unit( quantity, data[0] );
|
||||
else if (action == UDQAction::ASSIGN) {
|
||||
std::vector<std::string> selector(data.begin(), data.end() - 1);
|
||||
double value = std::stod(data.back());
|
||||
this->m_assignments.emplace_back( quantity, selector, value );
|
||||
} else
|
||||
this->m_definitions.emplace_back(this->udq_params, quantity, data);
|
||||
this->keywords.insert(quantity);
|
||||
else {
|
||||
auto index_iter = this->input_index.find(quantity);
|
||||
if (this->input_index.find(quantity) == this->input_index.end())
|
||||
this->input_index[quantity] = std::make_pair(this->input_index.size(), action);
|
||||
else
|
||||
index_iter->second.second = action;
|
||||
|
||||
|
||||
if (action == UDQAction::ASSIGN) {
|
||||
std::vector<std::string> selector(data.begin(), data.end() - 1);
|
||||
double value = std::stod(data.back());
|
||||
auto assignment = this->m_assignments.find(quantity);
|
||||
if (assignment == this->m_assignments.end())
|
||||
this->m_assignments.insert( std::make_pair(quantity, UDQAssign(quantity, selector, value )));
|
||||
else
|
||||
assignment->second.add_record(selector, value);
|
||||
} else if (action == UDQAction::DEFINE)
|
||||
this->m_definitions.insert( std::make_pair(quantity, UDQDefine(this->udq_params, quantity, data)));
|
||||
else
|
||||
throw std::runtime_error("Internal error - should not be here");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const std::vector<UDQDefine>& UDQInput::definitions() const {
|
||||
return this->m_definitions;
|
||||
std::vector<UDQDefine> UDQInput::definitions() const {
|
||||
std::vector<UDQDefine> ret;
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
if (index_pair.second.second == UDQAction::DEFINE) {
|
||||
const std::string& key = index_pair.first;
|
||||
ret.push_back(this->m_definitions.at(key));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::vector<UDQDefine> UDQInput::definitions(UDQVarType var_type) const {
|
||||
std::vector<UDQDefine> filtered_defines;
|
||||
|
||||
std::copy_if(this->m_definitions.begin(),
|
||||
this->m_definitions.end(),
|
||||
std::back_inserter(filtered_defines),
|
||||
[&var_type](const UDQDefine& def) { return def.var_type() == var_type; });
|
||||
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
if (index_pair.second.second == UDQAction::DEFINE) {
|
||||
const std::string& key = index_pair.first;
|
||||
const auto& udq_define = this->m_definitions.at(key);
|
||||
if (udq_define.var_type() == var_type)
|
||||
filtered_defines.push_back(udq_define);
|
||||
}
|
||||
}
|
||||
return filtered_defines;
|
||||
}
|
||||
|
||||
|
||||
const std::vector<UDQAssign>& UDQInput::assignments() const {
|
||||
return this->m_assignments;
|
||||
std::vector<std::pair<size_t, UDQDefine>> UDQInput::input_definitions() const {
|
||||
std::vector<std::pair<size_t, UDQDefine>> res;
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
if (index_pair.second.second == UDQAction::DEFINE) {
|
||||
const std::string& key = index_pair.first;
|
||||
res.emplace_back(index_pair.second.first, this->m_definitions.at(key));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
std::vector<UDQAssign> UDQInput::assignments() const {
|
||||
std::vector<UDQAssign> ret;
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
if (index_pair.second.second == UDQAction::ASSIGN) {
|
||||
const std::string& key = index_pair.first;
|
||||
ret.push_back(this->m_assignments.at(key));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::vector<UDQAssign> UDQInput::assignments(UDQVarType var_type) const {
|
||||
std::vector<UDQAssign> filtered_assignments;
|
||||
|
||||
std::copy_if(this->m_assignments.begin(),
|
||||
this->m_assignments.end(),
|
||||
std::back_inserter(filtered_assignments),
|
||||
[&var_type](const UDQAssign& assignment) { return assignment.var_type() == var_type; });
|
||||
|
||||
return filtered_assignments;
|
||||
std::vector<UDQAssign> filtered_defines;
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
if (index_pair.second.second == UDQAction::ASSIGN) {
|
||||
const std::string& key = index_pair.first;
|
||||
const auto& udq_define = this->m_assignments.at(key);
|
||||
if (udq_define.var_type() == var_type)
|
||||
filtered_defines.push_back(udq_define);
|
||||
}
|
||||
}
|
||||
return filtered_defines;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::string& UDQInput::unit(const std::string& key) const {
|
||||
const auto pair_ptr = this->units.find(key);
|
||||
if (pair_ptr == this->units.end())
|
||||
@ -121,10 +169,25 @@ namespace Opm {
|
||||
return (this->units.count(keyword) > 0);
|
||||
}
|
||||
|
||||
|
||||
bool UDQInput::has_keyword(const std::string& keyword) const {
|
||||
return (this->keywords.count(keyword) > 0);
|
||||
if (this->m_assignments.count(keyword) > 0)
|
||||
return true;
|
||||
|
||||
if (this->m_definitions.count(keyword) > 0)
|
||||
return true;
|
||||
|
||||
/*
|
||||
That a keyword is mentioned with UNITS is enough to consider it
|
||||
as a keyword which is present.
|
||||
*/
|
||||
if (this->units.count(keyword) > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const UDQFunctionTable& UDQInput::function_table() const {
|
||||
return this->udqft;
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ Schedule make_schedule(const std::string& input) {
|
||||
return Schedule(deck, grid , eclipseProperties, runspec);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(MIX_SCALAR) {
|
||||
UDQFunctionTable udqft;
|
||||
UDQParams udqp;
|
||||
@ -276,7 +277,6 @@ BOOST_AUTO_TEST_CASE(ENUM_CONVERSION) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(UDQ_KEWYORDS) {
|
||||
const std::string input = R"(
|
||||
RUNSPEC
|
||||
@ -418,18 +418,18 @@ ASSIGN WU2 8.0 /
|
||||
const auto& assignments = udq.assignments();
|
||||
const auto& ass0 = assignments[0];
|
||||
const auto& ass1 = assignments[1];
|
||||
auto w1 = ass0.eval({"P1", "P2", "P12"});
|
||||
auto w2 = ass1.eval({"P1", "P2", "P12"});
|
||||
BOOST_CHECK_EQUAL(w1.name(), "WU1");
|
||||
BOOST_CHECK_EQUAL(w2.name(), "WU2");
|
||||
|
||||
BOOST_CHECK_EQUAL( w1["P12"].value(), 4.0 );
|
||||
BOOST_CHECK_EQUAL( w1["P1"].defined(), false );
|
||||
BOOST_CHECK_EQUAL( w1["P2"].defined(), false );
|
||||
|
||||
BOOST_CHECK_EQUAL(ass0.keyword(), "WU1");
|
||||
BOOST_CHECK_EQUAL(ass1.keyword(), "WU2");
|
||||
|
||||
BOOST_CHECK_EQUAL(ass0.value(), 4.0 );
|
||||
BOOST_CHECK_EQUAL(ass1.value(), 8.0 );
|
||||
|
||||
std::vector<std::string> sel0 = {"P12"};
|
||||
std::vector<std::string> sel1 = {};
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(ass0.selector().begin(), ass0.selector().end(), sel0.begin(), sel0.end());
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(ass1.selector().begin(), ass1.selector().end(), sel1.begin(), sel1.end());
|
||||
BOOST_CHECK_EQUAL( w2["P12"].value(), 8.0 );
|
||||
BOOST_CHECK_EQUAL( w2["P1"].value(), 8.0 );
|
||||
BOOST_CHECK_EQUAL( w2["P2"].value(), 8.0 );
|
||||
}
|
||||
|
||||
|
||||
@ -1144,3 +1144,87 @@ BOOST_AUTO_TEST_CASE(UDA_VALUE_DIM) {
|
||||
value0.set_dim( dim );
|
||||
BOOST_CHECK_EQUAL( value0.get<double>(), 10);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(UDQ_INPUT_BASIC) {
|
||||
std::string deck_string = R"(
|
||||
SCHEDULE
|
||||
|
||||
UDQ
|
||||
ASSIGN WUBHP1 11 /
|
||||
ASSIGN WUOPR 20 /
|
||||
ASSIGN WUBHP2 P2 12 /
|
||||
UNITS WUBHP 'BARSA' /
|
||||
UNITS WUOPR 'SM3/DAY' /
|
||||
DEFINE WUWCT WWPR / (WWPR + WOPR) /
|
||||
UNITS WUWCT '1' /
|
||||
DEFINE FUOPR SUM(WOPR) /
|
||||
UNITS FUOPR 'SM3/DAY' /
|
||||
UNITS FUXXX 'SM3/DAY' /
|
||||
/
|
||||
|
||||
UDQ
|
||||
ASSIGN WUBHPX P2 12 /
|
||||
DEFINE FUOPRX SUM(WOPR) /
|
||||
/
|
||||
|
||||
)";
|
||||
auto schedule = make_schedule(deck_string);
|
||||
const auto& udq = schedule.getUDQConfig(0);
|
||||
|
||||
|
||||
const auto& def_input = udq.input_definitions();
|
||||
const auto& def = udq.definitions();
|
||||
BOOST_CHECK_EQUAL(def_input.size(), 3);
|
||||
for (std::size_t i = 0; i < def_input.size(); i++)
|
||||
BOOST_CHECK_EQUAL(def[i].input_string(), def_input[i].second.input_string());
|
||||
|
||||
BOOST_CHECK_EQUAL(def_input[0].first, 3);
|
||||
BOOST_CHECK_EQUAL(def_input[1].first, 4);
|
||||
BOOST_CHECK_EQUAL(def_input[2].first, 6);
|
||||
|
||||
|
||||
BOOST_CHECK_EQUAL(def[0].keyword(), "WUWCT");
|
||||
BOOST_CHECK_EQUAL(def[1].keyword(), "FUOPR");
|
||||
BOOST_CHECK_EQUAL(def[2].keyword(), "FUOPRX");
|
||||
|
||||
BOOST_CHECK( udq.has_keyword("FUXXX") );
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(UDQ_INPUT_OVERWRITE) {
|
||||
std::string deck_string = R"(
|
||||
SCHEDULE
|
||||
|
||||
UDQ
|
||||
ASSIGN WUBHP1 11 /
|
||||
ASSIGN WUOPR 20 /
|
||||
ASSIGN WUBHP2 P2 12 /
|
||||
UNITS WUBHP 'BARSA' /
|
||||
UNITS WUOPR 'SM3/DAY' /
|
||||
DEFINE WUWCT WWPR / (WWPR + WOPR) /
|
||||
UNITS WUWCT '1' /
|
||||
DEFINE FUOPR SUM(WOPR) /
|
||||
UNITS FUOPR 'SM3/DAY' /
|
||||
/
|
||||
|
||||
UDQ
|
||||
DEFINE WUBHP1 SUM(WOPR) /
|
||||
/
|
||||
|
||||
)";
|
||||
auto schedule = make_schedule(deck_string);
|
||||
const auto& udq = schedule.getUDQConfig(0);
|
||||
|
||||
|
||||
const auto& def_input = udq.input_definitions();
|
||||
const auto& def = udq.definitions();
|
||||
BOOST_CHECK_EQUAL(def_input.size(), 3);
|
||||
for (std::size_t i = 0; i < def_input.size(); i++)
|
||||
BOOST_CHECK_EQUAL(def[i].input_string(), def_input[i].second.input_string());
|
||||
|
||||
BOOST_CHECK_EQUAL(def_input[0].first, 0);
|
||||
BOOST_CHECK_EQUAL(def_input[1].first, 3);
|
||||
BOOST_CHECK_EQUAL(def_input[2].first, 4);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user