Merge pull request #3220 from bska/reduce-astnode-eval-nesting

Reduce Level of Nesting in UDQASTNode::eval
This commit is contained in:
Markus Blatt 2022-11-22 22:35:03 +01:00 committed by GitHub
commit 0624a04613
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1683 additions and 1167 deletions

View File

@ -20,6 +20,10 @@
#ifndef UDQASTNODE_HPP #ifndef UDQASTNODE_HPP
#define UDQASTNODE_HPP #define UDQASTNODE_HPP
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <memory> #include <memory>
#include <set> #include <set>
#include <string> #include <string>
@ -27,16 +31,13 @@
#include <variant> #include <variant>
#include <vector> #include <vector>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
namespace Opm { namespace Opm {
class UDQASTNode { class UDQASTNode
{
public: public:
UDQVarType var_type = UDQVarType::NONE;
UDQASTNode(); UDQASTNode();
explicit UDQASTNode(UDQTokenType type_arg); explicit UDQASTNode(UDQTokenType type_arg);
explicit UDQASTNode(double scalar_value); explicit UDQASTNode(double scalar_value);
@ -48,21 +49,20 @@ public:
static UDQASTNode serializationTestObject(); static UDQASTNode serializationTestObject();
UDQSet eval(UDQVarType eval_target, const UDQContext& context) const; UDQSet eval(UDQVarType eval_target, const UDQContext& context) const;
bool valid() const; bool valid() const;
UDQVarType var_type = UDQVarType::NONE;
std::set<UDQTokenType> func_tokens() const; std::set<UDQTokenType> func_tokens() const;
void update_type(const UDQASTNode& arg); void update_type(const UDQASTNode& arg);
void set_left(const UDQASTNode& arg); void set_left(const UDQASTNode& arg);
void set_right(const UDQASTNode& arg); void set_right(const UDQASTNode& arg);
UDQASTNode* get_left() const;
UDQASTNode* get_right() const;
void scale(double sign_factor); void scale(double sign_factor);
UDQASTNode* get_left() const;
UDQASTNode* get_right() const;
bool operator==(const UDQASTNode& data) const; bool operator==(const UDQASTNode& data) const;
void required_summary(std::unordered_set<std::string>& summary_keys) const; void required_summary(std::unordered_set<std::string>& summary_keys) const;
template<class Serializer> template <class Serializer>
void serializeOp(Serializer& serializer) void serializeOp(Serializer& serializer)
{ {
serializer(var_type); serializer(var_type);
@ -76,13 +76,34 @@ public:
private: private:
UDQTokenType type; UDQTokenType type;
void func_tokens(std::set<UDQTokenType>& tokens) const;
std::variant<std::string, double> value; std::variant<std::string, double> value;
double sign = 1.0; double sign = 1.0;
std::vector<std::string> selector; std::vector<std::string> selector;
std::shared_ptr<UDQASTNode> left; std::shared_ptr<UDQASTNode> left;
std::shared_ptr<UDQASTNode> right; std::shared_ptr<UDQASTNode> right;
UDQSet eval_expression(const UDQContext& context) const;
UDQSet eval_well_expression(const std::string& string_value,
const UDQContext& context) const;
UDQSet eval_group_expression(const std::string& string_value,
const UDQContext& context) const;
UDQSet eval_scalar_function(const UDQVarType target_type,
const UDQContext& context) const;
UDQSet eval_elemental_unary_function(const UDQVarType target_type,
const UDQContext& context) const;
UDQSet eval_binary_function(const UDQVarType target_type,
const UDQContext& context) const;
UDQSet eval_number(const UDQVarType target_type,
const UDQContext& context) const;
void func_tokens(std::set<UDQTokenType>& tokens) const;
}; };
UDQASTNode operator*(const UDQASTNode&lhs, double rhs); UDQASTNode operator*(const UDQASTNode&lhs, double rhs);

View File

@ -20,20 +20,22 @@
#ifndef UDQINPUT_HPP_ #ifndef UDQINPUT_HPP_
#define UDQINPUT_HPP_ #define UDQINPUT_HPP_
#include <string>
#include <unordered_map>
#include <map>
#include <unordered_set>
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
#include <opm/input/eclipse/EclipseState/Util/OrderedMap.hpp> #include <opm/input/eclipse/EclipseState/Util/OrderedMap.hpp>
#include <opm/input/eclipse/EclipseState/Util/IOrderSet.hpp> #include <opm/input/eclipse/EclipseState/Util/IOrderSet.hpp>
#include <cstddef>
#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace Opm { namespace Opm {
@ -43,12 +45,16 @@ namespace Opm {
class KeywordLocation; class KeywordLocation;
class WellMatcher; class WellMatcher;
namespace RestartIO { } // namespace Opm
struct RstState;
}
namespace Opm { namespace RestartIO {
struct RstState;
}} // namespace Opm::RestartIO
class UDQConfig { namespace Opm {
class UDQConfig
{
public: public:
UDQConfig() = default; UDQConfig() = default;
explicit UDQConfig(const UDQParams& params); explicit UDQConfig(const UDQParams& params);
@ -91,7 +97,6 @@ namespace Opm {
bool operator==(const UDQConfig& config) const; bool operator==(const UDQConfig& config) const;
void required_summary(std::unordered_set<std::string>& summary_keys) const; void required_summary(std::unordered_set<std::string>& summary_keys) const;
template<class Serializer> template<class Serializer>
void serializeOp(Serializer& serializer) void serializeOp(Serializer& serializer)
{ {
@ -113,20 +118,16 @@ namespace Opm {
void eval_assign(std::size_t report_step, SummaryState& st, UDQState& udq_state, UDQContext& context) const; void eval_assign(std::size_t report_step, SummaryState& st, UDQState& udq_state, UDQContext& context) const;
void eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const; void eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const;
UDQParams udq_params; UDQParams udq_params;
UDQFunctionTable udqft; UDQFunctionTable udqft;
// The choices of data structures are strongly motivated by the
/* // constraints imposed by the ECLIPSE formatted restart files; for
The choices of datastructures are strongly motivated by the // writing restart files it is essential to keep meticulous control
constraints imposed by the Eclipse formatted restart files; for // over the ordering of the keywords. In this class the ordering is
writing restart files it is essential to keep meticolous control over // mainly maintained by the input_index map which keeps track of the
the ordering of the keywords. In this class the ordering is mainly // insert order of each keyword, and whether the keyword is
maintained by the input_index map which keeps track of the insert // currently DEFINE'ed or ASSIGN'ed.
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, UDQDefine> m_definitions;
std::unordered_map<std::string, UDQAssign> m_assignments; std::unordered_map<std::string, UDQAssign> m_assignments;
std::unordered_map<std::string, std::string> units; std::unordered_map<std::string, std::string> units;

View File

@ -17,30 +17,38 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef UDQ_DEFINE_HPP #ifndef UDQ_DEFINE_HPP
#define UDQ_DEFINE_HPP #define UDQ_DEFINE_HPP
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <cstddef>
#include <memory>
#include <optional> #include <optional>
#include <set> #include <set>
#include <string> #include <string>
#include <unordered_set> #include <unordered_set>
#include <utility>
#include <vector> #include <vector>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
namespace Opm { namespace Opm {
class UDQASTNode; class UDQASTNode;
class ParseContext; class ParseContext;
class ErrorGuard; class ErrorGuard;
class UDQDefine{ } // Namespace Opm
namespace Opm {
class UDQDefine
{
public: public:
UDQDefine(); UDQDefine();
@ -73,7 +81,7 @@ public:
const std::string& keyword() const; const std::string& keyword() const;
const std::string& input_string() const; const std::string& input_string() const;
const KeywordLocation& location() const; const KeywordLocation& location() const;
UDQVarType var_type() const; UDQVarType var_type() const;
std::set<UDQTokenType> func_tokens() const; std::set<UDQTokenType> func_tokens() const;
void required_summary(std::unordered_set<std::string>& summary_keys) const; void required_summary(std::unordered_set<std::string>& summary_keys) const;
void update_status(UDQUpdate update_status, std::size_t report_step); void update_status(UDQUpdate update_status, std::size_t report_step);
@ -82,7 +90,7 @@ public:
bool operator==(const UDQDefine& data) const; bool operator==(const UDQDefine& data) const;
template<class Serializer> template <class Serializer>
void serializeOp(Serializer& serializer) void serializeOp(Serializer& serializer)
{ {
serializer(m_keyword); serializer(m_keyword);
@ -104,8 +112,7 @@ private:
UDQUpdate m_update_status; UDQUpdate m_update_status;
mutable std::optional<std::string> string_data; mutable std::optional<std::string> string_data;
}; };
}
} // Namespace Opm
#endif // UDQ_DEFINE_HPP
#endif

View File

@ -25,40 +25,41 @@
namespace Opm { namespace Opm {
/* // The UDQ variables can be of many different types. Additionally they can
The UDQ variables can be of of many different types. In addition they can be // be either scalars or vector sets. The archetypal example of a vector set
either scalars or vector sets. The arch example of a vector set is well // is well variables. For instance, in the expressions:
variables - in the expressions: //
// UDQ
// DEFINE WUBHP WBHP * 1.15 /
// DEFINE WUORAT 1000 /
// /
//
// we define two UDQ values 'WUBHP' and 'WUORAT'. Both of these UDQ values
// will apply to all wells; the WUBHP vector will correspond to the normal
// BHP scaled up 15%, the WUORAT has the scalar value 1000 for all wells.
// The well sets can be constrained with a well name. If the well name is a
// template, we get a well set. Otherwise, i.e., if the well name is fully
// qualified we have a scalar:
//
// UDQ
// DEFINE WUWCT WWCT 'OP*' /
// DEFINE FUORAT WOPR 'OPX' * 100 /
// /
//
// Here the UDQ WUCWT corresponds to the well WWCT for all wells matching
// the template 'OP*', and it is undefined for other wells. The UDQ FUORAT
// is a scalar, given by the WOPR of well 'OPX' - multiplied by 100.
//
// There are clearly rules for how the different variable types can be
// combined in expressions, and what will be resulting type from an
// expression - unfortunately that is not yet very well implemented in the
// opm codebase. In UDQParser.cpp there is a function static_type_check and
// in UDQDefine there is a function dynamic_type_check - these functions try
// to verfiy that the type conversions are legitimate, but currently they
// are woefully inadequate.
UDQ enum class UDQVarType
DEFINE WUBHP WBHP * 1.15 / {
DEFINE WUORAT 1000 /
/
we define two UDQ values 'WUBHP' and 'WUORAT'. Both of these UDQ values will
apply to all wells; the WUBHP vector will correspond to the normal BHP scaled
up 15%, the WUORAT has the scalar value 1000 for all the wells. The well sets
can be qualified with a wellname, if the wellname has a wildcard we will get a
well set, if the wellname is fully qualified we have a scalar:
UDQ
DEFINE WUWCT WWCT 'OP*' /
DEFINE FUORAT WOPR 'OPX' * 100 /
/
Here the UDQ WUCWT corresponds to the well WWCT for all wells matching the
name 'OP*', and it is undefined for the remaing wells. The UDQ FUORAT is a
scalar, given by the WOPR of well 'OPX' - multiplied by 100.
There are clearly rules for how the different variable types can be combined
in expressions, and what will be resulting type from an expression -
unfortunately that is not yet very well implemented in the opm codebase. In
UDQParser.cpp there is a function static_type_check and in UDQDefine there is
a function dynamic_type_check - these functions try to verfiy that the type
conversions are legitimate, but currently they are woefully inadequate.
*/
enum class UDQVarType {
NONE = 0, NONE = 0,
SCALAR = 1, SCALAR = 1,
CONNECTION_VAR = 2, CONNECTION_VAR = 2,
@ -68,10 +69,11 @@ enum class UDQVarType {
AQUIFER_VAR = 6, AQUIFER_VAR = 6,
BLOCK_VAR = 7, BLOCK_VAR = 7,
WELL_VAR = 8, WELL_VAR = 8,
GROUP_VAR = 9 GROUP_VAR = 9,
}; };
enum class UDQTokenType{ enum class UDQTokenType
{
error = 0, error = 0,
number = 1, number = 1,
open_paren = 2, open_paren = 2,
@ -123,23 +125,26 @@ enum class UDQTokenType{
// //
table_lookup = 47, table_lookup = 47,
// //
end = 100 end = 100,
}; };
enum class UDQAction { enum class UDQAction
{
ASSIGN, ASSIGN,
DEFINE, DEFINE,
UNITS, UNITS,
UPDATE UPDATE,
}; };
enum class UDQUpdate { enum class UDQUpdate
{
ON, ON,
OFF, OFF,
NEXT NEXT,
}; };
enum class UDAControl { enum class UDAControl
{
WCONPROD_ORAT, WCONPROD_ORAT,
WCONPROD_WRAT, WCONPROD_WRAT,
WCONPROD_GRAT, WCONPROD_GRAT,
@ -173,7 +178,8 @@ enum class UDAControl {
WELTARG_LIFT, WELTARG_LIFT,
}; };
enum class UDAKeyword { enum class UDAKeyword
{
WCONPROD, WCONPROD,
WCONINJE, WCONINJE,
WELTARG, WELTARG,
@ -187,11 +193,15 @@ namespace UDQ {
UDQVarType targetType(const std::string& keyword); UDQVarType targetType(const std::string& keyword);
UDQVarType varType(const std::string& keyword); UDQVarType varType(const std::string& keyword);
UDQVarType coerce(UDQVarType t1, UDQVarType t2); UDQVarType coerce(UDQVarType t1, UDQVarType t2);
UDQAction actionType(const std::string& action_string); UDQAction actionType(const std::string& action_string);
UDQUpdate updateType(const std::string& update_string); UDQUpdate updateType(const std::string& update_string);
UDQUpdate updateType(int int_value); UDQUpdate updateType(int int_value);
UDQTokenType tokenType(const std::string& func_name); UDQTokenType tokenType(const std::string& func_name);
UDQTokenType funcType(const std::string& func_name); UDQTokenType funcType(const std::string& func_name);
bool binaryFunc(UDQTokenType token_type); bool binaryFunc(UDQTokenType token_type);
bool elementalUnaryFunc(UDQTokenType token_type); bool elementalUnaryFunc(UDQTokenType token_type);
bool scalarFunc(UDQTokenType token_type); bool scalarFunc(UDQTokenType token_type);
@ -208,12 +218,15 @@ namespace UDQ {
std::string typeName(UDQVarType var_type); std::string typeName(UDQVarType var_type);
std::string controlName(UDAControl control); std::string controlName(UDAControl control);
UDAKeyword keyword(UDAControl control); UDAKeyword keyword(UDAControl control);
int udaCode(UDAControl control); int udaCode(UDAControl control);
UDAControl udaControl(int uda_code); UDAControl udaControl(int uda_code);
constexpr double restart_default = -0.3E+21; constexpr double restart_default = -0.3E+21;
} // UDQ
} // Opm
#endif // UDQ_ENUMS_HPP } // namespace UDQ
} // namespace Opm
#endif // UDQ_ENUMS_HPP

View File

@ -17,32 +17,33 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef UDQINPUT__HPP_ #ifndef UDQINPUT__HPP_
#define UDQINPUT__HPP_ #define UDQINPUT__HPP_
#include <variant>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <cstddef>
#include <string>
#include <variant>
namespace Opm { namespace Opm {
class UDQAssign; class UDQIndex
class UDQDefine; {
class UDQIndex {
public: public:
UDQIndex() = default; UDQIndex() = default;
UDQIndex(std::size_t insert_index_arg, std::size_t typed_insert_index_arg, UDQAction action_arg, UDQVarType var_type_arg) : UDQIndex(const std::size_t insert_index_arg,
insert_index(insert_index_arg), const std::size_t typed_insert_index_arg,
typed_insert_index(typed_insert_index_arg), const UDQAction action_arg,
action(action_arg), const UDQVarType var_type_arg)
var_type(var_type_arg) : insert_index (insert_index_arg)
{ , typed_insert_index(typed_insert_index_arg)
} , action (action_arg)
, var_type (var_type_arg)
{}
static UDQIndex serializationTestObject() static UDQIndex serializationTestObject()
{ {
@ -55,14 +56,16 @@ public:
return result; return result;
} }
bool operator==(const UDQIndex& data) const { bool operator==(const UDQIndex& data) const
return insert_index == data.insert_index && {
typed_insert_index == data.typed_insert_index && return (insert_index == data.insert_index)
action == data.action && && (typed_insert_index == data.typed_insert_index)
var_type == data.var_type; && (action == data.action)
&& (var_type == data.var_type)
;
} }
template<class Serializer> template <class Serializer>
void serializeOp(Serializer& serializer) void serializeOp(Serializer& serializer)
{ {
serializer(insert_index); serializer(insert_index);
@ -77,16 +80,16 @@ public:
UDQVarType var_type; UDQVarType var_type;
}; };
class UDQInput
class UDQInput{ {
public: public:
UDQInput(const UDQIndex& index, const UDQDefine& udq_define, const std::string& unit); UDQInput(const UDQIndex& index, const UDQDefine& udq_define, const std::string& unit);
UDQInput(const UDQIndex& index, const UDQAssign& udq_assign, const std::string& unit); UDQInput(const UDQIndex& index, const UDQAssign& udq_assign, const std::string& unit);
template<typename T> template <typename T>
const T& get() const; const T& get() const;
template<typename T> template <typename T>
bool is() const; bool is() const;
const std::string& keyword() const; const std::string& keyword() const;
@ -95,14 +98,14 @@ public:
const UDQIndex index; const UDQIndex index;
bool operator==(const UDQInput& other) const; bool operator==(const UDQInput& other) const;
private: private:
std::variant<UDQDefine, UDQAssign> value; std::variant<UDQDefine, UDQAssign> value;
const std::string m_keyword; std::string m_keyword;
UDQVarType m_var_type; UDQVarType m_var_type;
const std::string m_unit; std::string m_unit;
}; };
}
} // namespace Opm
#endif // UDQINPUT__HPP_
#endif

View File

@ -20,17 +20,19 @@
#ifndef UDQSET_HPP #ifndef UDQSET_HPP
#define UDQSET_HPP #define UDQSET_HPP
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <cstddef>
#include <optional> #include <optional>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
namespace Opm { namespace Opm {
class UDQScalar { class UDQScalar
{
public: public:
UDQScalar() = default; UDQScalar() = default;
explicit UDQScalar(double value); explicit UDQScalar(double value);
@ -60,12 +62,14 @@ public:
}; };
class UDQSet { class UDQSet
{
public: public:
UDQSet(const std::string& name, UDQVarType var_type); UDQSet(const std::string& name, UDQVarType var_type);
UDQSet(const std::string& name, UDQVarType var_type, const std::vector<std::string>& wgnames); UDQSet(const std::string& name, UDQVarType var_type, const std::vector<std::string>& wgnames);
UDQSet(const std::string& name, UDQVarType var_type, std::size_t size); UDQSet(const std::string& name, UDQVarType var_type, std::size_t size);
UDQSet(const std::string& name, std::size_t size); UDQSet(const std::string& name, std::size_t size);
static UDQSet scalar(const std::string& name, const std::optional<double>& scalar_value); static UDQSet scalar(const std::string& name, const std::optional<double>& scalar_value);
static UDQSet scalar(const std::string& name, double value); static UDQSet scalar(const std::string& name, double value);
static UDQSet empty(const std::string& name); static UDQSet empty(const std::string& name);
@ -84,6 +88,7 @@ public:
bool has(const std::string& name) const; bool has(const std::string& name) const;
std::size_t size() const; std::size_t size() const;
void operator+=(const UDQSet& rhs); void operator+=(const UDQSet& rhs);
void operator+=(double rhs); void operator+=(double rhs);
void operator-=(const UDQSet& rhs); void operator-=(const UDQSet& rhs);
@ -105,6 +110,7 @@ public:
void name(const std::string& name); void name(const std::string& name);
UDQVarType var_type() const; UDQVarType var_type() const;
bool operator==(const UDQSet& other) const; bool operator==(const UDQSet& other) const;
private: private:
UDQSet() = default; UDQSet() = default;

View File

@ -16,91 +16,131 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunction.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQFunction.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
namespace Opm {
UDQASTNode::UDQASTNode() :
UDQASTNode(UDQTokenType::error)
{}
UDQASTNode::UDQASTNode(UDQTokenType type_arg) :
var_type(UDQVarType::NONE),
type(type_arg)
{
if (type == UDQTokenType::error)
return;
if (type == UDQTokenType::binary_op_add)
return;
if (type == UDQTokenType::binary_op_sub)
return;
throw std::invalid_argument("The one argument constructor is only available for error and end");
}
#include <memory>
#include <set>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_set>
#include <variant>
#include <vector>
namespace { namespace {
UDQVarType init_type(UDQTokenType token_type) bool is_udq(const std::string& key)
{ {
if (token_type == UDQTokenType::number) return (key.size() >= std::string::size_type{2})
return UDQVarType::SCALAR; && (key[1] == 'U');
if (UDQ::scalarFunc(token_type))
return UDQVarType::SCALAR;
return UDQVarType::NONE;
} }
Opm::UDQVarType init_type(const Opm::UDQTokenType token_type)
{
if (token_type == Opm::UDQTokenType::number) {
return Opm::UDQVarType::SCALAR;
}
if (Opm::UDQ::scalarFunc(token_type)) {
return Opm::UDQVarType::SCALAR;
}
return Opm::UDQVarType::NONE;
} }
} // Anonymous namespace
UDQASTNode::UDQASTNode(double numeric_value) : namespace Opm {
var_type(init_type(UDQTokenType::number)),
type(UDQTokenType::number), UDQASTNode::UDQASTNode()
value(numeric_value) : UDQASTNode(UDQTokenType::error)
{} {}
UDQASTNode::UDQASTNode(const UDQTokenType type_arg)
UDQASTNode::UDQASTNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg) : : var_type(UDQVarType::NONE)
var_type(init_type(type_arg)), , type (type_arg)
type(type_arg),
value(value_arg)
{ {
if ((this->type == UDQTokenType::error) ||
(this->type == UDQTokenType::binary_op_add) ||
(this->type == UDQTokenType::binary_op_sub))
{
return;
}
throw std::invalid_argument {
"Single argument AST node constructor available only "
"for error and binary addition/subtraction tokens"
};
} }
UDQASTNode::UDQASTNode(double numeric_value)
: var_type(init_type(UDQTokenType::number))
, type (UDQTokenType::number)
, value (numeric_value)
{}
UDQASTNode::UDQASTNode(UDQTokenType type_arg, UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg)
: var_type(init_type(type_arg))
, type (type_arg)
, value (value_arg)
{}
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg, const std::variant<std::string, double>& value_arg,
const UDQASTNode& left_arg) const UDQASTNode& left_arg)
: UDQASTNode(type_arg, value_arg) : UDQASTNode(type_arg, value_arg)
{ {
if (UDQ::scalarFunc(type_arg)) if (UDQ::scalarFunc(type_arg)) {
this->var_type = UDQVarType::SCALAR; this->var_type = UDQVarType::SCALAR;
else }
else {
this->var_type = left_arg.var_type; this->var_type = left_arg.var_type;
}
this->left = std::make_unique<UDQASTNode>(left_arg); this->left = std::make_unique<UDQASTNode>(left_arg);
} }
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
UDQASTNode::UDQASTNode(UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg, const std::variant<std::string, double>& value_arg,
const UDQASTNode& left_arg, const UDQASTNode& left_arg,
const UDQASTNode& right_arg) : const UDQASTNode& right_arg)
var_type(init_type(type_arg)), : var_type(init_type(type_arg))
type(type_arg), , type (type_arg)
value(value_arg) , value (value_arg)
{ {
this->set_left(left_arg); this->set_left(left_arg);
this->set_right(right_arg); this->set_right(right_arg);
} }
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg,
const std::vector<std::string>& selector_arg)
: var_type(init_type(type_arg))
, type (type_arg)
, value (value_arg)
, selector(selector_arg)
{
if (type_arg == UDQTokenType::ecl_expr) {
this->var_type = UDQ::targetType(std::get<std::string>(this->value), this->selector);
}
if ((this->var_type == UDQVarType::CONNECTION_VAR) ||
(this->var_type == UDQVarType::REGION_VAR) ||
(this->var_type == UDQVarType::SEGMENT_VAR) ||
(this->var_type == UDQVarType::AQUIFER_VAR) ||
(this->var_type == UDQVarType::BLOCK_VAR))
{
throw std::invalid_argument {
"UDQ variable of type: " + UDQ::typeName(this->var_type) + " not yet supported in flow"
};
}
}
UDQASTNode UDQASTNode::serializationTestObject() UDQASTNode UDQASTNode::serializationTestObject()
{ {
@ -110,257 +150,323 @@ UDQASTNode UDQASTNode::serializationTestObject()
result.value = "test1"; result.value = "test1";
result.selector = {"test2"}; result.selector = {"test2"};
result.sign = -1; result.sign = -1;
UDQASTNode left = result; UDQASTNode left = result;
result.left = std::make_shared<UDQASTNode>(left); result.left = std::make_shared<UDQASTNode>(left);
return result; return result;
} }
UDQASTNode::UDQASTNode(UDQTokenType type_arg, UDQSet
const std::variant<std::string, double>& value_arg, UDQASTNode::eval(const UDQVarType target_type,
const std::vector<std::string>& selector_arg) : const UDQContext& context) const
var_type(init_type(type_arg)),
type(type_arg),
value(value_arg),
selector(selector_arg)
{ {
if (type_arg == UDQTokenType::ecl_expr)
this->var_type = UDQ::targetType(std::get<std::string>(this->value), this->selector);
if (this->var_type == UDQVarType::CONNECTION_VAR ||
this->var_type == UDQVarType::REGION_VAR ||
this->var_type == UDQVarType::SEGMENT_VAR ||
this->var_type == UDQVarType::AQUIFER_VAR ||
this->var_type == UDQVarType::BLOCK_VAR)
throw std::logic_error("UDQ variable of type: " + UDQ::typeName(this->var_type) + " not yet supported in flow");
}
UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const {
if (this->type == UDQTokenType::ecl_expr) { if (this->type == UDQTokenType::ecl_expr) {
const auto& string_value = std::get<std::string>( this->value ); return this->sign * this->eval_expression(context);
auto data_type = UDQ::targetType(string_value);
if (data_type == UDQVarType::WELL_VAR) {
const auto& all_wells = context.wells();
if (this->selector.empty()) {
auto res = UDQSet::wells(string_value, all_wells);
for (const auto& well : all_wells)
res.assign(well, context.get_well_var(well, string_value));
return this->sign * res;
} else {
const std::string& well_pattern = this->selector[0];
if (well_pattern.find('*') == std::string::npos)
/*
The right hand side is a fully qualified well name without
any '*', in this case the right hand side evaluates to a
*scalar* - and that scalar value is distributed among all
the wells in the result set.
*/
return this->sign * UDQSet::scalar(string_value, context.get_well_var(well_pattern, string_value));
else {
/*
The right hand side is a set of wells. The result set will
be updated for all wells in the right hand set, wells
missing in the right hand set will be undefined in the
result set.
*/
auto res = UDQSet::wells(string_value, all_wells);
for (const auto& wname : context.wells(well_pattern))
res.assign(wname, context.get_well_var(wname, string_value));
return this->sign * res;
}
}
}
if (data_type == UDQVarType::GROUP_VAR) {
if (this->selector.size() > 0) {
const std::string& group_pattern = this->selector[0];
if (group_pattern.find("*") == std::string::npos)
return UDQSet::scalar(string_value, context.get_group_var(group_pattern, string_value));
else
throw std::logic_error("Group names with wildcards is not yet supported");
} else {
const auto& groups = context.groups();
auto res = UDQSet::groups(string_value, groups);
for (const auto& group : groups)
res.assign(group, context.get_group_var(group, string_value));
return this->sign * res;
}
}
if (data_type == UDQVarType::FIELD_VAR)
return this->sign * UDQSet::scalar(string_value, context.get(string_value));
auto scalar = context.get(string_value);
if (scalar.has_value())
return this->sign * UDQSet::scalar(string_value, scalar.value());
throw std::logic_error("Should not be here: var_type: " + UDQ::typeName(data_type) + " stringvalue:" + string_value);
} }
if (UDQ::scalarFunc(this->type)) { if (UDQ::scalarFunc(this->type)) {
const auto& string_value = std::get<std::string>( this->value ); return this->sign * this->eval_scalar_function(target_type, context);
const auto& udqft = context.function_table();
const UDQScalarFunction& func = dynamic_cast<const UDQScalarFunction&>(udqft.get(string_value));
return this->sign * func.eval( this->left->eval(target_type, context) );
} }
if (UDQ::elementalUnaryFunc(this->type)) { if (UDQ::elementalUnaryFunc(this->type)) {
const auto& string_value = std::get<std::string>( this->value ); return this->sign * this->eval_elemental_unary_function(target_type, context);
auto func_arg = this->left->eval(target_type, context);
const auto& udqft = context.function_table();
const UDQUnaryElementalFunction& func = dynamic_cast<const UDQUnaryElementalFunction&>(udqft.get(string_value));
return this->sign * func.eval(func_arg);
} }
if (UDQ::binaryFunc(this->type)) { if (UDQ::binaryFunc(this->type)) {
auto left_arg = this->left->eval(target_type, context); return this->sign * this->eval_binary_function(target_type, context);
auto right_arg = this->right->eval(target_type, context);
const auto& string_value = std::get<std::string>( this->value );
const auto& udqft = context.function_table();
const UDQBinaryFunction& func = dynamic_cast<const UDQBinaryFunction&>(udqft.get(string_value));
auto res = func.eval(left_arg, right_arg);
return this->sign * res;
} }
if (this->type == UDQTokenType::number) { if (this->type == UDQTokenType::number) {
const std::string dummy_name = "DUMMY"; return this->sign * this->eval_number(target_type, context);
double numeric_value = std::get<double>(this->value);
switch(target_type) {
case UDQVarType::WELL_VAR:
return this->sign * UDQSet::wells(dummy_name, context.wells(), numeric_value);
case UDQVarType::GROUP_VAR:
return this->sign * UDQSet::groups(dummy_name, context.groups(), numeric_value);
case UDQVarType::SCALAR:
return this->sign * UDQSet::scalar(dummy_name, numeric_value);
case UDQVarType::FIELD_VAR:
return this->sign * UDQSet::field(dummy_name, numeric_value);
default:
throw std::invalid_argument("Unsupported target_type: " + std::to_string(static_cast<int>(target_type)));
}
} }
throw std::invalid_argument("Should not be here ... this->type: " + std::to_string(static_cast<int>(this->type))); throw std::invalid_argument {
"Should not be here ... this->type: " + std::to_string(static_cast<int>(this->type))
};
} }
void UDQASTNode::func_tokens(std::set<UDQTokenType>& tokens) const { bool UDQASTNode::valid() const
tokens.insert( this->type ); {
if (this->left) return this->type != UDQTokenType::error;
this->left->func_tokens(tokens);
if (this->right)
this->right->func_tokens(tokens);
} }
std::set<UDQTokenType> UDQASTNode::func_tokens() const { std::set<UDQTokenType> UDQASTNode::func_tokens() const
std::set<UDQTokenType> tokens; {
auto tokens = std::set<UDQTokenType>{};
this->func_tokens(tokens); this->func_tokens(tokens);
return tokens; return tokens;
} }
void UDQASTNode::update_type(const UDQASTNode& arg)
UDQASTNode* UDQASTNode::get_left() const { {
return this->left.get(); if (this->var_type == UDQVarType::NONE) {
}
UDQASTNode* UDQASTNode::get_right() const {
return this->right.get();
}
void UDQASTNode::update_type(const UDQASTNode& arg) {
if (this->var_type == UDQVarType::NONE)
this->var_type = arg.var_type; this->var_type = arg.var_type;
else }
else {
this->var_type = UDQ::coerce(this->var_type, arg.var_type); this->var_type = UDQ::coerce(this->var_type, arg.var_type);
}
} }
void UDQASTNode::set_left(const UDQASTNode& arg)
bool UDQASTNode::valid() const { {
return (this->type != UDQTokenType::error);
}
void UDQASTNode::set_left(const UDQASTNode& arg) {
this->left = std::make_unique<UDQASTNode>(arg); this->left = std::make_unique<UDQASTNode>(arg);
this->update_type(arg); this->update_type(arg);
} }
void UDQASTNode::set_right(const UDQASTNode& arg) { void UDQASTNode::set_right(const UDQASTNode& arg)
{
this->right = std::make_unique<UDQASTNode>(arg); this->right = std::make_unique<UDQASTNode>(arg);
this->update_type(arg); this->update_type(arg);
} }
void UDQASTNode::scale(double sign_factor) { void UDQASTNode::scale(double sign_factor)
{
this->sign *= sign_factor; this->sign *= sign_factor;
} }
bool UDQASTNode::operator==(const UDQASTNode& data) const { UDQASTNode* UDQASTNode::get_left() const
{
return this->left.get();
}
UDQASTNode* UDQASTNode::get_right() const
{
return this->right.get();
}
bool UDQASTNode::operator==(const UDQASTNode& data) const
{
if ((this->left && !data.left) || if ((this->left && !data.left) ||
(!this->left && data.left)) (!this->left && data.left))
{
return false; return false;
}
if (this->left && !(*this->left == *data.left)) if (this->left && !(*this->left == *data.left)) {
return false; return false;
}
if ((this->right && !data.right) || if ((this->right && !data.right) ||
(!this->right && data.right)) (!this->right && data.right))
{
return false; return false;
}
if (this->right && !(*this->right == *data.right)) if (this->right && !(*this->right == *data.right)) {
return false; return false;
}
return type == data.type && return (type == data.type)
var_type == data.var_type && && (var_type == data.var_type)
value == data.value && && (value == data.value)
selector == data.selector; && (selector == data.selector)
;
} }
namespace { void UDQASTNode::required_summary(std::unordered_set<std::string>& summary_keys) const
{
bool is_udq(const std::string& key) {
if (key.size() < 2)
return false;
if (key[1] != 'U')
return false;
return true;
}
}
void UDQASTNode::required_summary(std::unordered_set<std::string>& summary_keys) const {
if (this->type == UDQTokenType::ecl_expr) { if (this->type == UDQTokenType::ecl_expr) {
if (std::holds_alternative<std::string>(this->value)) { if (std::holds_alternative<std::string>(this->value)) {
const auto& keyword = std::get<std::string>(this->value); const auto& keyword = std::get<std::string>(this->value);
if (!is_udq(keyword)) if (!is_udq(keyword)) {
summary_keys.insert(keyword); summary_keys.insert(keyword);
}
} }
} }
if (this->left) if (this->left) {
this->left->required_summary(summary_keys); this->left->required_summary(summary_keys);
}
if (this->right) if (this->right) {
this->right->required_summary(summary_keys); this->right->required_summary(summary_keys);
}
} }
UDQASTNode operator*(const UDQASTNode&lhs, double sign_factor) { UDQSet
UDQASTNode::eval_expression(const UDQContext& context) const
{
const auto& string_value = std::get<std::string>(this->value);
const auto data_type = UDQ::targetType(string_value);
if (data_type == UDQVarType::WELL_VAR) {
return this->eval_well_expression(string_value, context);
}
if (data_type == UDQVarType::GROUP_VAR) {
return this->eval_group_expression(string_value, context);
}
if (data_type == UDQVarType::FIELD_VAR) {
return UDQSet::scalar(string_value, context.get(string_value));
}
if (const auto scalar = context.get(string_value); scalar.has_value()) {
return UDQSet::scalar(string_value, scalar.value());
}
throw std::logic_error {
"Should not be here: var_type: '"
+ UDQ::typeName(data_type)
+ "' stringvalue: '"
+ string_value + '\''
};
}
UDQSet
UDQASTNode::eval_well_expression(const std::string& string_value,
const UDQContext& context) const
{
const auto& all_wells = context.wells();
if (this->selector.empty()) {
auto res = UDQSet::wells(string_value, all_wells);
for (const auto& well : all_wells) {
res.assign(well, context.get_well_var(well, string_value));
}
return res;
}
const auto& well_pattern = this->selector.front();
if (well_pattern.find('*') == std::string::npos) {
// The right hand side is a fully qualified well name without any
// '*', in this case the right hand side evaluates to a *scalar* -
// and that scalar value is distributed among all the wells in the
// result set.
return UDQSet::scalar(string_value, context.get_well_var(well_pattern, string_value));
}
else {
// The right hand side is a set of wells. The result set will be
// updated for all wells in the right hand set, wells missing in the
// right hand set will be undefined in the result set.
auto res = UDQSet::wells(string_value, all_wells);
for (const auto& wname : context.wells(well_pattern)) {
res.assign(wname, context.get_well_var(wname, string_value));
}
return res;
}
}
UDQSet
UDQASTNode::eval_group_expression(const std::string& string_value,
const UDQContext& context) const
{
if (! this->selector.empty()) {
const std::string& group_pattern = this->selector[0];
if (group_pattern.find("*") == std::string::npos) {
return UDQSet::scalar(string_value, context.get_group_var(group_pattern, string_value));
}
throw std::logic_error("Group names with wildcards is not yet supported");
}
const auto& groups = context.groups();
auto res = UDQSet::groups(string_value, groups);
for (const auto& group : groups) {
res.assign(group, context.get_group_var(group, string_value));
}
return res;
}
UDQSet
UDQASTNode::eval_scalar_function(const UDQVarType target_type,
const UDQContext& context) const
{
const auto& string_value = std::get<std::string>(this->value);
const auto& udqft = context.function_table();
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get(string_value));
return func.eval(this->left->eval(target_type, context));
}
UDQSet
UDQASTNode::eval_elemental_unary_function(const UDQVarType target_type,
const UDQContext& context) const
{
const auto& string_value = std::get<std::string>(this->value);
const auto func_arg = this->left->eval(target_type, context);
const auto& udqft = context.function_table();
const auto& func = dynamic_cast<const UDQUnaryElementalFunction&>(udqft.get(string_value));
return func.eval(func_arg);
}
UDQSet
UDQASTNode::eval_binary_function(const UDQVarType target_type,
const UDQContext& context) const
{
const auto left_arg = this->left->eval(target_type, context);
const auto right_arg = this->right->eval(target_type, context);
const auto& string_value = std::get<std::string>(this->value);
const auto& udqft = context.function_table();
const auto& func = dynamic_cast<const UDQBinaryFunction&>(udqft.get(string_value));
return func.eval(left_arg, right_arg);
}
UDQSet
UDQASTNode::eval_number(const UDQVarType target_type,
const UDQContext& context) const
{
const auto dummy_name = std::string { "DUMMY" };
const auto numeric_value = std::get<double>(this->value);
switch (target_type) {
case UDQVarType::WELL_VAR:
return UDQSet::wells(dummy_name, context.wells(), numeric_value);
case UDQVarType::GROUP_VAR:
return UDQSet::groups(dummy_name, context.groups(), numeric_value);
case UDQVarType::SCALAR:
return UDQSet::scalar(dummy_name, numeric_value);
case UDQVarType::FIELD_VAR:
return UDQSet::field(dummy_name, numeric_value);
default:
throw std::invalid_argument {
"Unsupported target_type: " + std::to_string(static_cast<int>(target_type))
};
}
}
void UDQASTNode::func_tokens(std::set<UDQTokenType>& tokens) const
{
tokens.insert(this->type);
if (this->left) {
this->left->func_tokens(tokens);
}
if (this->right) {
this->right->func_tokens(tokens);
}
}
UDQASTNode operator*(const UDQASTNode&lhs, double sign_factor)
{
UDQASTNode prod = lhs; UDQASTNode prod = lhs;
prod.scale(sign_factor); prod.scale(sign_factor);
return prod; return prod;
} }
UDQASTNode operator*(double lhs, const UDQASTNode& rhs)
UDQASTNode operator*(double lhs, const UDQASTNode& rhs) { {
return rhs * lhs; return rhs * lhs;
} }
} } // namespace Opm

View File

@ -17,45 +17,69 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <fmt/format.h> #include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
#include <opm/io/eclipse/rst/state.hpp> #include <opm/io/eclipse/rst/state.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp> #include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/common/utility/OpmInputError.hpp> #include <opm/common/utility/OpmInputError.hpp>
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <opm/input/eclipse/Schedule/SummaryState.hpp> #include <opm/input/eclipse/Schedule/SummaryState.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
#include <opm/input/eclipse/Parser/ParserKeywords/U.hpp> // UDQ
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
#include <algorithm>
#include <cstddef>
#include <string>
#include <tuple>
#include <unordered_set>
#include <utility>
#include <vector>
#include <fmt/format.h>
namespace {
std::string strip_quotes(const std::string& s)
{
if (s[0] == '\'') {
return s.substr(1, s.size() - 2);
}
else {
return s;
}
}
} // Anonymous namespace
namespace Opm { namespace Opm {
namespace { UDQConfig::UDQConfig(const UDQParams& params)
std::string strip_quotes(const std::string& s) { : udq_params(params)
if (s[0] == '\'') , udqft(this->udq_params)
return s.substr(1, s.size() - 2);
else
return s;
}
}
UDQConfig::UDQConfig(const UDQParams& params) :
udq_params(params),
udqft(this->udq_params)
{} {}
UDQConfig::UDQConfig(const UDQParams& params, const RestartIO::RstState& rst_state)
UDQConfig::UDQConfig(const UDQParams& params, const RestartIO::RstState& rst_state) : : UDQConfig(params)
UDQConfig(params)
{ {
for (const auto& rst_udq : rst_state.udqs) { for (const auto& rst_udq : rst_state.udqs) {
if (rst_udq.is_define()) { if (rst_udq.is_define()) {
KeywordLocation location("UDQ", "Restart file", 0); KeywordLocation location("UDQ", "Restart file", 0);
this->add_define(rst_udq.name, location, {rst_udq.expression()}, rst_state.header.report_step); this->add_define(rst_udq.name,
} else location,
this->add_assign(rst_udq.name, rst_udq.assign_selector(), rst_udq.assign_value(), rst_state.header.report_step); { rst_udq.expression() },
rst_state.header.report_step);
}
else {
this->add_assign(rst_udq.name,
rst_udq.assign_selector(),
rst_udq.assign_value(),
rst_state.header.report_step);
}
this->add_unit(rst_udq.name, rst_udq.unit); this->add_unit(rst_udq.name, rst_udq.unit);
} }
} }
@ -74,113 +98,172 @@ namespace Opm {
return result; return result;
} }
const UDQParams& UDQConfig::params() const { const UDQParams& UDQConfig::params() const
{
return this->udq_params; return this->udq_params;
} }
void UDQConfig::add_node( const std::string& quantity, UDQAction action) { void UDQConfig::add_node(const std::string& quantity, const UDQAction action)
{
auto index_iter = this->input_index.find(quantity); auto index_iter = this->input_index.find(quantity);
if (this->input_index.find(quantity) == this->input_index.end()) { if (this->input_index.find(quantity) == this->input_index.end()) {
auto var_type = UDQ::varType(quantity); auto var_type = UDQ::varType(quantity);
auto insert_index = this->input_index.size(); auto insert_index = this->input_index.size();
this->type_count[var_type] += 1; this->type_count[var_type] += 1;
this->input_index[quantity] = UDQIndex(insert_index, this->type_count[var_type], action, var_type); this->input_index[quantity] = UDQIndex(insert_index, this->type_count[var_type], action, var_type);
} else }
else {
index_iter->second.action = action; index_iter->second.action = action;
}
} }
void UDQConfig::add_assign(const std::string& quantity, const std::vector<std::string>& selector, double value, std::size_t report_step) { void UDQConfig::add_assign(const std::string& quantity,
const std::vector<std::string>& selector,
const double value,
const std::size_t report_step)
{
this->add_node(quantity, UDQAction::ASSIGN); this->add_node(quantity, UDQAction::ASSIGN);
auto assignment = this->m_assignments.find(quantity); auto assignment = this->m_assignments.find(quantity);
if (assignment == this->m_assignments.end()) if (assignment == this->m_assignments.end()) {
this->m_assignments.insert( std::make_pair(quantity, UDQAssign(quantity, selector, value, report_step ))); this->m_assignments.emplace(std::piecewise_construct,
else std::forward_as_tuple(quantity),
std::forward_as_tuple(quantity, selector,
value, report_step));
}
else {
assignment->second.add_record(selector, value, report_step); assignment->second.add_record(selector, value, report_step);
}
} }
void UDQConfig::add_assign(const std::string& quantity, const std::unordered_set<std::string>& selector, double value, std::size_t report_step) { void UDQConfig::add_assign(const std::string& quantity,
const std::unordered_set<std::string>& selector,
const double value,
const std::size_t report_step)
{
this->add_node(quantity, UDQAction::ASSIGN); this->add_node(quantity, UDQAction::ASSIGN);
auto assignment = this->m_assignments.find(quantity); auto assignment = this->m_assignments.find(quantity);
if (assignment == this->m_assignments.end()) if (assignment == this->m_assignments.end()) {
this->m_assignments.insert( std::make_pair(quantity, UDQAssign(quantity, selector, value, report_step ))); this->m_assignments.emplace(std::piecewise_construct,
else std::forward_as_tuple(quantity),
std::forward_as_tuple(quantity, selector,
value, report_step));
}
else {
assignment->second.add_record(selector, value, report_step); assignment->second.add_record(selector, value, report_step);
}
} }
void UDQConfig::add_define(const std::string& quantity,
void UDQConfig::add_define(const std::string& quantity, const KeywordLocation& location, const std::vector<std::string>& expression, std::size_t report_step) { const KeywordLocation& location,
const std::vector<std::string>& expression,
const std::size_t report_step)
{
this->add_node(quantity, UDQAction::DEFINE); this->add_node(quantity, UDQAction::DEFINE);
auto defined_iter = this->m_definitions.find( quantity );
if (defined_iter != this->m_definitions.end())
this->m_definitions.erase( defined_iter );
this->m_definitions.insert( std::make_pair(quantity, UDQDefine(this->udq_params, quantity, report_step, location, expression))); this->m_definitions.insert_or_assign(quantity,
UDQDefine {
this->udq_params,
quantity,
report_step,
location,
expression
});
this->define_order.insert(quantity); this->define_order.insert(quantity);
} }
void UDQConfig::add_unit(const std::string& keyword, const std::string& quoted_unit)
void UDQConfig::add_unit(const std::string& keyword, const std::string& quoted_unit) { {
const std::string unit = strip_quotes(quoted_unit); const auto unit = strip_quotes(quoted_unit);
const auto pair_ptr = this->units.find(keyword); const auto pair_ptr = this->units.find(keyword);
if (pair_ptr != this->units.end()) { if (pair_ptr != this->units.end()) {
if (pair_ptr->second != unit) if (pair_ptr->second != unit) {
throw std::invalid_argument("Illegal to change unit of UDQ keyword runtime"); throw std::invalid_argument("Illegal to change unit of UDQ keyword runtime");
}
return; return;
} }
this->units[keyword] = unit; this->units[keyword] = unit;
} }
void UDQConfig::add_update(const std::string& keyword,
const std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& data)
{
if (data.empty()) {
throw OpmInputError {
fmt::format("Missing third item: ON|OFF|NEXT for UDQ update of {}", keyword),
location
};
}
void UDQConfig::add_update(const std::string& keyword, std::size_t report_step, const KeywordLocation& location, const std::vector<std::string>& data) { if (this->m_definitions.count(keyword) == 0) {
if (data.empty()) throw OpmInputError {
throw OpmInputError( fmt::format("Missing third item: ON|OFF|NEXT for UDQ update of {}", keyword), location); fmt::format("UDQ variable: {} must be defined before you can use UPDATE", keyword),
location
};
}
if (this->m_definitions.count(keyword) == 0) const auto update_status = UDQ::updateType(data[0]);
throw OpmInputError( fmt::format("UDQ variable: {} must be defined before you can use UPDATE", keyword), location);
auto update_status = UDQ::updateType(data[0]);
auto& define = this->m_definitions[keyword]; auto& define = this->m_definitions[keyword];
define.update_status( update_status, report_step ); define.update_status(update_status, report_step);
} }
void UDQConfig::add_record(const DeckRecord& record,
const KeywordLocation& location,
const std::size_t report_step)
{
using KW = ParserKeywords::UDQ;
const auto action = UDQ::actionType(record.getItem<KW::ACTION>().get<RawString>(0));
const auto& quantity = record.getItem<KW::QUANTITY>().get<std::string>(0);
const auto data = RawString::strings(record.getItem<KW::DATA>().getData<RawString>());
void UDQConfig::add_record(const DeckRecord& record, const KeywordLocation& location, std::size_t report_step) { if (action == UDQAction::UPDATE) {
auto action = UDQ::actionType(record.getItem("ACTION").get<RawString>(0));
const auto& quantity = record.getItem("QUANTITY").get<std::string>(0);
const auto& data = RawString::strings( record.getItem("DATA").getData<RawString>() );
if (action == UDQAction::UPDATE)
this->add_update(quantity, report_step, location, data); this->add_update(quantity, report_step, location, data);
else if (action == UDQAction::UNITS) }
this->add_unit( quantity, data[0] ); else if (action == UDQAction::UNITS) {
this->add_unit(quantity, data.front());
}
else if (action == UDQAction::ASSIGN) {
const auto selector = std::vector<std::string>(data.begin(), data.end() - 1);
const auto value = std::stod(data.back());
this->add_assign(quantity, selector, value, report_step);
}
else if (action == UDQAction::DEFINE) {
this->add_define(quantity, location, data, report_step);
}
else { else {
if (action == UDQAction::ASSIGN) { throw std::runtime_error {
std::vector<std::string> selector(data.begin(), data.end() - 1); "Unknown UDQ Operation " + std::to_string(static_cast<int>(action))
double value = std::stod(data.back()); };
this->add_assign(quantity, selector, value, report_step);
} else if (action == UDQAction::DEFINE)
this->add_define(quantity, location, data, report_step);
else
throw std::runtime_error("Internal error - should not be here");
} }
} }
const UDQAssign& UDQConfig::assign(const std::string& key) const { const UDQAssign& UDQConfig::assign(const std::string& key) const
{
return this->m_assignments.at(key); return this->m_assignments.at(key);
} }
const UDQDefine& UDQConfig::define(const std::string& key) const { const UDQDefine& UDQConfig::define(const std::string& key) const
{
return this->m_definitions.at(key); return this->m_definitions.at(key);
} }
UDQAction UDQConfig::action_type(const std::string& udq_key) const { UDQAction UDQConfig::action_type(const std::string& udq_key) const
{
auto action_iter = this->input_index.find(udq_key); auto action_iter = this->input_index.find(udq_key);
return action_iter->second.action; return action_iter->second.action;
} }
std::vector<UDQDefine> UDQConfig::definitions() const { std::vector<UDQDefine> UDQConfig::definitions() const
{
std::vector<UDQDefine> ret; std::vector<UDQDefine> ret;
for (const auto& index_pair : this->input_index) { for (const auto& index_pair : this->input_index) {
@ -193,164 +276,184 @@ namespace Opm {
return ret; return ret;
} }
std::vector<UDQDefine> UDQConfig::definitions(const UDQVarType var_type) const
std::vector<UDQDefine> UDQConfig::definitions(UDQVarType var_type) const { {
std::vector<UDQDefine> filtered_defines; std::vector<UDQDefine> filtered_defines;
for (const auto& index_pair : this->input_index) { for (const auto& index_pair : this->input_index) {
if (index_pair.second.action == UDQAction::DEFINE) { if (index_pair.second.action == UDQAction::DEFINE) {
const std::string& key = index_pair.first; const std::string& key = index_pair.first;
const auto& udq_define = this->m_definitions.at(key); const auto& udq_define = this->m_definitions.at(key);
if (udq_define.var_type() == var_type) if (udq_define.var_type() == var_type) {
filtered_defines.push_back(udq_define); filtered_defines.push_back(udq_define);
}
} }
} }
return filtered_defines; return filtered_defines;
} }
std::vector<UDQInput> UDQConfig::input() const
std::vector<UDQInput> UDQConfig::input() const { {
std::vector<UDQInput> res; std::vector<UDQInput> res;
for (const auto& index_pair : this->input_index) { for (const auto& index_pair : this->input_index) {
const UDQIndex& index = index_pair.second; const UDQIndex& index = index_pair.second;
std::string u; std::string u;
if (this->has_unit(index_pair.first)) if (this->has_unit(index_pair.first)) {
u = this->unit(index_pair.first); u = this->unit(index_pair.first);
}
if (index.action == UDQAction::DEFINE) { if (index.action == UDQAction::DEFINE) {
const std::string& key = index_pair.first; const std::string& key = index_pair.first;
res.push_back(UDQInput(index, this->m_definitions.at(key), u)); res.push_back(UDQInput(index, this->m_definitions.at(key), u));
} else if (index_pair.second.action == UDQAction::ASSIGN) { }
else if (index_pair.second.action == UDQAction::ASSIGN) {
const std::string& key = index_pair.first; const std::string& key = index_pair.first;
res.push_back(UDQInput(index, this->m_assignments.at(key), u)); res.push_back(UDQInput(index, this->m_assignments.at(key), u));
} }
} }
return res; return res;
} }
std::size_t UDQConfig::size() const { std::size_t UDQConfig::size() const
std::size_t s = 0; {
for (const auto& index_pair : this->input_index) { return std::count_if(this->input_index.begin(), this->input_index.end(),
if (index_pair.second.action == UDQAction::DEFINE) [](const auto& index_pair)
s += 1; {
else if (index_pair.second.action == UDQAction::ASSIGN) const auto action = index_pair.second.action;
s += 1;
} return (action == UDQAction::DEFINE)
return s; || (action == UDQAction::ASSIGN);
});
} }
std::vector<UDQAssign> UDQConfig::assignments() const
std::vector<UDQAssign> UDQConfig::assignments() const { {
std::vector<UDQAssign> ret; std::vector<UDQAssign> ret;
for (const auto& index_pair : this->input_index) { for (const auto& index_pair : this->input_index) {
if (index_pair.second.action == UDQAction::ASSIGN) { if (index_pair.second.action == UDQAction::ASSIGN) {
const std::string& key = index_pair.first; const std::string& key = index_pair.first;
ret.push_back(this->m_assignments.at(key)); ret.push_back(this->m_assignments.at(key));
} }
} }
return ret; return ret;
} }
std::vector<UDQAssign> UDQConfig::assignments(const UDQVarType var_type) const
std::vector<UDQAssign> UDQConfig::assignments(UDQVarType var_type) const { {
std::vector<UDQAssign> filtered_assigns; std::vector<UDQAssign> filtered_assigns;
for (const auto& index_pair : this->input_index) { for (const auto& index_pair : this->input_index) {
const std::string& key = index_pair.first; const std::string& key = index_pair.first;
const auto& assign_iter = this->m_assignments.find(key); const auto& assign_iter = this->m_assignments.find(key);
if (assign_iter != this->m_assignments.end()) { if (assign_iter != this->m_assignments.end()) {
if (assign_iter->second.var_type() == var_type) if (assign_iter->second.var_type() == var_type) {
filtered_assigns.push_back(assign_iter->second); filtered_assigns.push_back(assign_iter->second);
}
} }
} }
return filtered_assigns; return filtered_assigns;
} }
const std::string& UDQConfig::unit(const std::string& key) const
{
const std::string& UDQConfig::unit(const std::string& key) const {
const auto pair_ptr = this->units.find(key); const auto pair_ptr = this->units.find(key);
if (pair_ptr == this->units.end()) if (pair_ptr == this->units.end()) {
throw std::invalid_argument("No such UDQ quantity: " + key); throw std::invalid_argument("No such UDQ quantity: " + key);
}
return pair_ptr->second; return pair_ptr->second;
} }
bool UDQConfig::has_unit(const std::string& keyword) const { bool UDQConfig::has_unit(const std::string& keyword) const
{
return (this->units.count(keyword) > 0); return (this->units.count(keyword) > 0);
} }
bool UDQConfig::has_keyword(const std::string& keyword) const
bool UDQConfig::has_keyword(const std::string& keyword) const { {
if (this->m_assignments.count(keyword) > 0) return (this->m_assignments.find(keyword) != this->m_assignments.end())
return true; || (this->m_definitions.find(keyword) != this->m_definitions.end());
if (this->m_definitions.count(keyword) > 0)
return true;
return false;
} }
UDQInput UDQConfig::operator[](const std::string& keyword) const
UDQInput UDQConfig::operator[](const std::string& keyword) const { {
const auto index_iter = this->input_index.find(keyword); const auto index_iter = this->input_index.find(keyword);
if (index_iter == this->input_index.end()) if (index_iter == this->input_index.end()) {
throw std::invalid_argument("Keyword: " + keyword + " not recognized as ASSIGN/DEFINE UDQ"); throw std::invalid_argument("Keyword: '" + keyword +
"' not recognized as ASSIGN/DEFINE UDQ");
}
std::string u; const auto u = this->has_unit(keyword)
if (this->has_unit(keyword)) ? this->unit(keyword) : std::string{};
u = this->unit(keyword);
if (index_iter->second.action == UDQAction::ASSIGN) if (index_iter->second.action == UDQAction::ASSIGN) {
return UDQInput(this->input_index.at(keyword), this->m_assignments.at(keyword), u); return UDQInput(this->input_index.at(keyword), this->m_assignments.at(keyword), u);
}
if (index_iter->second.action == UDQAction::DEFINE) if (index_iter->second.action == UDQAction::DEFINE) {
return UDQInput(this->input_index.at(keyword), this->m_definitions.at(keyword), u); return UDQInput(this->input_index.at(keyword), this->m_definitions.at(keyword), u);
}
throw std::logic_error("Internal error - should not be here"); throw std::logic_error("Internal error - should not be here");
} }
UDQInput UDQConfig::operator[](std::size_t insert_index) const { UDQInput UDQConfig::operator[](const std::size_t insert_index) const
{
auto index_iter = std::find_if(this->input_index.begin(), this->input_index.end(), auto index_iter = std::find_if(this->input_index.begin(), this->input_index.end(),
[&insert_index](const std::pair<std::string, UDQIndex>& name_index) [insert_index](const std::pair<std::string, UDQIndex>& name_index)
{ {
const auto& [_, index] = name_index; return name_index.second.insert_index == insert_index;
(void)_; });
return index.insert_index == insert_index;
});
if (index_iter == this->input_index.end()) if (index_iter == this->input_index.end()) {
throw std::invalid_argument("Insert index not recognized"); throw std::invalid_argument("Insert index not recognized");
}
const auto& [keyword, index] = *index_iter; const auto& [keyword, index] = *index_iter;
std::string u; std::string u;
if (this->has_unit(keyword)) if (this->has_unit(keyword)) {
u = this->unit(keyword); u = this->unit(keyword);
}
if (index.action == UDQAction::ASSIGN) if (index.action == UDQAction::ASSIGN) {
return UDQInput(index, this->m_assignments.at(keyword), u); return UDQInput(index, this->m_assignments.at(keyword), u);
}
if (index.action == UDQAction::DEFINE) if (index.action == UDQAction::DEFINE) {
return UDQInput(index, this->m_definitions.at(keyword), u); return UDQInput(index, this->m_definitions.at(keyword), u);
}
throw std::logic_error("Internal error - should not be here"); throw std::logic_error("Internal error - should not be here");
} }
const UDQFunctionTable& UDQConfig::function_table() const
const UDQFunctionTable& UDQConfig::function_table() const { {
return this->udqft; return this->udqft;
} }
bool UDQConfig::operator==(const UDQConfig& data) const
bool UDQConfig::operator==(const UDQConfig& data) const { {
return this->params() == data.params() && return (this->params() == data.params())
this->function_table() == data.function_table() && && (this->function_table() == data.function_table())
this->m_definitions == data.m_definitions && && (this->m_definitions == data.m_definitions)
this->m_assignments == data.m_assignments && && (this->m_assignments == data.m_assignments)
this->units == data.units && && (this->units == data.units)
this->input_index == data.input_index && && (this->input_index == data.input_index)
this->type_count == data.type_count; && (this->type_count == data.type_count)
;
} }
void UDQConfig::eval_assign(std::size_t report_step, SummaryState& st, UDQState& udq_state, UDQContext& context) const { void UDQConfig::eval_assign(const std::size_t report_step,
SummaryState& st,
UDQState& udq_state,
UDQContext& context) const
{
for (const auto& assign : this->assignments(UDQVarType::WELL_VAR)) { for (const auto& assign : this->assignments(UDQVarType::WELL_VAR)) {
if (udq_state.assign(report_step, assign.keyword())) { if (udq_state.assign(report_step, assign.keyword())) {
auto ws = assign.eval(st.wells()); auto ws = assign.eval(st.wells());
@ -373,8 +476,10 @@ namespace Opm {
} }
} }
void UDQConfig::eval_define(const std::size_t report_step,
void UDQConfig::eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const { UDQState& udq_state,
UDQContext& context) const
{
for (const auto& def : this->definitions(UDQVarType::WELL_VAR)) { for (const auto& def : this->definitions(UDQVarType::WELL_VAR)) {
if (udq_state.define(def.keyword(), def.status())) { if (udq_state.define(def.keyword(), def.status())) {
auto ws = def.eval(context); auto ws = def.eval(context);
@ -397,26 +502,31 @@ namespace Opm {
} }
} }
void UDQConfig::eval(std::size_t report_step, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const { void UDQConfig::eval(const std::size_t report_step,
const WellMatcher& wm,
SummaryState& st,
UDQState& udq_state) const
{
UDQContext context(this->function_table(), wm, st, udq_state); UDQContext context(this->function_table(), wm, st, udq_state);
this->eval_assign(report_step, st, udq_state, context); this->eval_assign(report_step, st, udq_state, context);
this->eval_define(report_step, udq_state, context); this->eval_define(report_step, udq_state, context);
} }
void UDQConfig::eval_assign(std::size_t report_step, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const { void UDQConfig::eval_assign(const std::size_t report_step,
const WellMatcher& wm,
SummaryState& st,
UDQState& udq_state) const
{
UDQContext context(this->function_table(), wm, st, udq_state); UDQContext context(this->function_table(), wm, st, udq_state);
this->eval_assign(report_step, st, udq_state, context); this->eval_assign(report_step, st, udq_state, context);
} }
void UDQConfig::required_summary(std::unordered_set<std::string>& summary_keys) const
void UDQConfig::required_summary(std::unordered_set<std::string>& summary_keys) const { {
for (const auto& def_pair : this->m_definitions) { for (const auto& def_pair : this->m_definitions) {
const auto& udq_def = def_pair.second; const auto& udq_def = def_pair.second;
udq_def.required_summary(summary_keys); udq_def.required_summary(summary_keys);
} }
} }
} // namespace Opm
}

View File

@ -16,127 +16,126 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <iostream>
#include <cstring>
#include <tuple>
#include <fmt/format.h>
#include <exception>
#include <opm/common/utility/String.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <opm/input/eclipse/Parser/ErrorGuard.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/common/utility/String.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/input/eclipse/Parser/ErrorGuard.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include "../../Parser/raw/RawConsts.hpp" #include "../../Parser/raw/RawConsts.hpp"
#include "UDQParser.hpp" #include "UDQParser.hpp"
namespace Opm { #include <cstddef>
#include <cstring>
#include <exception>
#include <stdexcept>
#include <string>
#include <tuple>
#include <unordered_set>
#include <vector>
#include <fmt/format.h>
namespace { namespace {
std::vector<std::string> quote_split(const std::string& item) { std::vector<std::string> quote_split(const std::string& item)
{
char quote_char = '\''; char quote_char = '\'';
std::vector<std::string> items; std::vector<std::string> items;
std::size_t offset = 0; std::size_t offset = 0;
while (true) { while (true) {
auto quote_pos1 = item.find(quote_char, offset); auto quote_pos1 = item.find(quote_char, offset);
if (quote_pos1 == std::string::npos) { if (quote_pos1 == std::string::npos) {
if (offset < item.size()) if (offset < item.size()) {
items.push_back(item.substr(offset)); items.push_back(item.substr(offset));
}
break; break;
} }
auto quote_pos2 = item.find(quote_char, quote_pos1 + 1); auto quote_pos2 = item.find(quote_char, quote_pos1 + 1);
if (quote_pos2 == std::string::npos) if (quote_pos2 == std::string::npos) {
throw std::invalid_argument("Unbalanced quotes in: " + item); throw std::invalid_argument("Unbalanced quotes in: " + item);
}
if (quote_pos1 > offset) if (quote_pos1 > offset) {
items.push_back(item.substr(offset, quote_pos1 - offset)); items.push_back(item.substr(offset, quote_pos1 - offset));
}
items.push_back(item.substr(quote_pos1, 1 + quote_pos2 - quote_pos1)); items.push_back(item.substr(quote_pos1, 1 + quote_pos2 - quote_pos1));
offset = quote_pos2 + 1; offset = quote_pos2 + 1;
} }
return items; return items;
} }
std::vector<Opm::UDQToken>
make_tokens(const std::vector<std::string>& string_tokens)
{
std::vector<UDQToken> make_tokens(const std::vector<std::string>& string_tokens) { if (string_tokens.empty()) {
if (string_tokens.empty())
return {}; return {};
}
std::vector<UDQToken> tokens; std::vector<Opm::UDQToken> tokens;
std::size_t token_index = 0; std::size_t token_index = 0;
while (true) { while (true) {
const auto& string_token = string_tokens[token_index]; const auto& string_token = string_tokens[token_index];
auto token_type = UDQ::tokenType(string_tokens[token_index]); auto token_type = Opm::UDQ::tokenType(string_tokens[token_index]);
token_index += 1; token_index += 1;
if (token_type == UDQTokenType::ecl_expr) { if (token_type == Opm::UDQTokenType::ecl_expr) {
std::vector<std::string> selector; std::vector<std::string> selector;
while (true) { while (true) {
if (token_index == string_tokens.size()) if (token_index == string_tokens.size()) {
break; break;
}
auto next_type = UDQ::tokenType(string_tokens[token_index]); auto next_type = Opm::UDQ::tokenType(string_tokens[token_index]);
if (next_type == UDQTokenType::ecl_expr) { if (next_type == Opm::UDQTokenType::ecl_expr) {
const auto& select_token = string_tokens[token_index]; const auto& select_token = string_tokens[token_index];
if (RawConsts::is_quote()(select_token[0])) if (Opm::RawConsts::is_quote()(select_token[0])) {
selector.push_back(select_token.substr(1, select_token.size() - 2)); selector.push_back(select_token.substr(1, select_token.size() - 2));
else }
else {
selector.push_back(select_token); selector.push_back(select_token);
token_index += 1; }
} else
break;
}
tokens.emplace_back( string_token, selector );
} else
tokens.emplace_back( string_token, token_type );
if (token_index == string_tokens.size()) token_index += 1;
}
else {
break;
}
}
tokens.emplace_back(string_token, selector);
}
else {
tokens.emplace_back(string_token, token_type);
}
if (token_index == string_tokens.size()) {
break; break;
}
} }
return tokens; return tokens;
} }
std::string
} next_token(const std::string& item,
std::size_t& offset,
UDQDefine::UDQDefine() const std::vector<std::string>& splitters)
: m_var_type(UDQVarType::NONE) {
{}
template <typename T>
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
const std::string& keyword,
std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data,
const ParseContext& parseContext,
T&& errors) :
UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, parseContext, errors)
{}
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
const std::string& keyword,
std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data) :
UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, ParseContext(), ErrorGuard())
{}
namespace {
std::string next_token(const std::string& item, std::size_t& offset, const std::vector<std::string>& splitters) {
if (std::isdigit(item[offset])) { if (std::isdigit(item[offset])) {
auto substring = item.substr(offset); auto substring = item.substr(offset);
char * end_ptr; char* end_ptr;
std::ignore = std::strtod(substring.c_str(), &end_ptr); std::ignore = std::strtod(substring.c_str(), &end_ptr);
std::size_t token_size = end_ptr - substring.c_str(); std::size_t token_size = end_ptr - substring.c_str();
@ -153,32 +152,86 @@ std::string next_token(const std::string& item, std::size_t& offset, const std::
auto pos = item.find(splitter, offset); auto pos = item.find(splitter, offset);
if (pos < min_pos) { if (pos < min_pos) {
min_pos = pos; min_pos = pos;
if (pos == offset) if (pos == offset) {
token = splitter; token = splitter;
else }
else {
token = item.substr(offset, pos - offset); token = item.substr(offset, pos - offset);
}
} }
} }
offset += token.size(); offset += token.size();
return trim_copy(token);
return Opm::trim_copy(token);
}
// This function unconditionally returns true and is therefore not a real
// predicate at the moment. We nevertheless keep the predicate here in the
// hope that it is possible to actually make it useful in the future. See
// the comment in UDQEnums.hpp about 'UDQ type system'.
bool dynamic_type_check(const Opm::UDQVarType lhs,
const Opm::UDQVarType rhs)
{
if (lhs == rhs) {
return true;
}
if (rhs == Opm::UDQVarType::SCALAR) {
return true;
}
return true;
} }
} // Anonymous namespace } // Anonymous namespace
UDQDefine::UDQDefine(const UDQParams& udq_params, namespace Opm {
const std::string& keyword,
std::size_t report_step, UDQDefine::UDQDefine()
const KeywordLocation& location, : m_var_type(UDQVarType::NONE)
{}
template <typename T>
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
const std::string& keyword,
const std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data, const std::vector<std::string>& deck_data,
const ParseContext& parseContext, const ParseContext& parseContext,
ErrorGuard& errors) : T&& errors)
m_keyword(keyword), : UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, parseContext, errors)
m_var_type(UDQ::varType(keyword)), {}
m_location(location),
m_report_step(report_step),
m_update_status(UDQUpdate::ON) UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
const std::string& keyword,
const std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data)
: UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, ParseContext(), ErrorGuard())
{}
UDQDefine::UDQDefine(const UDQParams& udq_params,
const std::string& keyword,
const std::size_t report_step,
const KeywordLocation& location,
const std::vector<std::string>& deck_data,
const ParseContext& parseContext,
ErrorGuard& errors)
: m_keyword (keyword)
, m_var_type (UDQ::varType(keyword))
, m_location (location)
, m_report_step (report_step)
, m_update_status(UDQUpdate::ON)
{ {
std::vector<std::string> string_tokens; const auto splitters = std::vector<std::string> {
" ", "TU*[]", "(", ")", "[", "]", ",",
"+", "-", "/", "*",
"==", "!=", "^", ">=", "<=", ">", "<",
};
auto string_tokens = std::vector<std::string>{};
for (const std::string& deck_item : deck_data) { for (const std::string& deck_item : deck_data) {
for (const std::string& item : quote_split(deck_item)) { for (const std::string& item : quote_split(deck_item)) {
if (RawConsts::is_quote()(item[0])) { if (RawConsts::is_quote()(item[0])) {
@ -186,26 +239,35 @@ UDQDefine::UDQDefine(const UDQParams& udq_params,
continue; continue;
} }
const std::vector<std::string> splitters = {" ", "TU*[]", "(", ")", "[", "]", ",", "+", "-", "/", "*", "==", "!=", "^", ">=", "<=", ">", "<"}; std::size_t offset = 0;
size_t offset = 0;
while (offset < item.size()) { while (offset < item.size()) {
auto token = next_token(item, offset, splitters); auto token = next_token(item, offset, splitters);
if (!token.empty()) if (!token.empty()) {
string_tokens.push_back( token ); string_tokens.push_back(std::move(token));
}
} }
} }
} }
this->m_tokens = make_tokens(string_tokens); 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->ast = std::make_shared<UDQASTNode>
(UDQParser::parse(udq_params,
this->m_var_type,
this->m_keyword,
this->m_location,
this->m_tokens,
parseContext,
errors));
} }
void UDQDefine::update_status(UDQUpdate update, std::size_t report_step) { void UDQDefine::update_status(const UDQUpdate update,
const std::size_t report_step)
{
this->m_update_status = update; this->m_update_status = update;
this->m_report_step = report_step; this->m_report_step = report_step;
} }
UDQDefine UDQDefine::serializationTestObject() UDQDefine UDQDefine::serializationTestObject()
{ {
UDQDefine result; UDQDefine result;
@ -219,76 +281,63 @@ UDQDefine UDQDefine::serializationTestObject()
return result; return result;
} }
void UDQDefine::required_summary(std::unordered_set<std::string>& summary_keys) const
namespace { {
/*
This function unconditinally returns true and is of-course quite useless at
the moment; it is retained here in the hope that it is possible to actually
make it useful in the future. See the comment in UDQEnums.hpp about 'UDQ type
system'.
*/
bool dynamic_type_check(UDQVarType lhs, UDQVarType rhs) {
if (lhs == rhs)
return true;
if (rhs == UDQVarType::SCALAR)
return true;
return true;
}
}
void UDQDefine::required_summary(std::unordered_set<std::string>& summary_keys) const {
this->ast->required_summary(summary_keys); this->ast->required_summary(summary_keys);
} }
UDQSet UDQDefine::eval(const UDQContext& context) const { UDQSet UDQDefine::eval(const UDQContext& context) const
{
std::optional<UDQSet> res; std::optional<UDQSet> res;
try { try {
res = this->ast->eval(this->m_var_type, context); res = this->ast->eval(this->m_var_type, context);
res->name( this->m_keyword ); res->name(this->m_keyword);
if (!dynamic_type_check(this->var_type(), res->var_type())) { if (!dynamic_type_check(this->var_type(), res->var_type())) {
std::string msg = "Invalid runtime type conversion detected when evaluating UDQ"; throw std::invalid_argument {
throw std::invalid_argument(msg); "Invalid runtime type conversion detected when evaluating UDQ"
};
} }
} catch (const std::exception& exc) { }
auto msg = fmt::format("Problem evaluating UDQ {}\n" catch (const std::exception& exc) {
"In {} line {}\n" const auto msg = fmt::format("Problem evaluating UDQ {}\n"
"Internal error: {}", this->m_keyword, this->m_location.filename, this->m_location.lineno, exc.what()); "In {} line {}\n"
"Internal error: {}",
this->m_keyword,
this->m_location.filename,
this->m_location.lineno,
exc.what());
OpmLog::error(msg); OpmLog::error(msg);
std::throw_with_nested(exc); std::throw_with_nested(exc);
} }
if (!res)
throw std::logic_error("Bug in UDQDefine::eval()");
if (!res) {
throw std::logic_error("Bug in UDQDefine::eval()");
}
if (res->var_type() == UDQVarType::SCALAR) { if (res->var_type() == UDQVarType::SCALAR) {
/* // If the right hand side evaluates to a scalar that scalar value
If the right hand side evaluates to a scalar that scalar value should // should be set for all wells in the wellset:
be set for all wells in the wellset: //
// UDQ
// DEFINE WUINJ1 SUM(WOPR) * 1.25 /
// DEFINE WUINJ2 WOPR OP1 * 5.0 /
// /
//
// Both the expressions "SUM(WOPR)" and "WOPR OP1" evaluate to a
// scalar, this should then be copied all wells, so that
// WUINJ1:$WELL should evaulate to the same numerical value for all
// wells. We implement the same behavior for group sets - but there
// is lots of uncertainty regarding the semantics of group sets.
UDQ const auto& scalar_value = (*res)[0].value();
DEFINE WUINJ1 SUM(WOPR) * 1.25 /
DEFINE WUINJ2 WOPR OP1 * 5.0 /
/
Both the expressions "SUM(WOPR)" and "WOPR OP1" evaluate to a scalar,
this should then be copied all wells, so that WUINJ1:$WELL should
evaulate to the same numerical value for all wells. We implement the
same behavior for group sets - but there is lots of uncertainty
regarding the semantics of group sets.
*/
const auto& scalar_value = res->operator[](0).value();
if (this->var_type() == UDQVarType::WELL_VAR) { if (this->var_type() == UDQVarType::WELL_VAR) {
const std::vector<std::string> wells = context.wells(); const std::vector<std::string> wells = context.wells();
UDQSet well_res = UDQSet::wells(this->m_keyword, wells); UDQSet well_res = UDQSet::wells(this->m_keyword, wells);
for (const auto& well : wells) for (const auto& well : wells) {
well_res.assign(well, scalar_value); well_res.assign(well, scalar_value);
}
return well_res; return well_res;
} }
@ -297,8 +346,9 @@ UDQSet UDQDefine::eval(const UDQContext& context) const {
const std::vector<std::string> groups = context.groups(); const std::vector<std::string> groups = context.groups();
UDQSet group_res = UDQSet::groups(this->m_keyword, groups); UDQSet group_res = UDQSet::groups(this->m_keyword, groups);
for (const auto& group : groups) for (const auto& group : groups) {
group_res.assign(group, scalar_value); group_res.assign(group, scalar_value);
}
return group_res; return group_res;
} }
@ -307,72 +357,85 @@ UDQSet UDQDefine::eval(const UDQContext& context) const {
return *res; return *res;
} }
const KeywordLocation& UDQDefine::location() const { const KeywordLocation& UDQDefine::location() const
{
return this->m_location; return this->m_location;
} }
UDQVarType UDQDefine::var_type() const { UDQVarType UDQDefine::var_type() const
{
return this->m_var_type; return this->m_var_type;
} }
const std::string& UDQDefine::keyword() const
const std::string& UDQDefine::keyword() const { {
return this->m_keyword; return this->m_keyword;
} }
const std::string& UDQDefine::input_string() const { const std::string& UDQDefine::input_string() const
{
if (!this->string_data.has_value()) { if (!this->string_data.has_value()) {
std::string s; std::string s;
/*
A string representation equivalent to the input string is assembled by // A string representation equivalent to the input string is
joining tokens and sprinkle with ' ' at semi random locations. The // assembled by joining tokens and sprinkle with ' ' at semi random
main use of this function is to output the definition string in form // locations. The main use of this function is to output the
usable for the restart file. // definition string in form usable for the restart file.
*/
for (std::size_t token_index = 0; token_index < this->m_tokens.size(); token_index++) { for (std::size_t token_index = 0; token_index < this->m_tokens.size(); token_index++) {
const auto& token = this->m_tokens[token_index]; const auto& token = this->m_tokens[token_index];
if (UDQ::leadingSpace(token.type())) if (UDQ::leadingSpace(token.type())) {
s += " "; s += " ";
}
s += token.str(); s += token.str();
if (token_index == (this->m_tokens.size() - 1)) if (token_index == (this->m_tokens.size() - 1)) {
continue; continue;
}
if (UDQ::trailingSpace(token.type())) { if (UDQ::trailingSpace(token.type())) {
s += " "; s += " ";
continue; continue;
} }
} }
this->string_data = s;
this->string_data = s;
} }
return this->string_data.value(); return this->string_data.value();
} }
std::set<UDQTokenType> UDQDefine::func_tokens() const { std::set<UDQTokenType> UDQDefine::func_tokens() const
{
return this->ast->func_tokens(); return this->ast->func_tokens();
} }
std::pair<UDQUpdate, std::size_t> UDQDefine::status() const { std::pair<UDQUpdate, std::size_t> UDQDefine::status() const
{
return std::make_pair(this->m_update_status, this->m_report_step); return std::make_pair(this->m_update_status, this->m_report_step);
} }
const std::vector<UDQToken> UDQDefine::tokens() const { const std::vector<UDQToken> UDQDefine::tokens() const
{
return this->m_tokens; return this->m_tokens;
} }
bool UDQDefine::operator==(const UDQDefine& data) const { bool UDQDefine::operator==(const UDQDefine& data) const
if ((ast && !data.ast) || (!ast && data.ast)) {
return false; if ((ast && !data.ast) || (!ast && data.ast)) {
if (ast && !(*ast == *data.ast))
return false; return false;
}
return this->keyword() == data.keyword() && if (ast && !(*ast == *data.ast)) {
this->m_location == data.location() && return false;
this->var_type() == data.var_type() && }
this->status() == data.status() &&
this->input_string() == data.input_string(); return (this->keyword() == data.keyword())
&& (this->m_location == data.location())
&& (this->var_type() == data.var_type())
&& (this->status() == data.status())
&& (this->input_string() == data.input_string())
;
} }
} } // namespace Opm

View File

@ -28,367 +28,407 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
namespace Opm { namespace UDQ {
namespace { namespace {
const std::set<UDQTokenType> cmp_func = {UDQTokenType::binary_cmp_eq, bool is_no_mix(const Opm::UDQVarType t)
UDQTokenType::binary_cmp_ne, {
UDQTokenType::binary_cmp_le, return (t == Opm::UDQVarType::CONNECTION_VAR)
UDQTokenType::binary_cmp_ge, || (t == Opm::UDQVarType::REGION_VAR)
UDQTokenType::binary_cmp_lt, || (t == Opm::UDQVarType::SEGMENT_VAR)
UDQTokenType::binary_cmp_gt}; || (t == Opm::UDQVarType::AQUIFER_VAR)
|| (t == Opm::UDQVarType::BLOCK_VAR)
|| (t == Opm::UDQVarType::WELL_VAR)
|| (t == Opm::UDQVarType::GROUP_VAR)
;
}
const std::set<UDQTokenType> binary_func = {UDQTokenType::binary_op_add, bool is_valid_vartype(const Opm::UDQVarType t)
UDQTokenType::binary_op_mul, {
UDQTokenType::binary_op_sub, return is_no_mix(t)
UDQTokenType::binary_op_div, || (t == Opm::UDQVarType::NONE)
UDQTokenType::binary_op_pow, || (t == Opm::UDQVarType::SCALAR)
UDQTokenType::binary_op_uadd, || (t == Opm::UDQVarType::FIELD_VAR)
UDQTokenType::binary_op_umul, ;
UDQTokenType::binary_op_umin, }
UDQTokenType::binary_op_umax,
UDQTokenType::binary_cmp_eq,
UDQTokenType::binary_cmp_ne,
UDQTokenType::binary_cmp_le,
UDQTokenType::binary_cmp_ge,
UDQTokenType::binary_cmp_lt,
UDQTokenType::binary_cmp_gt};
const std::set<UDQTokenType> set_func = {UDQTokenType::binary_op_uadd, const auto cmp_func = std::set<Opm::UDQTokenType> {
UDQTokenType::binary_op_umul, Opm::UDQTokenType::binary_cmp_eq,
UDQTokenType::binary_op_umin, Opm::UDQTokenType::binary_cmp_ne,
UDQTokenType::binary_op_umax}; Opm::UDQTokenType::binary_cmp_le,
Opm::UDQTokenType::binary_cmp_ge,
Opm::UDQTokenType::binary_cmp_lt,
Opm::UDQTokenType::binary_cmp_gt,
};
const std::set<UDQTokenType> scalar_func = {UDQTokenType::scalar_func_sum, const auto binary_func = std::set<Opm::UDQTokenType> {
UDQTokenType::scalar_func_avea, Opm::UDQTokenType::binary_op_add,
UDQTokenType::scalar_func_aveg, Opm::UDQTokenType::binary_op_mul,
UDQTokenType::scalar_func_aveh, Opm::UDQTokenType::binary_op_sub,
UDQTokenType::scalar_func_max, Opm::UDQTokenType::binary_op_div,
UDQTokenType::scalar_func_min, Opm::UDQTokenType::binary_op_pow,
UDQTokenType::scalar_func_norm1, Opm::UDQTokenType::binary_op_uadd,
UDQTokenType::scalar_func_norm2, Opm::UDQTokenType::binary_op_umul,
UDQTokenType::scalar_func_normi, Opm::UDQTokenType::binary_op_umin,
UDQTokenType::scalar_func_prod}; Opm::UDQTokenType::binary_op_umax,
Opm::UDQTokenType::binary_cmp_eq,
Opm::UDQTokenType::binary_cmp_ne,
Opm::UDQTokenType::binary_cmp_le,
Opm::UDQTokenType::binary_cmp_ge,
Opm::UDQTokenType::binary_cmp_lt,
Opm::UDQTokenType::binary_cmp_gt,
};
const auto set_func = std::set<Opm::UDQTokenType> {
Opm::UDQTokenType::binary_op_uadd,
Opm::UDQTokenType::binary_op_umul,
Opm::UDQTokenType::binary_op_umin,
Opm::UDQTokenType::binary_op_umax,
};
const std::set<UDQTokenType> unary_elemental_func = {UDQTokenType::elemental_func_randn, const auto scalar_func = std::set<Opm::UDQTokenType> {
UDQTokenType::elemental_func_randu, Opm::UDQTokenType::scalar_func_sum,
UDQTokenType::elemental_func_rrandn, Opm::UDQTokenType::scalar_func_avea,
UDQTokenType::elemental_func_rrandu, Opm::UDQTokenType::scalar_func_aveg,
UDQTokenType::elemental_func_abs, Opm::UDQTokenType::scalar_func_aveh,
UDQTokenType::elemental_func_def, Opm::UDQTokenType::scalar_func_max,
UDQTokenType::elemental_func_exp, Opm::UDQTokenType::scalar_func_min,
UDQTokenType::elemental_func_idv, Opm::UDQTokenType::scalar_func_norm1,
UDQTokenType::elemental_func_ln, Opm::UDQTokenType::scalar_func_norm2,
UDQTokenType::elemental_func_log, Opm::UDQTokenType::scalar_func_normi,
UDQTokenType::elemental_func_nint, Opm::UDQTokenType::scalar_func_prod,
UDQTokenType::elemental_func_sorta, };
UDQTokenType::elemental_func_sortd,
UDQTokenType::elemental_func_undef};
const auto unary_elemental_func = std::set<Opm::UDQTokenType> {
Opm::UDQTokenType::elemental_func_randn,
Opm::UDQTokenType::elemental_func_randu,
Opm::UDQTokenType::elemental_func_rrandn,
Opm::UDQTokenType::elemental_func_rrandu,
Opm::UDQTokenType::elemental_func_abs,
Opm::UDQTokenType::elemental_func_def,
Opm::UDQTokenType::elemental_func_exp,
Opm::UDQTokenType::elemental_func_idv,
Opm::UDQTokenType::elemental_func_ln,
Opm::UDQTokenType::elemental_func_log,
Opm::UDQTokenType::elemental_func_nint,
Opm::UDQTokenType::elemental_func_sorta,
Opm::UDQTokenType::elemental_func_sortd,
Opm::UDQTokenType::elemental_func_undef,
};
const std::unordered_map<std::string, UDQTokenType> func_type = {{"+", UDQTokenType::binary_op_add}, const auto func_type = std::unordered_map<std::string, Opm::UDQTokenType> {
{"-", UDQTokenType::binary_op_sub}, {"+" , Opm::UDQTokenType::binary_op_add},
{"/", UDQTokenType::binary_op_div}, {"-" , Opm::UDQTokenType::binary_op_sub},
{"DIV", UDQTokenType::binary_op_div}, {"/" , Opm::UDQTokenType::binary_op_div},
{"*", UDQTokenType::binary_op_mul}, {"DIV" , Opm::UDQTokenType::binary_op_div},
{"^", UDQTokenType::binary_op_pow}, {"*" , Opm::UDQTokenType::binary_op_mul},
{"UADD", UDQTokenType::binary_op_uadd}, {"^" , Opm::UDQTokenType::binary_op_pow},
{"UMUL", UDQTokenType::binary_op_umul}, {"UADD" , Opm::UDQTokenType::binary_op_uadd},
{"UMIN", UDQTokenType::binary_op_umin}, {"UMUL" , Opm::UDQTokenType::binary_op_umul},
{"UMAX", UDQTokenType::binary_op_umax}, {"UMIN" , Opm::UDQTokenType::binary_op_umin},
{"==", UDQTokenType::binary_cmp_eq}, {"UMAX" , Opm::UDQTokenType::binary_op_umax},
{"!=", UDQTokenType::binary_cmp_ne}, {"==" , Opm::UDQTokenType::binary_cmp_eq},
{"<=", UDQTokenType::binary_cmp_le}, {"!=" , Opm::UDQTokenType::binary_cmp_ne},
{">=", UDQTokenType::binary_cmp_ge}, {"<=" , Opm::UDQTokenType::binary_cmp_le},
{"<", UDQTokenType::binary_cmp_lt}, {">=" , Opm::UDQTokenType::binary_cmp_ge},
{">", UDQTokenType::binary_cmp_gt}, {"<" , Opm::UDQTokenType::binary_cmp_lt},
{"RANDN", UDQTokenType::elemental_func_randn}, {">" , Opm::UDQTokenType::binary_cmp_gt},
{"RANDU", UDQTokenType::elemental_func_randu}, {"RANDN", Opm::UDQTokenType::elemental_func_randn},
{"RRNDN", UDQTokenType::elemental_func_rrandn}, {"RANDU", Opm::UDQTokenType::elemental_func_randu},
{"RRNDU", UDQTokenType::elemental_func_rrandu}, {"RRNDN", Opm::UDQTokenType::elemental_func_rrandn},
{"ABS", UDQTokenType::elemental_func_abs}, {"RRNDU", Opm::UDQTokenType::elemental_func_rrandu},
{"DEF", UDQTokenType::elemental_func_def}, {"ABS" , Opm::UDQTokenType::elemental_func_abs},
{"EXP", UDQTokenType::elemental_func_exp}, {"DEF" , Opm::UDQTokenType::elemental_func_def},
{"IDV", UDQTokenType::elemental_func_idv}, {"EXP" , Opm::UDQTokenType::elemental_func_exp},
{"LN", UDQTokenType::elemental_func_ln}, {"IDV" , Opm::UDQTokenType::elemental_func_idv},
{"LOG", UDQTokenType::elemental_func_log}, {"LN" , Opm::UDQTokenType::elemental_func_ln},
{"NINT", UDQTokenType::elemental_func_nint}, {"LOG" , Opm::UDQTokenType::elemental_func_log},
{"SORTA", UDQTokenType::elemental_func_sorta}, {"NINT" , Opm::UDQTokenType::elemental_func_nint},
{"SORTD", UDQTokenType::elemental_func_sortd}, {"SORTA", Opm::UDQTokenType::elemental_func_sorta},
{"UNDEF", UDQTokenType::elemental_func_undef}, {"SORTD", Opm::UDQTokenType::elemental_func_sortd},
{"SUM", UDQTokenType::scalar_func_sum}, {"UNDEF", Opm::UDQTokenType::elemental_func_undef},
{"AVEA", UDQTokenType::scalar_func_avea}, {"SUM" , Opm::UDQTokenType::scalar_func_sum},
{"AVEG", UDQTokenType::scalar_func_aveg}, {"AVEA" , Opm::UDQTokenType::scalar_func_avea},
{"AVEH", UDQTokenType::scalar_func_aveh}, {"AVEG" , Opm::UDQTokenType::scalar_func_aveg},
{"MAX", UDQTokenType::scalar_func_max}, {"AVEH" , Opm::UDQTokenType::scalar_func_aveh},
{"MIN", UDQTokenType::scalar_func_min}, {"MAX" , Opm::UDQTokenType::scalar_func_max},
{"NORM1", UDQTokenType::scalar_func_norm1}, {"MIN" , Opm::UDQTokenType::scalar_func_min},
{"NORM2", UDQTokenType::scalar_func_norm2}, {"NORM1", Opm::UDQTokenType::scalar_func_norm1},
{"NORMI", UDQTokenType::scalar_func_normi}, {"NORM2", Opm::UDQTokenType::scalar_func_norm2},
{"PROD", UDQTokenType::scalar_func_prod}}; {"NORMI", Opm::UDQTokenType::scalar_func_normi},
{"PROD" , Opm::UDQTokenType::scalar_func_prod},
};
} // Anonymous namespace
} namespace Opm { namespace UDQ {
UDQVarType targetType(const std::string& keyword) { UDQVarType targetType(const std::string& keyword)
{
const char first_char = keyword[0];
switch (first_char) {
case 'C': return UDQVarType::CONNECTION_VAR;
case 'R': return UDQVarType::REGION_VAR;
case 'F': return UDQVarType::FIELD_VAR;
case 'S': return UDQVarType::SEGMENT_VAR;
case 'A': return UDQVarType::AQUIFER_VAR;
case 'B': return UDQVarType::BLOCK_VAR;
case 'W': return UDQVarType::WELL_VAR;
case 'G': return UDQVarType::GROUP_VAR;
char first_char = keyword[0];
switch(first_char) {
case 'C':
return UDQVarType::CONNECTION_VAR;
case 'R':
return UDQVarType::REGION_VAR;
case 'F':
return UDQVarType::FIELD_VAR;
case 'S':
return UDQVarType::SEGMENT_VAR;
case 'A':
return UDQVarType::AQUIFER_VAR;
case 'B':
return UDQVarType::BLOCK_VAR;
case 'W':
return UDQVarType::WELL_VAR;
case 'G':
return UDQVarType::GROUP_VAR;
default: default:
const auto& double_value = try_parse_double(keyword); if (const auto double_value = try_parse_double(keyword);
if (double_value.has_value()) double_value.has_value())
{
return UDQVarType::SCALAR; return UDQVarType::SCALAR;
}
return UDQVarType::NONE; return UDQVarType::NONE;
} }
} }
UDQVarType targetType(const std::string& keyword, const std::vector<std::string>& selector) { UDQVarType targetType(const std::string& keyword,
auto tt = targetType(keyword); const std::vector<std::string>& selector)
{
if (tt == UDQVarType::WELL_VAR || tt == UDQVarType::GROUP_VAR) { const auto tt = targetType(keyword);
if (selector.empty()) if ((tt == UDQVarType::WELL_VAR) || (tt == UDQVarType::GROUP_VAR)) {
if (selector.empty() || (selector.front().find("*") != std::string::npos)) {
return tt; return tt;
else {
const auto& wgname = selector[0];
if (wgname.find("*") != std::string::npos)
return tt;
} }
} }
return UDQVarType::SCALAR; return UDQVarType::SCALAR;
} }
UDQVarType varType(const std::string& keyword)
{
if ((keyword.size() < std::string::size_type{2}) || (keyword[1] != 'U')) {
throw std::invalid_argument("Keyword: '" + keyword + "' is not of UDQ type");
}
UDQVarType varType(const std::string& keyword) { const char first_char = keyword[0];
if (keyword[1] != 'U') switch (first_char) {
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type"); case 'W': return UDQVarType::WELL_VAR;
case 'G': return UDQVarType::GROUP_VAR;
case 'C': return UDQVarType::CONNECTION_VAR;
case 'R': return UDQVarType::REGION_VAR;
case 'F': return UDQVarType::FIELD_VAR;
case 'S': return UDQVarType::SEGMENT_VAR;
case 'A': return UDQVarType::AQUIFER_VAR;
case 'B': return UDQVarType::BLOCK_VAR;
char first_char = keyword[0];
switch(first_char) {
case 'W':
return UDQVarType::WELL_VAR;
case 'G':
return UDQVarType::GROUP_VAR;
case 'C':
return UDQVarType::CONNECTION_VAR;
case 'R':
return UDQVarType::REGION_VAR;
case 'F':
return UDQVarType::FIELD_VAR;
case 'S':
return UDQVarType::SEGMENT_VAR;
case 'A':
return UDQVarType::AQUIFER_VAR;
case 'B':
return UDQVarType::BLOCK_VAR;
default: default:
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type"); throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type");
} }
} }
UDQAction actionType(const std::string& action_string)
UDQAction actionType(const std::string& action_string) { {
if (action_string == "ASSIGN") if (action_string == "ASSIGN") {
return UDQAction::ASSIGN; return UDQAction::ASSIGN;
}
if (action_string == "DEFINE") if (action_string == "DEFINE") {
return UDQAction::DEFINE; return UDQAction::DEFINE;
}
if (action_string == "UNITS") if (action_string == "UNITS") {
return UDQAction::UNITS; return UDQAction::UNITS;
}
if (action_string == "UPDATE") if (action_string == "UPDATE") {
return UDQAction::UPDATE; return UDQAction::UPDATE;
}
throw std::invalid_argument("Invalid action string " + action_string); throw std::invalid_argument("Invalid action string " + action_string);
} }
UDQUpdate updateType(const std::string& update_string)
UDQUpdate updateType(const std::string& update_string) { {
if (update_string == "ON") if (update_string == "ON") {
return UDQUpdate::ON; return UDQUpdate::ON;
}
if (update_string == "OFF") if (update_string == "OFF") {
return UDQUpdate::OFF; return UDQUpdate::OFF;
}
if (update_string == "NEXT") if (update_string == "NEXT") {
return UDQUpdate::NEXT; return UDQUpdate::NEXT;
}
throw std::invalid_argument("Invalid status update string " + update_string); throw std::invalid_argument("Invalid status update string " + update_string);
} }
UDQUpdate updateType(int int_value) { UDQUpdate updateType(const int int_value)
{
switch (int_value) { switch (int_value) {
case 0: return UDQUpdate::OFF; case 0: return UDQUpdate::OFF;
case 1: return UDQUpdate::NEXT; case 1: return UDQUpdate::NEXT;
case 2: return UDQUpdate::ON; case 2: return UDQUpdate::ON;
default: default:
throw std::logic_error("Invalid integer for UDQUpdate type"); throw std::logic_error("Invalid integer for UDQUpdate type");
} }
} }
bool binaryFunc(const UDQTokenType token_type)
bool binaryFunc(UDQTokenType token_type) { {
return (binary_func.count(token_type) > 0); return binary_func.find(token_type) != binary_func.end();
} }
bool scalarFunc(UDQTokenType token_type) { bool scalarFunc(const UDQTokenType token_type)
return (scalar_func.count(token_type) > 0); {
return scalar_func.find(token_type) != scalar_func.end();
} }
bool elementalUnaryFunc(UDQTokenType token_type) { bool elementalUnaryFunc(const UDQTokenType token_type)
return (unary_elemental_func.count(token_type) > 0); {
return unary_elemental_func.find(token_type) != unary_elemental_func.end();
} }
bool cmpFunc(UDQTokenType token_type) { bool cmpFunc(const UDQTokenType token_type)
return (cmp_func.count(token_type) > 0); {
return cmp_func.find(token_type) != cmp_func.end();
} }
bool setFunc(UDQTokenType token_type) { bool setFunc(const UDQTokenType token_type)
return (set_func.count(token_type) > 0); {
return set_func.find(token_type) != set_func.end();
} }
UDQTokenType funcType(const std::string& func_name)
{
{
auto func = func_type.find(func_name);
if (func != func_type.end()) {
return func->second;
}
}
UDQTokenType funcType(const std::string& func_name) { if (func_name.substr(0, 2) == "TU") {
if (func_type.count(func_name) > 0)
return func_type.at(func_name);
if (func_name.substr(0,2) == "TU") {
return UDQTokenType::table_lookup; return UDQTokenType::table_lookup;
} }
return UDQTokenType::error; return UDQTokenType::error;
} }
UDQTokenType tokenType(const std::string& token) { UDQTokenType tokenType(const std::string& token)
auto token_type = funcType(token); {
if (token_type == UDQTokenType::error) { if (const auto token_type = funcType(token);
if (token == "(") token_type != UDQTokenType::error)
token_type = UDQTokenType::open_paren; {
else if (token == ")") return token_type;
token_type = UDQTokenType::close_paren;
else {
auto value = try_parse_double(token);
if (value.has_value())
token_type = UDQTokenType::number;
else
token_type = UDQTokenType::ecl_expr;
}
} }
return token_type;
if (token == "(") {
return UDQTokenType::open_paren;
}
if (token == ")") {
return UDQTokenType::close_paren;
}
if (const auto number = try_parse_double(token);
number.has_value())
{
return UDQTokenType::number;
}
return UDQTokenType::ecl_expr;
} }
UDQVarType coerce(const UDQVarType t1, const UDQVarType t2)
{
if (! (is_valid_vartype(t1) && is_valid_vartype(t2))) {
// Note: Can't use typeName() here since that would throw another
// exception.
throw std::logic_error {
"Cannot coerce between " + std::to_string(static_cast<int>(t1))
+ " and " + std::to_string(static_cast<int>(t2))
};
}
UDQVarType coerce(UDQVarType t1, UDQVarType t2) { if (t1 == t2) {
if (t1 == t2)
return t1;
if (t1 == UDQVarType::WELL_VAR ) {
if (t2 == UDQVarType::GROUP_VAR)
throw std::logic_error("Can not coerce well variable and group variable");
return t1; return t1;
} }
if (t1 == UDQVarType::GROUP_VAR ) { const auto is_restricted_t1 = is_no_mix(t1);
if (t2 == UDQVarType::WELL_VAR) const auto is_restricted_t2 = is_no_mix(t2);
throw std::logic_error("Can not coerce well variable and group variable");
if (is_restricted_t1 && is_restricted_t2) {
// t1 != t2, but neither can be coerced into the other.
throw std::logic_error {
"Cannot coerce between " + typeName(t1) + " and " + typeName(t2)
};
}
if (is_restricted_t1) {
return t1; return t1;
} }
if (t2 == UDQVarType::WELL_VAR ) { if (is_restricted_t2) {
if (t1 == UDQVarType::GROUP_VAR)
throw std::logic_error("Can not coerce well variable and group variable");
return t2; return t2;
} }
if (t2 == UDQVarType::GROUP_VAR ) { if (t1 == UDQVarType::NONE) {
if (t1 == UDQVarType::WELL_VAR)
throw std::logic_error("Can not coerce well variable and group variable");
return t2; return t2;
} }
if (t1 == UDQVarType::NONE) if (t2 == UDQVarType::NONE) {
return t2;
if (t2 == UDQVarType::NONE)
return t1; return t1;
}
return t1; return t1;
} }
std::string typeName(const UDQVarType var_type)
{
std::string typeName(UDQVarType var_type) {
switch (var_type) { switch (var_type) {
case UDQVarType::NONE: case UDQVarType::NONE:
return "NONE"; return "NONE";
case UDQVarType::SCALAR: case UDQVarType::SCALAR:
return "SCALAR"; return "SCALAR";
case UDQVarType::WELL_VAR: case UDQVarType::WELL_VAR:
return "WELL_VAR"; return "WELL_VAR";
case UDQVarType::CONNECTION_VAR: case UDQVarType::CONNECTION_VAR:
return "CONNECTION_VAR"; return "CONNECTION_VAR";
case UDQVarType::FIELD_VAR: case UDQVarType::FIELD_VAR:
return "FIELD_VAR"; return "FIELD_VAR";
case UDQVarType::GROUP_VAR: case UDQVarType::GROUP_VAR:
return "GROUP_VAR"; return "GROUP_VAR";
case UDQVarType::REGION_VAR: case UDQVarType::REGION_VAR:
return "REGION_VAR"; return "REGION_VAR";
case UDQVarType::SEGMENT_VAR: case UDQVarType::SEGMENT_VAR:
return "SEGMENT_VAR"; return "SEGMENT_VAR";
case UDQVarType::AQUIFER_VAR: case UDQVarType::AQUIFER_VAR:
return "AQUIFER_VAR"; return "AQUIFER_VAR";
case UDQVarType::BLOCK_VAR: case UDQVarType::BLOCK_VAR:
return "BLOCK_VAR"; return "BLOCK_VAR";
default: default:
throw std::runtime_error("Should not be here: " + std::to_string(static_cast<int>(var_type))); throw std::runtime_error("Should not be here: " + std::to_string(static_cast<int>(var_type)));
} }
} }
bool trailingSpace(UDQTokenType token_type) { bool trailingSpace(const UDQTokenType token_type)
if (binaryFunc(token_type)) {
return true; return binaryFunc(token_type)
|| cmpFunc(token_type);
if (cmpFunc(token_type))
return true;
return false;
} }
bool leadingSpace(UDQTokenType token_type) { bool leadingSpace(const UDQTokenType token_type)
if (binaryFunc(token_type)) {
return true; return binaryFunc(token_type)
|| cmpFunc(token_type);
if (cmpFunc(token_type))
return true;
return false;
} }
namespace { namespace {
@ -401,7 +441,7 @@ namespace {
throw std::logic_error { throw std::logic_error {
"Unrecognized enum type (" + "Unrecognized enum type (" +
std::to_string(static_cast<int>(control)) + std::to_string(static_cast<int>(control)) +
"- internal error" ") - internal error"
}; };
} }
@ -683,5 +723,4 @@ std::string controlName(const UDAControl control)
}; };
} }
}} // namespace Opm::UDQ
}} // Opm::UDQ

View File

@ -17,78 +17,91 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp> #include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
#include <stdexcept>
#include <string>
#include <variant>
namespace Opm { namespace Opm {
UDQInput::UDQInput(const UDQIndex& index_arg,
UDQInput::UDQInput(const UDQIndex& index_arg, const UDQDefine& udq_define, const std::string& unit_arg) : const UDQDefine& udq_define,
index(index_arg), const std::string& unit_arg)
value(udq_define), : index (index_arg)
m_keyword(udq_define.keyword()), , value (udq_define)
m_var_type(udq_define.var_type()), , m_keyword (udq_define.keyword())
m_unit(unit_arg) , m_var_type(udq_define.var_type())
, m_unit (unit_arg)
{} {}
UDQInput::UDQInput(const UDQIndex& index_arg,
UDQInput::UDQInput(const UDQIndex& index_arg, const UDQAssign& udq_assign, const std::string& unit_arg): const UDQAssign& udq_assign,
index(index_arg), const std::string& unit_arg)
value(udq_assign), : index (index_arg)
m_keyword(udq_assign.keyword()), , value (udq_assign)
m_var_type(udq_assign.var_type()), , m_keyword (udq_assign.keyword())
m_unit(unit_arg) , m_var_type(udq_assign.var_type())
, m_unit (unit_arg)
{} {}
const std::string& UDQInput::unit() const { const std::string& UDQInput::unit() const
{
return this->m_unit; return this->m_unit;
} }
const std::string& UDQInput::keyword() const { const std::string& UDQInput::keyword() const
{
return this->m_keyword; return this->m_keyword;
} }
const UDQVarType& UDQInput::var_type() const { const UDQVarType& UDQInput::var_type() const
{
return this->m_var_type; return this->m_var_type;
} }
template<> template<>
bool UDQInput::is<UDQAssign>() const { bool UDQInput::is<UDQAssign>() const
{
return std::holds_alternative<UDQAssign>(this->value); return std::holds_alternative<UDQAssign>(this->value);
} }
template<> template<>
bool UDQInput::is<UDQDefine>() const { bool UDQInput::is<UDQDefine>() const
{
return std::holds_alternative<UDQDefine>(this->value); return std::holds_alternative<UDQDefine>(this->value);
} }
template<> template<>
const UDQAssign& UDQInput::get<UDQAssign>() const { const UDQAssign& UDQInput::get<UDQAssign>() const
if (this->is<UDQAssign>()) {
if (this->is<UDQAssign>()) {
return std::get<UDQAssign>(this->value); return std::get<UDQAssign>(this->value);
}
throw std::runtime_error("Invalid get"); throw std::runtime_error("Invalid get");
} }
template<> template<>
const UDQDefine& UDQInput::get<UDQDefine>() const { const UDQDefine& UDQInput::get<UDQDefine>() const
if (this->is<UDQDefine>()) {
if (this->is<UDQDefine>()) {
return std::get<UDQDefine>(this->value); return std::get<UDQDefine>(this->value);
}
throw std::runtime_error("Invalid get"); throw std::runtime_error("Invalid get");
} }
bool UDQInput::operator==(const UDQInput& other) const
bool UDQInput::operator==(const UDQInput& other) const { {
return this->value == other.value && return (this->value == other.value)
this->m_keyword == other.m_keyword && && (this->m_keyword == other.m_keyword)
this->m_var_type == other.m_var_type && && (this->m_var_type == other.m_var_type)
this->m_unit == other.m_unit; && (this->m_unit == other.m_unit)
;
} }
} // namespace Opm
}

View File

@ -17,77 +17,131 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <iostream> #include "UDQParser.hpp"
#include <cstring>
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include <opm/input/eclipse/Parser/ParseContext.hpp>
#include <cassert> #include <cassert>
#include <cstddef>
#include <cstring>
#include <iostream>
#include <memory>
#include <fmt/format.h> #include <fmt/format.h>
#include <opm/input/eclipse/Parser/ParseContext.hpp> namespace {
#include <opm/common/OpmLog/KeywordLocation.hpp>
#include "UDQParser.hpp" void dump_tokens(const std::string& target_var,
const std::vector<Opm::UDQToken>& tokens)
{
std::cout << target_var << " = ";
for (const auto& token : tokens) {
std::cout << token.str();
}
std::cout << std::endl;
}
// This function is extremely weak - hopefully it can be improved in the
// future. See the comment in UDQEnums.hpp about 'UDQ type system'.
bool static_type_check(const Opm::UDQVarType lhs,
const Opm::UDQVarType rhs)
{
if (lhs == rhs) {
return true;
}
if (rhs == Opm::UDQVarType::SCALAR) {
return true;
}
// This does not check if the rhs evaluates to a scalar.
if (rhs == Opm::UDQVarType::WELL_VAR) {
return lhs == Opm::UDQVarType::WELL_VAR;
}
return false;
}
} // Anonymous namespace
namespace Opm { namespace Opm {
UDQTokenType UDQParser::get_type(const std::string& arg) const { UDQTokenType UDQParser::get_type(const std::string& arg) const
{
auto func_type = UDQ::funcType(arg); auto func_type = UDQ::funcType(arg);
if (func_type == UDQTokenType::table_lookup) if (func_type == UDQTokenType::table_lookup) {
throw std::invalid_argument("Table lookup function TU*[] is not supported in UDQ"); throw std::invalid_argument {
"Table lookup function TU*[] is not supported in UDQ"
};
}
if (func_type != UDQTokenType::error) if (func_type != UDQTokenType::error) {
return func_type; return func_type;
}
if (arg == "(") if (arg == "(") {
return UDQTokenType::open_paren; return UDQTokenType::open_paren;
}
if (arg == ")") if (arg == ")") {
return UDQTokenType::close_paren; return UDQTokenType::close_paren;
}
{ {
char * end_ptr; char* end_ptr;
std::strtod(arg.c_str(), &end_ptr); std::strtod(arg.c_str(), &end_ptr);
if (std::strlen(end_ptr) == 0) if (std::strlen(end_ptr) == 0) {
return UDQTokenType::number; return UDQTokenType::number;
}
} }
return UDQTokenType::ecl_expr; return UDQTokenType::ecl_expr;
} }
bool UDQParser::empty() const
{
bool UDQParser::empty() const { return static_cast<std::size_t>(this->current_pos) == this->tokens.size();
return (static_cast<size_t>(this->current_pos) == this->tokens.size());
} }
UDQParseNode UDQParser::next() { UDQParseNode UDQParser::next()
{
this->current_pos += 1; this->current_pos += 1;
return this->current(); return this->current();
} }
UDQParseNode UDQParser::current() const
{
UDQParseNode UDQParser::current() const { if (this->empty()) {
if (this->empty())
return UDQTokenType::end; return UDQTokenType::end;
}
const auto& token = this->tokens[current_pos]; const auto& token = this->tokens[current_pos];
if (token.type() == UDQTokenType::number) if (token.type() == UDQTokenType::number) {
return UDQParseNode(UDQTokenType::number, token.value()); return UDQParseNode(UDQTokenType::number, token.value());
}
if (token.type() == UDQTokenType::ecl_expr) if (token.type() == UDQTokenType::ecl_expr) {
return UDQParseNode(UDQTokenType::ecl_expr, token.value(), token.selector()); return UDQParseNode(UDQTokenType::ecl_expr, token.value(), token.selector());
}
return UDQParseNode(this->get_type(std::get<std::string>(token.value())), token.value()); return UDQParseNode(this->get_type(std::get<std::string>(token.value())), token.value());
} }
UDQASTNode UDQParser::parse_factor()
UDQASTNode UDQParser::parse_factor() { {
double sign = 1.0; double sign = 1.0;
auto current = this->current(); auto current = this->current();
if (current.type == UDQTokenType::binary_op_add || current.type == UDQTokenType::binary_op_sub) { if ((current.type == UDQTokenType::binary_op_add) ||
if (current.type == UDQTokenType::binary_op_sub) (current.type == UDQTokenType::binary_op_sub))
{
if (current.type == UDQTokenType::binary_op_sub) {
sign = -1.0; sign = -1.0;
}
this->next(); this->next();
current = this->current(); current = this->current();
} }
@ -98,8 +152,9 @@ UDQASTNode UDQParser::parse_factor() {
auto inner_expr = this->parse_set(); auto inner_expr = this->parse_set();
current = this->current(); current = this->current();
if (current.type != UDQTokenType::close_paren) if (current.type != UDQTokenType::close_paren) {
return UDQASTNode(UDQTokenType::error); return UDQASTNode(UDQTokenType::error);
}
this->next(); this->next();
return sign * inner_expr; return sign * inner_expr;
@ -113,30 +168,37 @@ UDQASTNode UDQParser::parse_factor() {
auto arg_expr = this->parse_set(); auto arg_expr = this->parse_set();
current = this->current(); current = this->current();
if (current.type != UDQTokenType::close_paren) if (current.type != UDQTokenType::close_paren) {
return UDQASTNode(UDQTokenType::error); return UDQASTNode(UDQTokenType::error);
}
this->next(); this->next();
return sign * UDQASTNode(func_node.type, func_node.value, arg_expr); return sign * UDQASTNode(func_node.type, func_node.value, arg_expr);
} else }
else {
return UDQASTNode(UDQTokenType::error); return UDQASTNode(UDQTokenType::error);
}
} }
UDQASTNode node(current.type, current.value, current.selector); UDQASTNode node(current.type, current.value, current.selector);
this->next(); this->next();
return sign * node; return sign * node;
} }
UDQASTNode UDQParser::parse_pow() { UDQASTNode UDQParser::parse_pow()
{
auto left = this->parse_factor(); auto left = this->parse_factor();
if (this->empty()) if (this->empty()) {
return left; return left;
}
auto current = this->current(); auto current = this->current();
if (current.type == UDQTokenType::binary_op_pow) { if (current.type == UDQTokenType::binary_op_pow) {
this->next(); this->next();
if (this->empty()) if (this->empty()) {
return UDQASTNode(UDQTokenType::error); return UDQASTNode(UDQTokenType::error);
}
auto right = this->parse_mul(); auto right = this->parse_mul();
return UDQASTNode(current.type, current.value, left, right); return UDQASTNode(current.type, current.value, left, right);
@ -145,9 +207,8 @@ UDQASTNode UDQParser::parse_pow() {
return left; return left;
} }
UDQASTNode UDQParser::parse_mul()
{
UDQASTNode UDQParser::parse_mul() {
std::vector<UDQASTNode> nodes; std::vector<UDQASTNode> nodes;
{ {
std::unique_ptr<UDQASTNode> current_node; std::unique_ptr<UDQASTNode> current_node;
@ -156,36 +217,48 @@ UDQASTNode UDQParser::parse_mul() {
if (current_node) { if (current_node) {
current_node->set_right(node); current_node->set_right(node);
nodes.push_back(*current_node); nodes.push_back(*current_node);
} else }
else {
nodes.push_back(node); nodes.push_back(node);
}
if (this->empty()) if (this->empty()) {
break; break;
}
auto current_token = this->current(); auto current_token = this->current();
if (current_token.type == UDQTokenType::binary_op_mul || current_token.type == UDQTokenType::binary_op_div) { if ((current_token.type == UDQTokenType::binary_op_mul) ||
current_node.reset( new UDQASTNode(current_token.type, current_token.value) ); (current_token.type == UDQTokenType::binary_op_div))
{
current_node = std::make_unique<UDQASTNode>(current_token.type, current_token.value);
this->next(); this->next();
if (this->empty()) if (this->empty()) {
return UDQASTNode( UDQTokenType::error ); return UDQASTNode( UDQTokenType::error );
} else break; }
}
else {
break;
}
} }
} }
UDQASTNode top_node = nodes.back(); UDQASTNode top_node = nodes.back();
if (nodes.size() > 1) { if (nodes.size() > 1) {
UDQASTNode * current = &top_node; UDQASTNode* current = &top_node;
for (std::size_t index = nodes.size() - 1; index > 0; index--) { for (std::size_t index = nodes.size() - 1; index > 0; index--) {
current->set_left(nodes[index - 1]); current->set_left(nodes[index - 1]);
current = current->get_left(); current = current->get_left();
} }
} }
return top_node; return top_node;
} }
UDQASTNode UDQParser::parse_add()
UDQASTNode UDQParser::parse_add() { {
std::vector<UDQASTNode> nodes; std::vector<UDQASTNode> nodes;
{ {
std::unique_ptr<UDQASTNode> current_node; std::unique_ptr<UDQASTNode> current_node;
while (true) { while (true) {
@ -193,119 +266,117 @@ UDQASTNode UDQParser::parse_add() {
if (current_node) { if (current_node) {
current_node->set_right(node); current_node->set_right(node);
nodes.push_back(*current_node); nodes.push_back(*current_node);
} else }
else {
nodes.push_back(node); nodes.push_back(node);
}
if (this->empty()) if (this->empty()) {
break; break;
}
auto current_token = this->current(); auto current_token = this->current();
if (current_token.type == UDQTokenType::binary_op_add || current_token.type == UDQTokenType::binary_op_sub) { if ((current_token.type == UDQTokenType::binary_op_add) ||
current_node.reset( new UDQASTNode(current_token.type, current_token.value) ); (current_token.type == UDQTokenType::binary_op_sub))
{
current_node = std::make_unique<UDQASTNode>
(current_token.type, current_token.value);
this->next(); this->next();
if (this->empty()) if (this->empty()) {
return UDQASTNode( UDQTokenType::error ); return UDQASTNode(UDQTokenType::error);
} else if (current_token.type == UDQTokenType::close_paren || UDQ::cmpFunc(current_token.type) || UDQ::setFunc(current_token.type)) }
}
else if ((current_token.type == UDQTokenType::close_paren) ||
UDQ::cmpFunc(current_token.type) ||
UDQ::setFunc(current_token.type))
{
break; break;
else }
return UDQASTNode( UDQTokenType::error ); else {
return UDQASTNode(UDQTokenType::error);
}
} }
} }
UDQASTNode top_node = nodes.back(); UDQASTNode top_node = nodes.back();
if (nodes.size() > 1) { if (nodes.size() > 1) {
UDQASTNode * current = &top_node; UDQASTNode* current = &top_node;
for (std::size_t index = nodes.size() - 1; index > 0; index--) { for (std::size_t index = nodes.size() - 1; index > 0; index--) {
current->set_left(nodes[index - 1]); current->set_left(nodes[index - 1]);
current = current->get_left(); current = current->get_left();
} }
} }
return top_node; return top_node;
} }
// A bit uncertain on the presedence of the comparison operators. In normal
// C the comparion operators bind weaker than addition, i.e. for the
// assignment:
//
// auto cmp = a + b < c;
//
// The sum (a+b) is evaluated and then compared with c, that is the order of
// presedence implemented here. But reading the eclipse UDQ manual one can
// get the imporession that the relation operators should bind "very
// strong", i.e. that (b < c) should be evaluated first, and then the
// result of the comparison added to a.
/* UDQASTNode UDQParser::parse_cmp()
A bit uncertain on the presedence of the comparison operators. In normal C the {
comparion operators bind weaker than addition, i.e. for the assignment:
auto cmp = a + b < c;
The sum (a+b) is evaluated and then compared with c, that is the order of
presedence implemented here. But reading the eclipse UDQ manual one can get
the imporession that the relation operators should bind "very strong", i.e.
that (b < c) should be evaluated first, and then the result of the comparison
added to a.
*/
UDQASTNode UDQParser::parse_cmp() {
auto left = this->parse_add(); auto left = this->parse_add();
if (this->empty()) if (this->empty()) {
return left; return left;
}
auto current = this->current(); auto current = this->current();
if (UDQ::cmpFunc(current.type)) { if (UDQ::cmpFunc(current.type)) {
auto func_node = current; auto func_node = current;
this->next(); this->next();
if (this->empty()) if (this->empty()) {
return UDQASTNode(UDQTokenType::error); return UDQASTNode(UDQTokenType::error);
}
auto right = this->parse_cmp(); auto right = this->parse_cmp();
return UDQASTNode(current.type, current.value, left, right); return UDQASTNode(current.type, current.value, left, right);
} }
return left; return left;
} }
UDQASTNode UDQParser::parse_set()
UDQASTNode UDQParser::parse_set() { {
auto left = this->parse_cmp(); auto left = this->parse_cmp();
if (this->empty()) if (this->empty()) {
return left; return left;
}
auto current = this->current(); auto current = this->current();
if (UDQ::setFunc(current.type)) { if (UDQ::setFunc(current.type)) {
auto func_node = current; auto func_node = current;
this->next(); this->next();
if (this->empty()) if (this->empty()) {
return UDQASTNode(UDQTokenType::error); return UDQASTNode(UDQTokenType::error);
}
auto right = this->parse_set(); auto right = this->parse_set();
return UDQASTNode(current.type, current.value, left, right); return UDQASTNode(current.type, current.value, left, right);
} }
return left; return left;
} }
UDQASTNode
namespace { UDQParser::parse(const UDQParams& udq_params,
void dump_tokens(const std::string& target_var, const std::vector<UDQToken>& tokens) { const UDQVarType target_type,
std::cout << target_var << " = "; const std::string& target_var,
for (const auto& token : tokens) const KeywordLocation& location,
std::cout << token.str(); const std::vector<UDQToken>& tokens,
std::cout << std::endl; const ParseContext& parseContext,
} ErrorGuard& errors)
/*
This function is extremely weak - hopefully it can be improved in the future.
See the comment in UDQEnums.hpp about 'UDQ type system'.
*/
bool static_type_check(UDQVarType lhs, UDQVarType rhs) {
if (lhs == rhs)
return true;
if (rhs == UDQVarType::SCALAR)
return true;
/*
This does not check if the rhs evaluates to a scalar.
*/
if (rhs == UDQVarType::WELL_VAR)
return (lhs == UDQVarType::WELL_VAR);
return false;
}
}
UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type, const std::string& target_var, const KeywordLocation& location, const std::vector<UDQToken>& tokens, const ParseContext& parseContext, ErrorGuard& errors)
{ {
UDQParser parser(udq_params, tokens); UDQParser parser(udq_params, tokens);
parser.next(); parser.next();
@ -315,20 +386,26 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type,
auto current = parser.current(); auto current = parser.current();
std::string msg_fmt = fmt::format("Problem parsing UDQ {}\n" std::string msg_fmt = fmt::format("Problem parsing UDQ {}\n"
"In {{file}} line {{line}}.\n" "In {{file}} line {{line}}.\n"
"Extra unhandled data starting with item {}.", target_var, current.string()); "Extra unhandled data starting with item {}.",
target_var, current.string());
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors); parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
return UDQASTNode( udq_params.undefinedValue() ); return UDQASTNode( udq_params.undefinedValue() );
} }
if (!tree.valid()) { if (!tree.valid()) {
std::string token_string; std::string token_string;
for (const auto& token : tokens) for (const auto& token : tokens) {
token_string += token.str() + " "; token_string += token.str() + " ";
}
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n" std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
"In {{file}} line {{line}}.\n" "In {{file}} line {{line}}.\n"
"This can be a bug in flow or a bug in the UDQ input string.\n" "This can be a bug in flow or a "
"UDQ input: '{}'", target_var, token_string); "bug in the UDQ input string.\n"
"UDQ input: '{}'",
target_var, token_string);
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors); parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
return UDQASTNode( udq_params.undefinedValue() ); return UDQASTNode( udq_params.undefinedValue() );
} }
@ -336,27 +413,35 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type,
if (!static_type_check(target_type, tree.var_type)) { if (!static_type_check(target_type, tree.var_type)) {
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n" std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
"In {{file}} line {{line}}.\n" "In {{file}} line {{line}}.\n"
"Invalid type conversion detected in UDQ expression expected: {} got: {}", target_var, UDQ::typeName(target_type), UDQ::typeName(tree.var_type)); "Invalid type conversion detected "
"in UDQ expression expected: {}, got: {}",
target_var,
UDQ::typeName(target_type),
UDQ::typeName(tree.var_type));
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors); parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE) if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE) {
dump_tokens(target_var, tokens); dump_tokens(target_var, tokens);
}
return UDQASTNode( udq_params.undefinedValue() ); return UDQASTNode(udq_params.undefinedValue());
} }
if (tree.var_type == UDQVarType::NONE) { if (tree.var_type == UDQVarType::NONE) {
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n" std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
"In {{file}} line {{line}}.\n" "In {{file}} line {{line}}.\n"
"Could not determine expression type.", target_var); "Could not determine "
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors); "expression type.", target_var);
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE)
dump_tokens(target_var, tokens);
return UDQASTNode( udq_params.undefinedValue() ); parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE) {
dump_tokens(target_var, tokens);
}
return UDQASTNode(udq_params.undefinedValue());
} }
return tree; return tree;
} }
} } // namespace Opm

