Normalise input data in UDQ definitions

The UDQDefine::input_string() function will return normalized input which is
equivalent to the deck input string, but not necessarily identical. Normalizing
which might give rise to differences:

- All selectors/qualifiers in expressions like "WWCT '*'" are quoted.

- Whether to pad operators with space like "170 + FU_PAR10" or "170+FU_PAR10" is
  hardcoded and independent of the space used in the input.

- Floating point numbers is output with format "%g" - no trailing zeros.
This commit is contained in:
Joakim Hove 2021-07-25 16:24:47 +02:00
parent f17b75ab53
commit 7939adf3e3
7 changed files with 84 additions and 32 deletions

View File

@ -21,10 +21,11 @@
#ifndef UDQ_DEFINE_HPP
#define UDQ_DEFINE_HPP
#include <string>
#include <vector>
#include <optional>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQEnums.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQSet.hpp>
@ -101,7 +102,7 @@ private:
KeywordLocation m_location;
std::size_t m_report_step;
UDQUpdate m_update_status;
std::string string_data;
mutable std::optional<std::string> string_data;
};
}

View File

@ -187,6 +187,9 @@ namespace UDQ {
bool scalarFunc(UDQTokenType token_type);
bool cmpFunc(UDQTokenType token_type);
bool setFunc(UDQTokenType token_type);
bool trailingSpace(UDQTokenType token_type);
bool leadingSpace(UDQTokenType token_type);
std::string typeName(UDQVarType var_type);
UDAKeyword keyword(UDAControl control);

View File

@ -198,12 +198,6 @@ UDQDefine::UDQDefine(const UDQParams& udq_params,
}
this->m_tokens = make_tokens(string_tokens);
this->ast = std::make_shared<UDQASTNode>( UDQParser::parse(udq_params, this->m_var_type, this->m_keyword, this->m_location, this->m_tokens, parseContext, errors) );
this->string_data = "";
for (std::size_t index = 0; index < deck_data.size(); index++) {
this->string_data += deck_data[index];
if (index != deck_data.size() - 1)
this->string_data += " ";
}
}
void UDQDefine::update_status(UDQUpdate update, std::size_t report_step) {
@ -328,7 +322,33 @@ const std::string& UDQDefine::keyword() const {
}
const std::string& UDQDefine::input_string() const {
return this->string_data;
if (!this->string_data.has_value()) {
std::string s;
/*
A string representation equivalent to the input string is assembled by
joining tokens and sprinkle with ' ' at semi random locations. The
main use of this function is to output the definition string in form
usable for the restart file.
*/
for (std::size_t token_index = 0; token_index < this->m_tokens.size(); token_index++) {
const auto& token = this->m_tokens[token_index];
if (UDQ::leadingSpace(token.type()))
s += " ";
s += token.str();
if (token_index == (this->m_tokens.size() - 1))
continue;
if (UDQ::trailingSpace(token.type())) {
s += " ";
continue;
}
}
this->string_data = s;
}
return this->string_data.value();
}
std::set<UDQTokenType> UDQDefine::func_tokens() const {

View File

@ -372,6 +372,26 @@ std::string typeName(UDQVarType var_type) {
}
}
bool trailingSpace(UDQTokenType token_type) {
if (binaryFunc(token_type))
return true;
if (cmpFunc(token_type))
return true;
return false;
}
bool leadingSpace(UDQTokenType token_type) {
if (binaryFunc(token_type))
return true;
if (cmpFunc(token_type))
return true;
return false;
}
namespace {
template <typename Value>
Value lookup_control_map_value(const std::map<UDAControl, Value>& map, const UDAControl control)

View File

@ -16,12 +16,21 @@
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fmt/format.h>
#include <numeric>
#include <opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQToken.hpp>
namespace Opm {
namespace {
std::string format_double(double d) {
return fmt::format("{:g}", d);
}
}
UDQToken::UDQToken(const std::string& string_token, UDQTokenType token_type_) :
token_type(token_type_)
{
@ -56,10 +65,13 @@ std::string UDQToken::str() const {
if (this->m_selector.empty())
return std::get<std::string>(this->m_value);
return std::get<std::string>(this->m_value) + std::string{" "} + std::accumulate(this->m_selector.begin(), this->m_selector.end(), std::string{},
[](const std::string& s1, const std::string& s2) { return s1 + " " + s2; });
std::string quoted_selector;
for (const auto& s : this->m_selector)
quoted_selector += " '" + s + "'";
return std::get<std::string>(this->m_value) + quoted_selector;
} else
return std::to_string(std::get<double>(this->m_value));
return format_double(std::get<double>(this->m_value));
}

View File

@ -1272,10 +1272,10 @@ BOOST_AUTO_TEST_CASE(UDQPARSE_TEST1) {
KeywordLocation location;
UDQParams udqp;
UDQDefine def1(udqp, "WUBHP",0, location, {"1/(WWCT", "'W1*')"});
BOOST_CHECK_EQUAL( def1.input_string() , "1/(WWCT 'W1*')");
BOOST_CHECK_EQUAL( def1.input_string() , "1 / (WWCT 'W1*')");
UDQDefine def2(udqp, "WUBHP",0, location, {"2*(1", "+" , "WBHP)"});
BOOST_CHECK_EQUAL( def2.input_string() , "2*(1 + WBHP)");
UDQDefine def2(udqp, "WUBHP",0, location, {"2 * (1", "+" , "WBHP)"});
BOOST_CHECK_EQUAL( def2.input_string() , "2 * (1 + WBHP)");
}

View File

@ -646,22 +646,22 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data)
const auto& zUdl = udqData.getZUDL();
auto start = 0*udqDims[5];
BOOST_CHECK_EQUAL(zUdl[start + 0].c_str() , "(WOPR PR"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 1].c_str() , "OD1 - 17"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 2].c_str() , "0) * 0.6"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 3].c_str() , "0 "); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 0].c_str() , "(WOPR 'P"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 1].c_str() , "ROD1' - "); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 2].c_str() , "170) * 0"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 3].c_str() , ".6 "); // udq NO. 1
start = 3*udqDims[5];
BOOST_CHECK_EQUAL(zUdl[start + 0].c_str() , "(GOPR GR"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 1].c_str() , "P1 - 449"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 2].c_str() , ") * 0.77"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 3].c_str() , " "); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 0].c_str() , "(GOPR 'G"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 1].c_str() , "RP1' - 4"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 2].c_str() , "49) * 0."); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 3].c_str() , "77 "); // udq NO. 1
start = 4*udqDims[5];
BOOST_CHECK_EQUAL(zUdl[start + 0].c_str() , "(WLPR PR"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 1].c_str() , "OD2 - 30"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 2].c_str() , "0) * 0.8"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 3].c_str() , "0 "); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 0].c_str() , "(WLPR 'P"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 1].c_str() , "ROD2' - "); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 2].c_str() , "300) * 0"); // udq NO. 1
BOOST_CHECK_EQUAL(zUdl[start + 3].c_str() , ".8 "); // udq NO. 1
start = 5*udqDims[5];
BOOST_CHECK_EQUAL(zUdl[start + 0].c_str() , "(FLPR - "); // udq NO. 1
@ -761,9 +761,6 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data)
}
BOOST_CHECK_EQUAL(rst_state.udqs[0].expression(), "(WOPR PROD1 - 170) * 0.60");
const auto& udq_params = es.runspec().udqParams();
const auto& input_config = sched[1].udq();
Opm::UDQConfig rst_config(udq_params, rst_state);
@ -779,7 +776,6 @@ BOOST_AUTO_TEST_CASE (Declared_UDQ_data)
rst_udq_state.load_rst(rst_state);
for (const auto& input_def : input_config.definitions()) {
const auto& rst_def = rst_config.define( input_def.keyword() );
auto input_eval = input_def.eval(input_context);
auto rst_eval = rst_def.eval(rst_context);