View File

@ -16,70 +16,85 @@
OPM. If not, see <http://www.gnu.org/licenses/>. OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef UDQPARSER_HPP #ifndef UDQPARSER_HPP
#define UDQPARSER_HPP #define UDQPARSER_HPP
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
#include <string> #include <string>
#include <variant> #include <variant>
#include <vector> #include <vector>
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
namespace Opm { namespace Opm {
class ParseContext; class ParseContext;
class ErrorGuard; class ErrorGuard;
class KeywordLocation; class KeywordLocation;
struct UDQParseNode { } // namespace Opm
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg, const std::vector<std::string>& selector_arg) :
type(type_arg), namespace Opm {
value(value_arg),
selector(selector_arg) struct UDQParseNode
{
UDQParseNode(const UDQTokenType type_arg,
const std::variant<std::string, double>& value_arg,
const std::vector<std::string>& selector_arg)
: type(type_arg)
, value(value_arg)
, selector(selector_arg)
{ {
if (type_arg == UDQTokenType::ecl_expr) if (type_arg == UDQTokenType::ecl_expr) {
this->var_type = UDQ::targetType(std::get<std::string>(value_arg), selector_arg); this->var_type = UDQ::targetType(std::get<std::string>(value_arg), selector_arg);
}
} }
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg)
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg) : : UDQParseNode(type_arg, value_arg, {})
UDQParseNode(type_arg, value_arg, {})
{} {}
// Implicit converting constructor. // Implicit converting constructor.
UDQParseNode(UDQTokenType type_arg) : UDQParseNode(type_arg, "") UDQParseNode(UDQTokenType type_arg) : UDQParseNode(type_arg, "")
{} {}
std::string string() const { std::string string() const
if (std::holds_alternative<std::string>(this->value)) {
if (std::holds_alternative<std::string>(this->value)) {
return std::get<std::string>(this->value); return std::get<std::string>(this->value);
else }
return std::to_string( std::get<double>(this->value)); else {
return std::to_string(std::get<double>(this->value));
}
} }
UDQTokenType type; UDQTokenType type;
std::variant<std::string, double> value; std::variant<std::string, double> value;
std::vector<std::string> selector; std::vector<std::string> selector;
UDQVarType var_type = UDQVarType::NONE; UDQVarType var_type = UDQVarType::NONE;
}; };
class UDQParser
class UDQParser { {
public: public:
static UDQASTNode parse(const UDQParams& udq_params, UDQVarType target_type, const std::string& target_var, const KeywordLocation& location, const std::vector<UDQToken>& tokens_, const ParseContext& parseContext, ErrorGuard& errors); static UDQASTNode
parse(const UDQParams& udq_params,
UDQVarType target_type,
const std::string& target_var,
const KeywordLocation& location,
const std::vector<UDQToken>& tokens_,
const ParseContext& parseContext,
ErrorGuard& errors);
private: private:
UDQParser(const UDQParams& udq_params1, const std::vector<UDQToken>& tokens_) : UDQParser(const UDQParams& udq_params1,
udq_params(udq_params1), const std::vector<UDQToken>& tokens_)
udqft(UDQFunctionTable(udq_params)), : udq_params(udq_params1)
tokens(tokens_) , udqft(UDQFunctionTable(udq_params))
, tokens(tokens_)
{} {}
UDQASTNode parse_set(); UDQASTNode parse_set();
@ -101,7 +116,6 @@ private:
ssize_t current_pos = -1; ssize_t current_pos = -1;
}; };
} // namespace Opm
} #endif // UDQPARSER_HPP
#endif

View File

@ -16,12 +16,21 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>. along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <algorithm>
#include <cmath> #include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <fmt/format.h>
#include <opm/common/utility/shmatch.hpp> #include <opm/common/utility/shmatch.hpp>
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <optional>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
#include <fmt/format.h>
namespace Opm { namespace Opm {
@ -216,12 +225,13 @@ UDQSet UDQSet::groups(const std::string& name, const std::vector<std::string>& g
} }
bool UDQSet::has(const std::string& name) const { bool UDQSet::has(const std::string& name) const
for (const auto& res : this->values) { {
if (res.wgname() == name) return std::any_of(this->values.begin(), this->values.end(),
return true; [&name](const UDQScalar& value)
} {
return false; return value.wgname() == name;
});
} }
std::size_t UDQSet::size() const { std::size_t UDQSet::size() const {
@ -342,25 +352,36 @@ std::vector<double> UDQSet::defined_values() const {
} }
std::size_t UDQSet::defined_size() const { std::size_t UDQSet::defined_size() const
std::size_t dsize = 0; {
for (const auto& v : this->values) { return std::count_if(this->values.begin(), this->values.end(),
if (v) [](const UDQScalar& value)
dsize += 1; {
} return value.defined();
return dsize; });
} }
const UDQScalar& UDQSet::operator[](std::size_t index) const { const UDQScalar& UDQSet::operator[](std::size_t index) const
if (index >= this->size()) {
if (index >= this->size()) {
throw std::out_of_range("Index out of range in UDQset::operator[]"); throw std::out_of_range("Index out of range in UDQset::operator[]");
}
return this->values[index]; return this->values[index];
} }
const UDQScalar& UDQSet::operator[](const std::string& wgname) const { const UDQScalar& UDQSet::operator[](const std::string& wgname) const
auto value_iter = std::find_if( this->values.begin(), this->values.end(), [&wgname](const UDQScalar& value) { return (value.wgname() == wgname );}); {
if (value_iter == this->values.end()) auto value_iter = std::find_if(this->values.begin(), this->values.end(),
[&wgname](const UDQScalar& value)
{
return value.wgname() == wgname;
});
if (value_iter == this->values.end()) {
throw std::out_of_range("No such well/group: " + wgname); throw std::out_of_range("No such well/group: " + wgname);
}
return *value_iter; return *value_iter;
} }
@ -453,54 +474,58 @@ UDQScalar operator/(double lhs, const UDQScalar& rhs) {
namespace { namespace {
bool is_scalar(const UDQSet& udq_set) { bool is_scalar(const UDQSet& udq_set)
if (udq_set.var_type() == UDQVarType::SCALAR) {
return true; const auto vtype = udq_set.var_type();
if (udq_set.var_type() == UDQVarType::FIELD_VAR) return (vtype == UDQVarType::SCALAR)
return true; || (vtype == UDQVarType::FIELD_VAR);
return false;
} }
// If one result set is scalar and the other represents a set of
/* // wells/groups, the scalar result is promoted to a set of the right type.
If one result set is scalar and the other represents a set of wells/groups, //
the scalar result is promoted to a set of the right type. // This function is quite subconscious about FIELD / SCALAR.
This function is quite subconcious about FIELD / SCALAR.
*/
std::pair<UDQSet, UDQSet> udq_cast(const UDQSet& lhs, const UDQSet& rhs) std::pair<UDQSet, UDQSet> udq_cast(const UDQSet& lhs, const UDQSet& rhs)
{ {
if (lhs.var_type() == rhs.var_type()) if (lhs.var_type() == rhs.var_type()) {
return std::make_pair(lhs,rhs); return { lhs, rhs };
}
if (lhs.size() == rhs.size()) if (is_scalar(lhs) && is_scalar(rhs)) {
return std::make_pair(lhs,rhs); return { lhs, rhs };
}
if (is_scalar(lhs)) { if (is_scalar(lhs)) {
if (rhs.var_type() == UDQVarType::WELL_VAR) if (rhs.var_type() == UDQVarType::WELL_VAR) {
return std::make_pair(UDQSet::wells(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs); return { UDQSet::wells(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs };
}
if (rhs.var_type() == UDQVarType::GROUP_VAR) if (rhs.var_type() == UDQVarType::GROUP_VAR) {
return std::make_pair(UDQSet::groups(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs); return { UDQSet::groups(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs };
}
} }
if (is_scalar(rhs)) { if (is_scalar(rhs)) {
if (lhs.var_type() == UDQVarType::WELL_VAR) if (lhs.var_type() == UDQVarType::WELL_VAR) {
return std::make_pair(lhs, UDQSet::wells(rhs.name(), lhs.wgnames(), rhs[0].get())); return { lhs, UDQSet::wells(rhs.name(), lhs.wgnames(), rhs[0].get()) };
}
if (lhs.var_type() == UDQVarType::GROUP_VAR) if (lhs.var_type() == UDQVarType::GROUP_VAR) {
return std::make_pair(lhs, UDQSet::groups(rhs.name(), lhs.wgnames(), rhs[0].get())); return { lhs, UDQSet::groups(rhs.name(), lhs.wgnames(), rhs[0].get()) };
}
} }
auto msg = fmt::format("Type/size mismatch when combining UDQs {}(size={}, type={}) and {}(size={}, type={})", throw std::logic_error {
lhs.name(), lhs.size(), static_cast<int>(lhs.var_type()), fmt::format("Type/size mismatch when combining UDQs "
rhs.name(), rhs.size(), static_cast<int>(rhs.var_type())); "{}(size={}, type={}) and "
throw std::logic_error(msg); "{}(size={}, type={})",
lhs.name(), lhs.size(), UDQ::typeName(lhs.var_type()),
rhs.name(), rhs.size(), UDQ::typeName(rhs.var_type()))
};
} }
} } // Anonymous namespace
UDQSet operator+(const UDQSet&lhs, const UDQSet& rhs) { UDQSet operator+(const UDQSet&lhs, const UDQSet& rhs) {
auto [left,right] = udq_cast(lhs, rhs); auto [left,right] = udq_cast(lhs, rhs);
@ -584,4 +609,4 @@ bool UDQSet::operator==(const UDQSet& other) const {
this->values == other.values; this->values == other.values;
} }
} } // namespace Opm

View File

@ -36,47 +36,57 @@ namespace {
namespace Opm { namespace Opm {
UDQToken::UDQToken(const std::string& string_token, UDQTokenType token_type_) : UDQToken::UDQToken(const std::string& string_token,
token_type(token_type_) const UDQTokenType token_type_)
: token_type(token_type_)
{ {
if (this->token_type == UDQTokenType::number) if (this->token_type == UDQTokenType::number) {
this->m_value = stod(string_token); this->m_value = stod(string_token);
else }
else {
this->m_value = string_token; this->m_value = string_token;
}
} }
UDQToken::UDQToken(const std::string& string_token, const std::vector<std::string>& selector_): UDQToken::UDQToken(const std::string& string_token,
token_type(UDQTokenType::ecl_expr), const std::vector<std::string>& selector_)
m_value(string_token), : token_type(UDQTokenType::ecl_expr)
m_selector(selector_) , m_value (string_token)
, m_selector(selector_)
{}
const std::variant<std::string, double>& UDQToken::value() const
{ {
}
const std::variant<std::string, double>& UDQToken::value() const {
return this->m_value; return this->m_value;
} }
const std::vector<std::string>& UDQToken::selector() const { const std::vector<std::string>& UDQToken::selector() const
{
return this->m_selector; return this->m_selector;
} }
UDQTokenType UDQToken::type() const { UDQTokenType UDQToken::type() const
{
return this->token_type; return this->token_type;
} }
std::string UDQToken::str() const { std::string UDQToken::str() const
{
if (std::holds_alternative<std::string>(this->m_value)) { if (std::holds_alternative<std::string>(this->m_value)) {
if (this->m_selector.empty()) if (this->m_selector.empty()) {
return std::get<std::string>(this->m_value); return std::get<std::string>(this->m_value);
}
std::string quoted_selector; std::string quoted_selector;
for (const auto& s : this->m_selector) for (const auto& s : this->m_selector) {
quoted_selector += " '" + s + "'"; quoted_selector += " '" + s + "'";
}
return std::get<std::string>(this->m_value) + quoted_selector; return std::get<std::string>(this->m_value) + quoted_selector;
} else }
else {
return format_double(std::get<double>(this->m_value)); return format_double(std::get<double>(this->m_value));
}
} }
} // namespace Opm } // namespace Opm