Merge pull request #3220 from bska/reduce-astnode-eval-nesting
Reduce Level of Nesting in UDQASTNode::eval
This commit is contained in:
commit
0624a04613
@ -20,6 +20,10 @@
|
||||
#ifndef 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 <set>
|
||||
#include <string>
|
||||
@ -27,16 +31,13 @@
|
||||
#include <variant>
|
||||
#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 {
|
||||
|
||||
class UDQASTNode {
|
||||
class UDQASTNode
|
||||
{
|
||||
public:
|
||||
UDQVarType var_type = UDQVarType::NONE;
|
||||
|
||||
UDQASTNode();
|
||||
explicit UDQASTNode(UDQTokenType type_arg);
|
||||
explicit UDQASTNode(double scalar_value);
|
||||
@ -48,21 +49,20 @@ public:
|
||||
static UDQASTNode serializationTestObject();
|
||||
|
||||
UDQSet eval(UDQVarType eval_target, const UDQContext& context) const;
|
||||
|
||||
bool valid() const;
|
||||
UDQVarType var_type = UDQVarType::NONE;
|
||||
std::set<UDQTokenType> func_tokens() const;
|
||||
|
||||
void update_type(const UDQASTNode& arg);
|
||||
void set_left(const UDQASTNode& arg);
|
||||
void set_right(const UDQASTNode& arg);
|
||||
UDQASTNode* get_left() const;
|
||||
UDQASTNode* get_right() const;
|
||||
void scale(double sign_factor);
|
||||
|
||||
UDQASTNode* get_left() const;
|
||||
UDQASTNode* get_right() const;
|
||||
bool operator==(const UDQASTNode& data) const;
|
||||
void required_summary(std::unordered_set<std::string>& summary_keys) const;
|
||||
|
||||
template<class Serializer>
|
||||
template <class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer(var_type);
|
||||
@ -76,13 +76,34 @@ public:
|
||||
|
||||
private:
|
||||
UDQTokenType type;
|
||||
void func_tokens(std::set<UDQTokenType>& tokens) const;
|
||||
|
||||
std::variant<std::string, double> value;
|
||||
double sign = 1.0;
|
||||
std::vector<std::string> selector;
|
||||
std::shared_ptr<UDQASTNode> left;
|
||||
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);
|
||||
|
@ -20,20 +20,22 @@
|
||||
#ifndef 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/UDQDefine.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/UDQInput.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/Util/OrderedMap.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 {
|
||||
|
||||
@ -43,12 +45,16 @@ namespace Opm {
|
||||
class KeywordLocation;
|
||||
class WellMatcher;
|
||||
|
||||
namespace RestartIO {
|
||||
struct RstState;
|
||||
}
|
||||
} // namespace Opm
|
||||
|
||||
namespace Opm { namespace RestartIO {
|
||||
struct RstState;
|
||||
}} // namespace Opm::RestartIO
|
||||
|
||||
class UDQConfig {
|
||||
namespace Opm {
|
||||
|
||||
class UDQConfig
|
||||
{
|
||||
public:
|
||||
UDQConfig() = default;
|
||||
explicit UDQConfig(const UDQParams& params);
|
||||
@ -91,7 +97,6 @@ namespace Opm {
|
||||
bool operator==(const UDQConfig& config) const;
|
||||
void required_summary(std::unordered_set<std::string>& summary_keys) const;
|
||||
|
||||
|
||||
template<class 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_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const;
|
||||
|
||||
|
||||
UDQParams udq_params;
|
||||
UDQFunctionTable udqft;
|
||||
|
||||
|
||||
/*
|
||||
The choices of datastructures are strongly motivated by the
|
||||
constraints imposed by the Eclipse formatted restart files; for
|
||||
writing restart files it is essential to keep meticolous control over
|
||||
the ordering of the keywords. In this class the ordering is mainly
|
||||
maintained by the input_index map which keeps track of the insert
|
||||
order of each keyword, and whether the keyword is currently DEFINE'ed
|
||||
or ASSIGN'ed.
|
||||
*/
|
||||
// The choices of data structures are strongly motivated by the
|
||||
// constraints imposed by the ECLIPSE formatted restart files; for
|
||||
// writing restart files it is essential to keep meticulous control
|
||||
// over the ordering of the keywords. In this class the ordering is
|
||||
// mainly maintained by the input_index map which keeps track of the
|
||||
// insert order of each keyword, and whether the keyword is
|
||||
// currently DEFINE'ed or ASSIGN'ed.
|
||||
std::unordered_map<std::string, UDQDefine> m_definitions;
|
||||
std::unordered_map<std::string, UDQAssign> m_assignments;
|
||||
std::unordered_map<std::string, std::string> units;
|
||||
|
@ -17,30 +17,38 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef 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 <set>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#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 {
|
||||
|
||||
class UDQASTNode;
|
||||
class ParseContext;
|
||||
class ErrorGuard;
|
||||
|
||||
class UDQDefine{
|
||||
} // Namespace Opm
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class UDQDefine
|
||||
{
|
||||
public:
|
||||
UDQDefine();
|
||||
|
||||
@ -73,7 +81,7 @@ public:
|
||||
const std::string& keyword() const;
|
||||
const std::string& input_string() const;
|
||||
const KeywordLocation& location() const;
|
||||
UDQVarType var_type() const;
|
||||
UDQVarType var_type() const;
|
||||
std::set<UDQTokenType> func_tokens() const;
|
||||
void required_summary(std::unordered_set<std::string>& summary_keys) const;
|
||||
void update_status(UDQUpdate update_status, std::size_t report_step);
|
||||
@ -82,7 +90,7 @@ public:
|
||||
|
||||
bool operator==(const UDQDefine& data) const;
|
||||
|
||||
template<class Serializer>
|
||||
template <class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer(m_keyword);
|
||||
@ -104,8 +112,7 @@ private:
|
||||
UDQUpdate m_update_status;
|
||||
mutable std::optional<std::string> string_data;
|
||||
};
|
||||
}
|
||||
|
||||
} // Namespace Opm
|
||||
|
||||
|
||||
#endif
|
||||
#endif // UDQ_DEFINE_HPP
|
||||
|
@ -25,40 +25,41 @@
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/*
|
||||
The UDQ variables can be of of many different types. In addition they can be
|
||||
either scalars or vector sets. The arch example of a vector set is well
|
||||
variables - in the expressions:
|
||||
// The UDQ variables can be of many different types. Additionally they can
|
||||
// be either scalars or vector sets. The archetypal example of a vector set
|
||||
// is well variables. For instance, 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
|
||||
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 {
|
||||
enum class UDQVarType
|
||||
{
|
||||
NONE = 0,
|
||||
SCALAR = 1,
|
||||
CONNECTION_VAR = 2,
|
||||
@ -68,10 +69,11 @@ enum class UDQVarType {
|
||||
AQUIFER_VAR = 6,
|
||||
BLOCK_VAR = 7,
|
||||
WELL_VAR = 8,
|
||||
GROUP_VAR = 9
|
||||
GROUP_VAR = 9,
|
||||
};
|
||||
|
||||
enum class UDQTokenType{
|
||||
enum class UDQTokenType
|
||||
{
|
||||
error = 0,
|
||||
number = 1,
|
||||
open_paren = 2,
|
||||
@ -123,23 +125,26 @@ enum class UDQTokenType{
|
||||
//
|
||||
table_lookup = 47,
|
||||
//
|
||||
end = 100
|
||||
end = 100,
|
||||
};
|
||||
|
||||
enum class UDQAction {
|
||||
enum class UDQAction
|
||||
{
|
||||
ASSIGN,
|
||||
DEFINE,
|
||||
UNITS,
|
||||
UPDATE
|
||||
UPDATE,
|
||||
};
|
||||
|
||||
enum class UDQUpdate {
|
||||
enum class UDQUpdate
|
||||
{
|
||||
ON,
|
||||
OFF,
|
||||
NEXT
|
||||
NEXT,
|
||||
};
|
||||
|
||||
enum class UDAControl {
|
||||
enum class UDAControl
|
||||
{
|
||||
WCONPROD_ORAT,
|
||||
WCONPROD_WRAT,
|
||||
WCONPROD_GRAT,
|
||||
@ -173,7 +178,8 @@ enum class UDAControl {
|
||||
WELTARG_LIFT,
|
||||
};
|
||||
|
||||
enum class UDAKeyword {
|
||||
enum class UDAKeyword
|
||||
{
|
||||
WCONPROD,
|
||||
WCONINJE,
|
||||
WELTARG,
|
||||
@ -187,11 +193,15 @@ namespace UDQ {
|
||||
UDQVarType targetType(const std::string& keyword);
|
||||
UDQVarType varType(const std::string& keyword);
|
||||
UDQVarType coerce(UDQVarType t1, UDQVarType t2);
|
||||
|
||||
UDQAction actionType(const std::string& action_string);
|
||||
|
||||
UDQUpdate updateType(const std::string& update_string);
|
||||
UDQUpdate updateType(int int_value);
|
||||
|
||||
UDQTokenType tokenType(const std::string& func_name);
|
||||
UDQTokenType funcType(const std::string& func_name);
|
||||
|
||||
bool binaryFunc(UDQTokenType token_type);
|
||||
bool elementalUnaryFunc(UDQTokenType token_type);
|
||||
bool scalarFunc(UDQTokenType token_type);
|
||||
@ -208,12 +218,15 @@ namespace UDQ {
|
||||
|
||||
std::string typeName(UDQVarType var_type);
|
||||
std::string controlName(UDAControl control);
|
||||
|
||||
UDAKeyword keyword(UDAControl control);
|
||||
int udaCode(UDAControl control);
|
||||
UDAControl udaControl(int uda_code);
|
||||
|
||||
constexpr double restart_default = -0.3E+21;
|
||||
} // UDQ
|
||||
} // Opm
|
||||
|
||||
#endif // UDQ_ENUMS_HPP
|
||||
} // namespace UDQ
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // UDQ_ENUMS_HPP
|
||||
|
@ -17,32 +17,33 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef 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/UDQDefine.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class UDQAssign;
|
||||
class UDQDefine;
|
||||
|
||||
class UDQIndex {
|
||||
class UDQIndex
|
||||
{
|
||||
public:
|
||||
UDQIndex() = default;
|
||||
|
||||
UDQIndex(std::size_t insert_index_arg, std::size_t typed_insert_index_arg, UDQAction action_arg, UDQVarType var_type_arg) :
|
||||
insert_index(insert_index_arg),
|
||||
typed_insert_index(typed_insert_index_arg),
|
||||
action(action_arg),
|
||||
var_type(var_type_arg)
|
||||
{
|
||||
}
|
||||
UDQIndex(const std::size_t insert_index_arg,
|
||||
const std::size_t typed_insert_index_arg,
|
||||
const UDQAction action_arg,
|
||||
const UDQVarType 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()
|
||||
{
|
||||
@ -55,14 +56,16 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const UDQIndex& data) const {
|
||||
return insert_index == data.insert_index &&
|
||||
typed_insert_index == data.typed_insert_index &&
|
||||
action == data.action &&
|
||||
var_type == data.var_type;
|
||||
bool operator==(const UDQIndex& data) const
|
||||
{
|
||||
return (insert_index == data.insert_index)
|
||||
&& (typed_insert_index == data.typed_insert_index)
|
||||
&& (action == data.action)
|
||||
&& (var_type == data.var_type)
|
||||
;
|
||||
}
|
||||
|
||||
template<class Serializer>
|
||||
template <class Serializer>
|
||||
void serializeOp(Serializer& serializer)
|
||||
{
|
||||
serializer(insert_index);
|
||||
@ -77,16 +80,16 @@ public:
|
||||
UDQVarType var_type;
|
||||
};
|
||||
|
||||
|
||||
class UDQInput{
|
||||
class UDQInput
|
||||
{
|
||||
public:
|
||||
UDQInput(const UDQIndex& index, const UDQDefine& udq_define, 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;
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
bool is() const;
|
||||
|
||||
const std::string& keyword() const;
|
||||
@ -95,14 +98,14 @@ public:
|
||||
const UDQIndex index;
|
||||
|
||||
bool operator==(const UDQInput& other) const;
|
||||
|
||||
private:
|
||||
std::variant<UDQDefine, UDQAssign> value;
|
||||
const std::string m_keyword;
|
||||
std::string m_keyword;
|
||||
UDQVarType m_var_type;
|
||||
const std::string m_unit;
|
||||
std::string m_unit;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
#endif
|
||||
#endif // UDQINPUT__HPP_
|
||||
|
@ -20,17 +20,19 @@
|
||||
#ifndef UDQSET_HPP
|
||||
#define UDQSET_HPP
|
||||
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class UDQScalar {
|
||||
class UDQScalar
|
||||
{
|
||||
public:
|
||||
UDQScalar() = default;
|
||||
explicit UDQScalar(double value);
|
||||
@ -60,12 +62,14 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class UDQSet {
|
||||
class UDQSet
|
||||
{
|
||||
public:
|
||||
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, 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, double value);
|
||||
static UDQSet empty(const std::string& name);
|
||||
@ -84,6 +88,7 @@ public:
|
||||
|
||||
bool has(const std::string& name) const;
|
||||
std::size_t size() const;
|
||||
|
||||
void operator+=(const UDQSet& rhs);
|
||||
void operator+=(double rhs);
|
||||
void operator-=(const UDQSet& rhs);
|
||||
@ -105,6 +110,7 @@ public:
|
||||
void name(const std::string& name);
|
||||
UDQVarType var_type() const;
|
||||
bool operator==(const UDQSet& other) const;
|
||||
|
||||
private:
|
||||
UDQSet() = default;
|
||||
|
||||
|
@ -16,91 +16,131 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
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/UDQEnums.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQFunction.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 {
|
||||
|
||||
UDQVarType init_type(UDQTokenType token_type)
|
||||
bool is_udq(const std::string& key)
|
||||
{
|
||||
if (token_type == UDQTokenType::number)
|
||||
return UDQVarType::SCALAR;
|
||||
|
||||
if (UDQ::scalarFunc(token_type))
|
||||
return UDQVarType::SCALAR;
|
||||
|
||||
return UDQVarType::NONE;
|
||||
return (key.size() >= std::string::size_type{2})
|
||||
&& (key[1] == 'U');
|
||||
}
|
||||
|
||||
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) :
|
||||
var_type(init_type(UDQTokenType::number)),
|
||||
type(UDQTokenType::number),
|
||||
value(numeric_value)
|
||||
namespace Opm {
|
||||
|
||||
UDQASTNode::UDQASTNode()
|
||||
: UDQASTNode(UDQTokenType::error)
|
||||
{}
|
||||
|
||||
|
||||
UDQASTNode::UDQASTNode(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)
|
||||
: var_type(UDQVarType::NONE)
|
||||
, type (type_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 UDQASTNode& left_arg)
|
||||
const UDQASTNode& left_arg)
|
||||
: UDQASTNode(type_arg, value_arg)
|
||||
{
|
||||
if (UDQ::scalarFunc(type_arg))
|
||||
if (UDQ::scalarFunc(type_arg)) {
|
||||
this->var_type = UDQVarType::SCALAR;
|
||||
else
|
||||
}
|
||||
else {
|
||||
this->var_type = left_arg.var_type;
|
||||
}
|
||||
|
||||
this->left = std::make_unique<UDQASTNode>(left_arg);
|
||||
}
|
||||
|
||||
|
||||
UDQASTNode::UDQASTNode(UDQTokenType type_arg,
|
||||
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
|
||||
const std::variant<std::string, double>& value_arg,
|
||||
const UDQASTNode& left_arg,
|
||||
const UDQASTNode& right_arg) :
|
||||
var_type(init_type(type_arg)),
|
||||
type(type_arg),
|
||||
value(value_arg)
|
||||
const UDQASTNode& left_arg,
|
||||
const UDQASTNode& right_arg)
|
||||
: var_type(init_type(type_arg))
|
||||
, type (type_arg)
|
||||
, value (value_arg)
|
||||
{
|
||||
this->set_left(left_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()
|
||||
{
|
||||
@ -110,257 +150,323 @@ UDQASTNode UDQASTNode::serializationTestObject()
|
||||
result.value = "test1";
|
||||
result.selector = {"test2"};
|
||||
result.sign = -1;
|
||||
|
||||
UDQASTNode left = result;
|
||||
result.left = std::make_shared<UDQASTNode>(left);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
UDQASTNode::UDQASTNode(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)
|
||||
UDQSet
|
||||
UDQASTNode::eval(const UDQVarType target_type,
|
||||
const UDQContext& context) const
|
||||
{
|
||||
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) {
|
||||
const auto& string_value = std::get<std::string>( this->value );
|
||||
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);
|
||||
return this->sign * this->eval_expression(context);
|
||||
}
|
||||
|
||||
|
||||
if (UDQ::scalarFunc(this->type)) {
|
||||
const auto& string_value = std::get<std::string>( this->value );
|
||||
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) );
|
||||
return this->sign * this->eval_scalar_function(target_type, context);
|
||||
}
|
||||
|
||||
|
||||
if (UDQ::elementalUnaryFunc(this->type)) {
|
||||
const auto& string_value = std::get<std::string>( this->value );
|
||||
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);
|
||||
return this->sign * this->eval_elemental_unary_function(target_type, context);
|
||||
}
|
||||
|
||||
if (UDQ::binaryFunc(this->type)) {
|
||||
auto left_arg = this->left->eval(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;
|
||||
return this->sign * this->eval_binary_function(target_type, context);
|
||||
}
|
||||
|
||||
if (this->type == UDQTokenType::number) {
|
||||
const std::string dummy_name = "DUMMY";
|
||||
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)));
|
||||
}
|
||||
return this->sign * this->eval_number(target_type, context);
|
||||
}
|
||||
|
||||
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 {
|
||||
tokens.insert( this->type );
|
||||
if (this->left)
|
||||
this->left->func_tokens(tokens);
|
||||
if (this->right)
|
||||
this->right->func_tokens(tokens);
|
||||
bool UDQASTNode::valid() const
|
||||
{
|
||||
return this->type != UDQTokenType::error;
|
||||
}
|
||||
|
||||
std::set<UDQTokenType> UDQASTNode::func_tokens() const {
|
||||
std::set<UDQTokenType> tokens;
|
||||
std::set<UDQTokenType> UDQASTNode::func_tokens() const
|
||||
{
|
||||
auto tokens = std::set<UDQTokenType>{};
|
||||
this->func_tokens(tokens);
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
UDQASTNode* UDQASTNode::get_left() const {
|
||||
return this->left.get();
|
||||
}
|
||||
|
||||
UDQASTNode* UDQASTNode::get_right() const {
|
||||
return this->right.get();
|
||||
}
|
||||
|
||||
|
||||
void UDQASTNode::update_type(const UDQASTNode& arg) {
|
||||
if (this->var_type == UDQVarType::NONE)
|
||||
void UDQASTNode::update_type(const UDQASTNode& arg)
|
||||
{
|
||||
if (this->var_type == UDQVarType::NONE) {
|
||||
this->var_type = arg.var_type;
|
||||
else
|
||||
}
|
||||
else {
|
||||
this->var_type = UDQ::coerce(this->var_type, arg.var_type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool UDQASTNode::valid() const {
|
||||
return (this->type != UDQTokenType::error);
|
||||
}
|
||||
|
||||
|
||||
void UDQASTNode::set_left(const UDQASTNode& arg) {
|
||||
void UDQASTNode::set_left(const UDQASTNode& arg)
|
||||
{
|
||||
this->left = std::make_unique<UDQASTNode>(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->update_type(arg);
|
||||
}
|
||||
|
||||
void UDQASTNode::scale(double sign_factor) {
|
||||
void UDQASTNode::scale(double 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) ||
|
||||
(!this->left && data.left))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->left && !(*this->left == *data.left))
|
||||
if (this->left && !(*this->left == *data.left)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((this->right && !data.right) ||
|
||||
(!this->right && data.right))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->right && !(*this->right == *data.right))
|
||||
if (this->right && !(*this->right == *data.right)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return type == data.type &&
|
||||
var_type == data.var_type &&
|
||||
value == data.value &&
|
||||
selector == data.selector;
|
||||
return (type == data.type)
|
||||
&& (var_type == data.var_type)
|
||||
&& (value == data.value)
|
||||
&& (selector == data.selector)
|
||||
;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
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 {
|
||||
void UDQASTNode::required_summary(std::unordered_set<std::string>& summary_keys) const
|
||||
{
|
||||
if (this->type == UDQTokenType::ecl_expr) {
|
||||
if (std::holds_alternative<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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this->left)
|
||||
if (this->left) {
|
||||
this->left->required_summary(summary_keys);
|
||||
}
|
||||
|
||||
if (this->right)
|
||||
if (this->right) {
|
||||
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;
|
||||
|
||||
prod.scale(sign_factor);
|
||||
|
||||
return prod;
|
||||
}
|
||||
|
||||
|
||||
UDQASTNode operator*(double lhs, const UDQASTNode& rhs) {
|
||||
UDQASTNode operator*(double lhs, const UDQASTNode& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Opm
|
||||
|
@ -17,45 +17,69 @@
|
||||
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/common/OpmLog/KeywordLocation.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/UDQ/UDQConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.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 {
|
||||
std::string strip_quotes(const std::string& s) {
|
||||
if (s[0] == '\'')
|
||||
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)
|
||||
: udq_params(params)
|
||||
, udqft(this->udq_params)
|
||||
{}
|
||||
|
||||
|
||||
UDQConfig::UDQConfig(const UDQParams& params, const RestartIO::RstState& rst_state) :
|
||||
UDQConfig(params)
|
||||
UDQConfig::UDQConfig(const UDQParams& params, const RestartIO::RstState& rst_state)
|
||||
: UDQConfig(params)
|
||||
{
|
||||
for (const auto& rst_udq : rst_state.udqs) {
|
||||
if (rst_udq.is_define()) {
|
||||
KeywordLocation location("UDQ", "Restart file", 0);
|
||||
this->add_define(rst_udq.name, location, {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_define(rst_udq.name,
|
||||
location,
|
||||
{ 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);
|
||||
}
|
||||
}
|
||||
@ -74,113 +98,172 @@ namespace Opm {
|
||||
return result;
|
||||
}
|
||||
|
||||
const UDQParams& UDQConfig::params() const {
|
||||
const UDQParams& UDQConfig::params() const
|
||||
{
|
||||
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);
|
||||
if (this->input_index.find(quantity) == this->input_index.end()) {
|
||||
auto var_type = UDQ::varType(quantity);
|
||||
auto insert_index = this->input_index.size();
|
||||
|
||||
this->type_count[var_type] += 1;
|
||||
this->input_index[quantity] = UDQIndex(insert_index, this->type_count[var_type], action, var_type);
|
||||
} else
|
||||
}
|
||||
else {
|
||||
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);
|
||||
|
||||
auto assignment = this->m_assignments.find(quantity);
|
||||
if (assignment == this->m_assignments.end())
|
||||
this->m_assignments.insert( std::make_pair(quantity, UDQAssign(quantity, selector, value, report_step )));
|
||||
else
|
||||
if (assignment == this->m_assignments.end()) {
|
||||
this->m_assignments.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(quantity),
|
||||
std::forward_as_tuple(quantity, selector,
|
||||
value, report_step));
|
||||
}
|
||||
else {
|
||||
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);
|
||||
|
||||
auto assignment = this->m_assignments.find(quantity);
|
||||
if (assignment == this->m_assignments.end())
|
||||
this->m_assignments.insert( std::make_pair(quantity, UDQAssign(quantity, selector, value, report_step )));
|
||||
else
|
||||
if (assignment == this->m_assignments.end()) {
|
||||
this->m_assignments.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(quantity),
|
||||
std::forward_as_tuple(quantity, selector,
|
||||
value, report_step));
|
||||
}
|
||||
else {
|
||||
assignment->second.add_record(selector, value, report_step);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UDQConfig::add_define(const std::string& quantity, const KeywordLocation& location, const std::vector<std::string>& expression, std::size_t report_step) {
|
||||
void UDQConfig::add_define(const std::string& quantity,
|
||||
const KeywordLocation& location,
|
||||
const std::vector<std::string>& expression,
|
||||
const std::size_t report_step)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
void UDQConfig::add_unit(const std::string& keyword, const std::string& quoted_unit) {
|
||||
const std::string unit = strip_quotes(quoted_unit);
|
||||
void UDQConfig::add_unit(const std::string& keyword, const std::string& quoted_unit)
|
||||
{
|
||||
const auto unit = strip_quotes(quoted_unit);
|
||||
const auto pair_ptr = this->units.find(keyword);
|
||||
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");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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 (data.empty())
|
||||
throw OpmInputError( fmt::format("Missing third item: ON|OFF|NEXT for UDQ update of {}", keyword), location);
|
||||
if (this->m_definitions.count(keyword) == 0) {
|
||||
throw OpmInputError {
|
||||
fmt::format("UDQ variable: {} must be defined before you can use UPDATE", keyword),
|
||||
location
|
||||
};
|
||||
}
|
||||
|
||||
if (this->m_definitions.count(keyword) == 0)
|
||||
throw OpmInputError( fmt::format("UDQ variable: {} must be defined before you can use UPDATE", keyword), location);
|
||||
const auto update_status = UDQ::updateType(data[0]);
|
||||
|
||||
auto update_status = UDQ::updateType(data[0]);
|
||||
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) {
|
||||
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)
|
||||
if (action == UDQAction::UPDATE) {
|
||||
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 {
|
||||
if (action == UDQAction::ASSIGN) {
|
||||
std::vector<std::string> selector(data.begin(), data.end() - 1);
|
||||
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");
|
||||
throw std::runtime_error {
|
||||
"Unknown UDQ Operation " + std::to_string(static_cast<int>(action))
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const UDQAssign& UDQConfig::assign(const std::string& key) const {
|
||||
const UDQAssign& UDQConfig::assign(const std::string& key) const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
return action_iter->second.action;
|
||||
}
|
||||
|
||||
std::vector<UDQDefine> UDQConfig::definitions() const {
|
||||
std::vector<UDQDefine> UDQConfig::definitions() const
|
||||
{
|
||||
std::vector<UDQDefine> ret;
|
||||
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
@ -193,164 +276,184 @@ namespace Opm {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::vector<UDQDefine> UDQConfig::definitions(UDQVarType var_type) const {
|
||||
std::vector<UDQDefine> UDQConfig::definitions(const UDQVarType var_type) const
|
||||
{
|
||||
std::vector<UDQDefine> filtered_defines;
|
||||
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
if (index_pair.second.action == UDQAction::DEFINE) {
|
||||
const std::string& key = index_pair.first;
|
||||
const auto& udq_define = this->m_definitions.at(key);
|
||||
if (udq_define.var_type() == var_type)
|
||||
if (udq_define.var_type() == var_type) {
|
||||
filtered_defines.push_back(udq_define);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return filtered_defines;
|
||||
}
|
||||
|
||||
|
||||
std::vector<UDQInput> UDQConfig::input() const {
|
||||
std::vector<UDQInput> UDQConfig::input() const
|
||||
{
|
||||
std::vector<UDQInput> res;
|
||||
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
const UDQIndex& index = index_pair.second;
|
||||
std::string u;
|
||||
if (this->has_unit(index_pair.first))
|
||||
if (this->has_unit(index_pair.first)) {
|
||||
u = this->unit(index_pair.first);
|
||||
}
|
||||
|
||||
if (index.action == UDQAction::DEFINE) {
|
||||
const std::string& key = index_pair.first;
|
||||
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;
|
||||
res.push_back(UDQInput(index, this->m_assignments.at(key), u));
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
std::size_t UDQConfig::size() const {
|
||||
std::size_t s = 0;
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
if (index_pair.second.action == UDQAction::DEFINE)
|
||||
s += 1;
|
||||
else if (index_pair.second.action == UDQAction::ASSIGN)
|
||||
s += 1;
|
||||
}
|
||||
return s;
|
||||
std::size_t UDQConfig::size() const
|
||||
{
|
||||
return std::count_if(this->input_index.begin(), this->input_index.end(),
|
||||
[](const auto& index_pair)
|
||||
{
|
||||
const auto action = index_pair.second.action;
|
||||
|
||||
return (action == UDQAction::DEFINE)
|
||||
|| (action == UDQAction::ASSIGN);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
std::vector<UDQAssign> UDQConfig::assignments() const {
|
||||
std::vector<UDQAssign> UDQConfig::assignments() const
|
||||
{
|
||||
std::vector<UDQAssign> ret;
|
||||
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
if (index_pair.second.action == UDQAction::ASSIGN) {
|
||||
const std::string& key = index_pair.first;
|
||||
ret.push_back(this->m_assignments.at(key));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
std::vector<UDQAssign> UDQConfig::assignments(UDQVarType var_type) const {
|
||||
std::vector<UDQAssign> UDQConfig::assignments(const UDQVarType var_type) const
|
||||
{
|
||||
std::vector<UDQAssign> filtered_assigns;
|
||||
|
||||
for (const auto& index_pair : this->input_index) {
|
||||
const std::string& key = index_pair.first;
|
||||
const auto& assign_iter = this->m_assignments.find(key);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
if (pair_ptr == this->units.end())
|
||||
if (pair_ptr == this->units.end()) {
|
||||
throw std::invalid_argument("No such UDQ quantity: " + key);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
bool UDQConfig::has_keyword(const std::string& keyword) const {
|
||||
if (this->m_assignments.count(keyword) > 0)
|
||||
return true;
|
||||
|
||||
if (this->m_definitions.count(keyword) > 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
bool UDQConfig::has_keyword(const std::string& keyword) const
|
||||
{
|
||||
return (this->m_assignments.find(keyword) != this->m_assignments.end())
|
||||
|| (this->m_definitions.find(keyword) != this->m_definitions.end());
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
if (index_iter == this->input_index.end())
|
||||
throw std::invalid_argument("Keyword: " + keyword + " not recognized as ASSIGN/DEFINE UDQ");
|
||||
if (index_iter == this->input_index.end()) {
|
||||
throw std::invalid_argument("Keyword: '" + keyword +
|
||||
"' not recognized as ASSIGN/DEFINE UDQ");
|
||||
}
|
||||
|
||||
std::string u;
|
||||
if (this->has_unit(keyword))
|
||||
u = this->unit(keyword);
|
||||
const auto u = this->has_unit(keyword)
|
||||
? this->unit(keyword) : std::string{};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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(),
|
||||
[&insert_index](const std::pair<std::string, UDQIndex>& name_index)
|
||||
{
|
||||
const auto& [_, index] = name_index;
|
||||
(void)_;
|
||||
return index.insert_index == insert_index;
|
||||
});
|
||||
[insert_index](const std::pair<std::string, UDQIndex>& name_index)
|
||||
{
|
||||
return name_index.second.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");
|
||||
}
|
||||
|
||||
const auto& [keyword, index] = *index_iter;
|
||||
std::string u;
|
||||
if (this->has_unit(keyword))
|
||||
if (this->has_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);
|
||||
}
|
||||
|
||||
if (index.action == UDQAction::DEFINE)
|
||||
if (index.action == UDQAction::DEFINE) {
|
||||
return UDQInput(index, this->m_definitions.at(keyword), u);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
bool UDQConfig::operator==(const UDQConfig& data) const {
|
||||
return this->params() == data.params() &&
|
||||
this->function_table() == data.function_table() &&
|
||||
this->m_definitions == data.m_definitions &&
|
||||
this->m_assignments == data.m_assignments &&
|
||||
this->units == data.units &&
|
||||
this->input_index == data.input_index &&
|
||||
this->type_count == data.type_count;
|
||||
bool UDQConfig::operator==(const UDQConfig& data) const
|
||||
{
|
||||
return (this->params() == data.params())
|
||||
&& (this->function_table() == data.function_table())
|
||||
&& (this->m_definitions == data.m_definitions)
|
||||
&& (this->m_assignments == data.m_assignments)
|
||||
&& (this->units == data.units)
|
||||
&& (this->input_index == data.input_index)
|
||||
&& (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)) {
|
||||
if (udq_state.assign(report_step, assign.keyword())) {
|
||||
auto ws = assign.eval(st.wells());
|
||||
@ -373,8 +476,10 @@ namespace Opm {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UDQConfig::eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const {
|
||||
void UDQConfig::eval_define(const std::size_t report_step,
|
||||
UDQState& udq_state,
|
||||
UDQContext& context) const
|
||||
{
|
||||
for (const auto& def : this->definitions(UDQVarType::WELL_VAR)) {
|
||||
if (udq_state.define(def.keyword(), def.status())) {
|
||||
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);
|
||||
this->eval_assign(report_step, st, 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);
|
||||
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) {
|
||||
const auto& udq_def = def_pair.second;
|
||||
udq_def.required_summary(summary_keys);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
@ -16,127 +16,126 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
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/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/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 "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 {
|
||||
|
||||
std::vector<std::string> quote_split(const std::string& item) {
|
||||
std::vector<std::string> quote_split(const std::string& item)
|
||||
{
|
||||
char quote_char = '\'';
|
||||
std::vector<std::string> items;
|
||||
std::size_t offset = 0;
|
||||
while (true) {
|
||||
auto quote_pos1 = item.find(quote_char, offset);
|
||||
if (quote_pos1 == std::string::npos) {
|
||||
if (offset < item.size())
|
||||
if (offset < item.size()) {
|
||||
items.push_back(item.substr(offset));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (quote_pos1 > offset)
|
||||
if (quote_pos1 > offset) {
|
||||
items.push_back(item.substr(offset, quote_pos1 - offset));
|
||||
}
|
||||
|
||||
items.push_back(item.substr(quote_pos1, 1 + quote_pos2 - quote_pos1));
|
||||
offset = quote_pos2 + 1;
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::vector<UDQToken> make_tokens(const std::vector<std::string>& string_tokens) {
|
||||
if (string_tokens.empty())
|
||||
std::vector<Opm::UDQToken>
|
||||
make_tokens(const std::vector<std::string>& string_tokens)
|
||||
{
|
||||
if (string_tokens.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<UDQToken> tokens;
|
||||
std::vector<Opm::UDQToken> tokens;
|
||||
std::size_t token_index = 0;
|
||||
while (true) {
|
||||
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;
|
||||
|
||||
if (token_type == UDQTokenType::ecl_expr) {
|
||||
if (token_type == Opm::UDQTokenType::ecl_expr) {
|
||||
std::vector<std::string> selector;
|
||||
while (true) {
|
||||
if (token_index == string_tokens.size())
|
||||
if (token_index == string_tokens.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto next_type = UDQ::tokenType(string_tokens[token_index]);
|
||||
if (next_type == UDQTokenType::ecl_expr) {
|
||||
auto next_type = Opm::UDQ::tokenType(string_tokens[token_index]);
|
||||
if (next_type == Opm::UDQTokenType::ecl_expr) {
|
||||
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));
|
||||
else
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
UDQDefine::UDQDefine()
|
||||
: 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) {
|
||||
std::string
|
||||
next_token(const std::string& item,
|
||||
std::size_t& offset,
|
||||
const std::vector<std::string>& splitters)
|
||||
{
|
||||
if (std::isdigit(item[offset])) {
|
||||
auto substring = item.substr(offset);
|
||||
char * end_ptr;
|
||||
char* end_ptr;
|
||||
std::ignore = std::strtod(substring.c_str(), &end_ptr);
|
||||
|
||||
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);
|
||||
if (pos < min_pos) {
|
||||
min_pos = pos;
|
||||
if (pos == offset)
|
||||
if (pos == offset) {
|
||||
token = splitter;
|
||||
else
|
||||
}
|
||||
else {
|
||||
token = item.substr(offset, pos - offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
UDQDefine::UDQDefine(const UDQParams& udq_params,
|
||||
const std::string& keyword,
|
||||
std::size_t report_step,
|
||||
const KeywordLocation& location,
|
||||
namespace Opm {
|
||||
|
||||
UDQDefine::UDQDefine()
|
||||
: 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 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)
|
||||
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,
|
||||
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& item : quote_split(deck_item)) {
|
||||
if (RawConsts::is_quote()(item[0])) {
|
||||
@ -186,26 +239,35 @@ UDQDefine::UDQDefine(const UDQParams& udq_params,
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::vector<std::string> splitters = {" ", "TU*[]", "(", ")", "[", "]", ",", "+", "-", "/", "*", "==", "!=", "^", ">=", "<=", ">", "<"};
|
||||
size_t offset = 0;
|
||||
std::size_t offset = 0;
|
||||
while (offset < item.size()) {
|
||||
auto token = next_token(item, offset, splitters);
|
||||
if (!token.empty())
|
||||
string_tokens.push_back( token );
|
||||
if (!token.empty()) {
|
||||
string_tokens.push_back(std::move(token));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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_report_step = report_step;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UDQDefine UDQDefine::serializationTestObject()
|
||||
{
|
||||
UDQDefine result;
|
||||
@ -219,76 +281,63 @@ UDQDefine UDQDefine::serializationTestObject()
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
void UDQDefine::required_summary(std::unordered_set<std::string>& summary_keys) const
|
||||
{
|
||||
this->ast->required_summary(summary_keys);
|
||||
}
|
||||
|
||||
UDQSet UDQDefine::eval(const UDQContext& context) const {
|
||||
UDQSet UDQDefine::eval(const UDQContext& context) const
|
||||
{
|
||||
std::optional<UDQSet> res;
|
||||
try {
|
||||
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())) {
|
||||
std::string msg = "Invalid runtime type conversion detected when evaluating UDQ";
|
||||
throw std::invalid_argument(msg);
|
||||
throw std::invalid_argument {
|
||||
"Invalid runtime type conversion detected when evaluating UDQ"
|
||||
};
|
||||
}
|
||||
} catch (const std::exception& exc) {
|
||||
auto msg = fmt::format("Problem evaluating UDQ {}\n"
|
||||
"In {} line {}\n"
|
||||
"Internal error: {}", this->m_keyword, this->m_location.filename, this->m_location.lineno, exc.what());
|
||||
}
|
||||
catch (const std::exception& exc) {
|
||||
const auto msg = fmt::format("Problem evaluating UDQ {}\n"
|
||||
"In {} line {}\n"
|
||||
"Internal error: {}",
|
||||
this->m_keyword,
|
||||
this->m_location.filename,
|
||||
this->m_location.lineno,
|
||||
exc.what());
|
||||
OpmLog::error(msg);
|
||||
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 the right hand side evaluates to a scalar that scalar value should
|
||||
be set for all wells in the wellset:
|
||||
// If the right hand side evaluates to a scalar that scalar value
|
||||
// should 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
|
||||
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();
|
||||
const auto& scalar_value = (*res)[0].value();
|
||||
if (this->var_type() == UDQVarType::WELL_VAR) {
|
||||
const std::vector<std::string> wells = context.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);
|
||||
}
|
||||
|
||||
return well_res;
|
||||
}
|
||||
@ -297,8 +346,9 @@ UDQSet UDQDefine::eval(const UDQContext& context) const {
|
||||
const std::vector<std::string> groups = context.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);
|
||||
}
|
||||
|
||||
return group_res;
|
||||
}
|
||||
@ -307,72 +357,85 @@ UDQSet UDQDefine::eval(const UDQContext& context) const {
|
||||
return *res;
|
||||
}
|
||||
|
||||
const KeywordLocation& UDQDefine::location() const {
|
||||
const KeywordLocation& UDQDefine::location() const
|
||||
{
|
||||
return this->m_location;
|
||||
}
|
||||
|
||||
UDQVarType UDQDefine::var_type() const {
|
||||
UDQVarType UDQDefine::var_type() const
|
||||
{
|
||||
return this->m_var_type;
|
||||
}
|
||||
|
||||
|
||||
const std::string& UDQDefine::keyword() const {
|
||||
const std::string& UDQDefine::keyword() const
|
||||
{
|
||||
return this->m_keyword;
|
||||
}
|
||||
|
||||
const std::string& UDQDefine::input_string() const {
|
||||
const std::string& UDQDefine::input_string() const
|
||||
{
|
||||
if (!this->string_data.has_value()) {
|
||||
std::string s;
|
||||
/*
|
||||
A string representation equivalent to the input string is assembled by
|
||||
joining tokens and sprinkle with ' ' at semi random locations. The
|
||||
main use of this function is to output the definition string in form
|
||||
usable for the restart file.
|
||||
*/
|
||||
|
||||
// A string representation equivalent to the input string is
|
||||
// assembled by joining tokens and sprinkle with ' ' at semi random
|
||||
// locations. The main use of this function is to output the
|
||||
// definition string in form usable for the restart file.
|
||||
|
||||
for (std::size_t token_index = 0; token_index < this->m_tokens.size(); token_index++) {
|
||||
const auto& token = this->m_tokens[token_index];
|
||||
if (UDQ::leadingSpace(token.type()))
|
||||
if (UDQ::leadingSpace(token.type())) {
|
||||
s += " ";
|
||||
}
|
||||
|
||||
s += token.str();
|
||||
if (token_index == (this->m_tokens.size() - 1))
|
||||
if (token_index == (this->m_tokens.size() - 1)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (UDQ::trailingSpace(token.type())) {
|
||||
s += " ";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
this->string_data = s;
|
||||
|
||||
this->string_data = s;
|
||||
}
|
||||
|
||||
return this->string_data.value();
|
||||
}
|
||||
|
||||
std::set<UDQTokenType> UDQDefine::func_tokens() const {
|
||||
std::set<UDQTokenType> UDQDefine::func_tokens() const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
const std::vector<UDQToken> UDQDefine::tokens() const {
|
||||
const std::vector<UDQToken> UDQDefine::tokens() const
|
||||
{
|
||||
return this->m_tokens;
|
||||
}
|
||||
|
||||
bool UDQDefine::operator==(const UDQDefine& data) const {
|
||||
if ((ast && !data.ast) || (!ast && data.ast))
|
||||
return false;
|
||||
if (ast && !(*ast == *data.ast))
|
||||
bool UDQDefine::operator==(const UDQDefine& data) const
|
||||
{
|
||||
if ((ast && !data.ast) || (!ast && data.ast)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
if (ast && !(*ast == *data.ast)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -28,367 +28,407 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm { namespace UDQ {
|
||||
|
||||
namespace {
|
||||
|
||||
const std::set<UDQTokenType> cmp_func = {UDQTokenType::binary_cmp_eq,
|
||||
UDQTokenType::binary_cmp_ne,
|
||||
UDQTokenType::binary_cmp_le,
|
||||
UDQTokenType::binary_cmp_ge,
|
||||
UDQTokenType::binary_cmp_lt,
|
||||
UDQTokenType::binary_cmp_gt};
|
||||
bool is_no_mix(const Opm::UDQVarType t)
|
||||
{
|
||||
return (t == Opm::UDQVarType::CONNECTION_VAR)
|
||||
|| (t == Opm::UDQVarType::REGION_VAR)
|
||||
|| (t == Opm::UDQVarType::SEGMENT_VAR)
|
||||
|| (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,
|
||||
UDQTokenType::binary_op_mul,
|
||||
UDQTokenType::binary_op_sub,
|
||||
UDQTokenType::binary_op_div,
|
||||
UDQTokenType::binary_op_pow,
|
||||
UDQTokenType::binary_op_uadd,
|
||||
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};
|
||||
bool is_valid_vartype(const Opm::UDQVarType t)
|
||||
{
|
||||
return is_no_mix(t)
|
||||
|| (t == Opm::UDQVarType::NONE)
|
||||
|| (t == Opm::UDQVarType::SCALAR)
|
||||
|| (t == Opm::UDQVarType::FIELD_VAR)
|
||||
;
|
||||
}
|
||||
|
||||
const std::set<UDQTokenType> set_func = {UDQTokenType::binary_op_uadd,
|
||||
UDQTokenType::binary_op_umul,
|
||||
UDQTokenType::binary_op_umin,
|
||||
UDQTokenType::binary_op_umax};
|
||||
const auto cmp_func = std::set<Opm::UDQTokenType> {
|
||||
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 std::set<UDQTokenType> scalar_func = {UDQTokenType::scalar_func_sum,
|
||||
UDQTokenType::scalar_func_avea,
|
||||
UDQTokenType::scalar_func_aveg,
|
||||
UDQTokenType::scalar_func_aveh,
|
||||
UDQTokenType::scalar_func_max,
|
||||
UDQTokenType::scalar_func_min,
|
||||
UDQTokenType::scalar_func_norm1,
|
||||
UDQTokenType::scalar_func_norm2,
|
||||
UDQTokenType::scalar_func_normi,
|
||||
UDQTokenType::scalar_func_prod};
|
||||
const auto binary_func = std::set<Opm::UDQTokenType> {
|
||||
Opm::UDQTokenType::binary_op_add,
|
||||
Opm::UDQTokenType::binary_op_mul,
|
||||
Opm::UDQTokenType::binary_op_sub,
|
||||
Opm::UDQTokenType::binary_op_div,
|
||||
Opm::UDQTokenType::binary_op_pow,
|
||||
Opm::UDQTokenType::binary_op_uadd,
|
||||
Opm::UDQTokenType::binary_op_umul,
|
||||
Opm::UDQTokenType::binary_op_umin,
|
||||
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,
|
||||
UDQTokenType::elemental_func_randu,
|
||||
UDQTokenType::elemental_func_rrandn,
|
||||
UDQTokenType::elemental_func_rrandu,
|
||||
UDQTokenType::elemental_func_abs,
|
||||
UDQTokenType::elemental_func_def,
|
||||
UDQTokenType::elemental_func_exp,
|
||||
UDQTokenType::elemental_func_idv,
|
||||
UDQTokenType::elemental_func_ln,
|
||||
UDQTokenType::elemental_func_log,
|
||||
UDQTokenType::elemental_func_nint,
|
||||
UDQTokenType::elemental_func_sorta,
|
||||
UDQTokenType::elemental_func_sortd,
|
||||
UDQTokenType::elemental_func_undef};
|
||||
const auto scalar_func = std::set<Opm::UDQTokenType> {
|
||||
Opm::UDQTokenType::scalar_func_sum,
|
||||
Opm::UDQTokenType::scalar_func_avea,
|
||||
Opm::UDQTokenType::scalar_func_aveg,
|
||||
Opm::UDQTokenType::scalar_func_aveh,
|
||||
Opm::UDQTokenType::scalar_func_max,
|
||||
Opm::UDQTokenType::scalar_func_min,
|
||||
Opm::UDQTokenType::scalar_func_norm1,
|
||||
Opm::UDQTokenType::scalar_func_norm2,
|
||||
Opm::UDQTokenType::scalar_func_normi,
|
||||
Opm::UDQTokenType::scalar_func_prod,
|
||||
};
|
||||
|
||||
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},
|
||||
{"-", UDQTokenType::binary_op_sub},
|
||||
{"/", UDQTokenType::binary_op_div},
|
||||
{"DIV", UDQTokenType::binary_op_div},
|
||||
{"*", UDQTokenType::binary_op_mul},
|
||||
{"^", UDQTokenType::binary_op_pow},
|
||||
{"UADD", UDQTokenType::binary_op_uadd},
|
||||
{"UMUL", UDQTokenType::binary_op_umul},
|
||||
{"UMIN", UDQTokenType::binary_op_umin},
|
||||
{"UMAX", 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},
|
||||
{"RANDN", UDQTokenType::elemental_func_randn},
|
||||
{"RANDU", UDQTokenType::elemental_func_randu},
|
||||
{"RRNDN", UDQTokenType::elemental_func_rrandn},
|
||||
{"RRNDU", UDQTokenType::elemental_func_rrandu},
|
||||
{"ABS", UDQTokenType::elemental_func_abs},
|
||||
{"DEF", UDQTokenType::elemental_func_def},
|
||||
{"EXP", UDQTokenType::elemental_func_exp},
|
||||
{"IDV", UDQTokenType::elemental_func_idv},
|
||||
{"LN", UDQTokenType::elemental_func_ln},
|
||||
{"LOG", UDQTokenType::elemental_func_log},
|
||||
{"NINT", UDQTokenType::elemental_func_nint},
|
||||
{"SORTA", UDQTokenType::elemental_func_sorta},
|
||||
{"SORTD", UDQTokenType::elemental_func_sortd},
|
||||
{"UNDEF", UDQTokenType::elemental_func_undef},
|
||||
{"SUM", UDQTokenType::scalar_func_sum},
|
||||
{"AVEA", UDQTokenType::scalar_func_avea},
|
||||
{"AVEG", UDQTokenType::scalar_func_aveg},
|
||||
{"AVEH", UDQTokenType::scalar_func_aveh},
|
||||
{"MAX", UDQTokenType::scalar_func_max},
|
||||
{"MIN", UDQTokenType::scalar_func_min},
|
||||
{"NORM1", UDQTokenType::scalar_func_norm1},
|
||||
{"NORM2", UDQTokenType::scalar_func_norm2},
|
||||
{"NORMI", UDQTokenType::scalar_func_normi},
|
||||
{"PROD", UDQTokenType::scalar_func_prod}};
|
||||
const auto func_type = std::unordered_map<std::string, Opm::UDQTokenType> {
|
||||
{"+" , Opm::UDQTokenType::binary_op_add},
|
||||
{"-" , Opm::UDQTokenType::binary_op_sub},
|
||||
{"/" , Opm::UDQTokenType::binary_op_div},
|
||||
{"DIV" , Opm::UDQTokenType::binary_op_div},
|
||||
{"*" , Opm::UDQTokenType::binary_op_mul},
|
||||
{"^" , Opm::UDQTokenType::binary_op_pow},
|
||||
{"UADD" , Opm::UDQTokenType::binary_op_uadd},
|
||||
{"UMUL" , Opm::UDQTokenType::binary_op_umul},
|
||||
{"UMIN" , Opm::UDQTokenType::binary_op_umin},
|
||||
{"UMAX" , 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},
|
||||
{"RANDN", Opm::UDQTokenType::elemental_func_randn},
|
||||
{"RANDU", Opm::UDQTokenType::elemental_func_randu},
|
||||
{"RRNDN", Opm::UDQTokenType::elemental_func_rrandn},
|
||||
{"RRNDU", Opm::UDQTokenType::elemental_func_rrandu},
|
||||
{"ABS" , Opm::UDQTokenType::elemental_func_abs},
|
||||
{"DEF" , Opm::UDQTokenType::elemental_func_def},
|
||||
{"EXP" , Opm::UDQTokenType::elemental_func_exp},
|
||||
{"IDV" , Opm::UDQTokenType::elemental_func_idv},
|
||||
{"LN" , Opm::UDQTokenType::elemental_func_ln},
|
||||
{"LOG" , Opm::UDQTokenType::elemental_func_log},
|
||||
{"NINT" , Opm::UDQTokenType::elemental_func_nint},
|
||||
{"SORTA", Opm::UDQTokenType::elemental_func_sorta},
|
||||
{"SORTD", Opm::UDQTokenType::elemental_func_sortd},
|
||||
{"UNDEF", Opm::UDQTokenType::elemental_func_undef},
|
||||
{"SUM" , Opm::UDQTokenType::scalar_func_sum},
|
||||
{"AVEA" , Opm::UDQTokenType::scalar_func_avea},
|
||||
{"AVEG" , Opm::UDQTokenType::scalar_func_aveg},
|
||||
{"AVEH" , Opm::UDQTokenType::scalar_func_aveh},
|
||||
{"MAX" , Opm::UDQTokenType::scalar_func_max},
|
||||
{"MIN" , Opm::UDQTokenType::scalar_func_min},
|
||||
{"NORM1", Opm::UDQTokenType::scalar_func_norm1},
|
||||
{"NORM2", Opm::UDQTokenType::scalar_func_norm2},
|
||||
{"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:
|
||||
const auto& double_value = try_parse_double(keyword);
|
||||
if (double_value.has_value())
|
||||
if (const auto double_value = try_parse_double(keyword);
|
||||
double_value.has_value())
|
||||
{
|
||||
return UDQVarType::SCALAR;
|
||||
}
|
||||
|
||||
return UDQVarType::NONE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UDQVarType targetType(const std::string& keyword, const std::vector<std::string>& selector) {
|
||||
auto tt = targetType(keyword);
|
||||
|
||||
if (tt == UDQVarType::WELL_VAR || tt == UDQVarType::GROUP_VAR) {
|
||||
if (selector.empty())
|
||||
UDQVarType targetType(const std::string& keyword,
|
||||
const std::vector<std::string>& selector)
|
||||
{
|
||||
const auto tt = targetType(keyword);
|
||||
if ((tt == UDQVarType::WELL_VAR) || (tt == UDQVarType::GROUP_VAR)) {
|
||||
if (selector.empty() || (selector.front().find("*") != std::string::npos)) {
|
||||
return tt;
|
||||
else {
|
||||
const auto& wgname = selector[0];
|
||||
if (wgname.find("*") != std::string::npos)
|
||||
return tt;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (keyword[1] != 'U')
|
||||
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type");
|
||||
const 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;
|
||||
|
||||
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:
|
||||
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
UDQAction actionType(const std::string& action_string) {
|
||||
if (action_string == "ASSIGN")
|
||||
UDQAction actionType(const std::string& action_string)
|
||||
{
|
||||
if (action_string == "ASSIGN") {
|
||||
return UDQAction::ASSIGN;
|
||||
}
|
||||
|
||||
if (action_string == "DEFINE")
|
||||
if (action_string == "DEFINE") {
|
||||
return UDQAction::DEFINE;
|
||||
}
|
||||
|
||||
if (action_string == "UNITS")
|
||||
if (action_string == "UNITS") {
|
||||
return UDQAction::UNITS;
|
||||
}
|
||||
|
||||
if (action_string == "UPDATE")
|
||||
if (action_string == "UPDATE") {
|
||||
return UDQAction::UPDATE;
|
||||
}
|
||||
|
||||
throw std::invalid_argument("Invalid action string " + action_string);
|
||||
}
|
||||
|
||||
|
||||
UDQUpdate updateType(const std::string& update_string) {
|
||||
if (update_string == "ON")
|
||||
UDQUpdate updateType(const std::string& update_string)
|
||||
{
|
||||
if (update_string == "ON") {
|
||||
return UDQUpdate::ON;
|
||||
}
|
||||
|
||||
if (update_string == "OFF")
|
||||
if (update_string == "OFF") {
|
||||
return UDQUpdate::OFF;
|
||||
}
|
||||
|
||||
if (update_string == "NEXT")
|
||||
if (update_string == "NEXT") {
|
||||
return UDQUpdate::NEXT;
|
||||
}
|
||||
|
||||
throw std::invalid_argument("Invalid status update string " + update_string);
|
||||
}
|
||||
|
||||
UDQUpdate updateType(int int_value) {
|
||||
UDQUpdate updateType(const int int_value)
|
||||
{
|
||||
switch (int_value) {
|
||||
case 0: return UDQUpdate::OFF;
|
||||
case 1: return UDQUpdate::NEXT;
|
||||
case 2: return UDQUpdate::ON;
|
||||
|
||||
default:
|
||||
throw std::logic_error("Invalid integer for UDQUpdate type");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool binaryFunc(UDQTokenType token_type) {
|
||||
return (binary_func.count(token_type) > 0);
|
||||
bool binaryFunc(const UDQTokenType token_type)
|
||||
{
|
||||
return binary_func.find(token_type) != binary_func.end();
|
||||
}
|
||||
|
||||
bool scalarFunc(UDQTokenType token_type) {
|
||||
return (scalar_func.count(token_type) > 0);
|
||||
bool scalarFunc(const UDQTokenType token_type)
|
||||
{
|
||||
return scalar_func.find(token_type) != scalar_func.end();
|
||||
}
|
||||
|
||||
bool elementalUnaryFunc(UDQTokenType token_type) {
|
||||
return (unary_elemental_func.count(token_type) > 0);
|
||||
bool elementalUnaryFunc(const UDQTokenType token_type)
|
||||
{
|
||||
return unary_elemental_func.find(token_type) != unary_elemental_func.end();
|
||||
}
|
||||
|
||||
bool cmpFunc(UDQTokenType token_type) {
|
||||
return (cmp_func.count(token_type) > 0);
|
||||
bool cmpFunc(const UDQTokenType token_type)
|
||||
{
|
||||
return cmp_func.find(token_type) != cmp_func.end();
|
||||
}
|
||||
|
||||
bool setFunc(UDQTokenType token_type) {
|
||||
return (set_func.count(token_type) > 0);
|
||||
bool setFunc(const UDQTokenType token_type)
|
||||
{
|
||||
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_type.count(func_name) > 0)
|
||||
return func_type.at(func_name);
|
||||
|
||||
if (func_name.substr(0,2) == "TU") {
|
||||
if (func_name.substr(0, 2) == "TU") {
|
||||
return UDQTokenType::table_lookup;
|
||||
}
|
||||
|
||||
return UDQTokenType::error;
|
||||
}
|
||||
|
||||
UDQTokenType tokenType(const std::string& token) {
|
||||
auto token_type = funcType(token);
|
||||
if (token_type == UDQTokenType::error) {
|
||||
if (token == "(")
|
||||
token_type = UDQTokenType::open_paren;
|
||||
else if (token == ")")
|
||||
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;
|
||||
}
|
||||
UDQTokenType tokenType(const std::string& token)
|
||||
{
|
||||
if (const auto token_type = funcType(token);
|
||||
token_type != UDQTokenType::error)
|
||||
{
|
||||
return token_type;
|
||||
}
|
||||
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)
|
||||
return t1;
|
||||
|
||||
if (t1 == UDQVarType::WELL_VAR ) {
|
||||
if (t2 == UDQVarType::GROUP_VAR)
|
||||
throw std::logic_error("Can not coerce well variable and group variable");
|
||||
|
||||
if (t1 == t2) {
|
||||
return t1;
|
||||
}
|
||||
|
||||
if (t1 == UDQVarType::GROUP_VAR ) {
|
||||
if (t2 == UDQVarType::WELL_VAR)
|
||||
throw std::logic_error("Can not coerce well variable and group variable");
|
||||
const auto is_restricted_t1 = is_no_mix(t1);
|
||||
const auto is_restricted_t2 = is_no_mix(t2);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (t2 == UDQVarType::WELL_VAR ) {
|
||||
if (t1 == UDQVarType::GROUP_VAR)
|
||||
throw std::logic_error("Can not coerce well variable and group variable");
|
||||
|
||||
if (is_restricted_t2) {
|
||||
return t2;
|
||||
}
|
||||
|
||||
if (t2 == UDQVarType::GROUP_VAR ) {
|
||||
if (t1 == UDQVarType::WELL_VAR)
|
||||
throw std::logic_error("Can not coerce well variable and group variable");
|
||||
|
||||
if (t1 == UDQVarType::NONE) {
|
||||
return t2;
|
||||
}
|
||||
|
||||
if (t1 == UDQVarType::NONE)
|
||||
return t2;
|
||||
|
||||
if (t2 == UDQVarType::NONE)
|
||||
if (t2 == UDQVarType::NONE) {
|
||||
return t1;
|
||||
}
|
||||
|
||||
return t1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::string typeName(UDQVarType var_type) {
|
||||
std::string typeName(const UDQVarType var_type)
|
||||
{
|
||||
switch (var_type) {
|
||||
case UDQVarType::NONE:
|
||||
return "NONE";
|
||||
|
||||
case UDQVarType::SCALAR:
|
||||
return "SCALAR";
|
||||
|
||||
case UDQVarType::WELL_VAR:
|
||||
return "WELL_VAR";
|
||||
|
||||
case UDQVarType::CONNECTION_VAR:
|
||||
return "CONNECTION_VAR";
|
||||
|
||||
case UDQVarType::FIELD_VAR:
|
||||
return "FIELD_VAR";
|
||||
|
||||
case UDQVarType::GROUP_VAR:
|
||||
return "GROUP_VAR";
|
||||
|
||||
case UDQVarType::REGION_VAR:
|
||||
return "REGION_VAR";
|
||||
|
||||
case UDQVarType::SEGMENT_VAR:
|
||||
return "SEGMENT_VAR";
|
||||
|
||||
case UDQVarType::AQUIFER_VAR:
|
||||
return "AQUIFER_VAR";
|
||||
|
||||
case UDQVarType::BLOCK_VAR:
|
||||
return "BLOCK_VAR";
|
||||
|
||||
default:
|
||||
throw std::runtime_error("Should not be here: " + std::to_string(static_cast<int>(var_type)));
|
||||
}
|
||||
}
|
||||
|
||||
bool trailingSpace(UDQTokenType token_type) {
|
||||
if (binaryFunc(token_type))
|
||||
return true;
|
||||
|
||||
if (cmpFunc(token_type))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
bool trailingSpace(const UDQTokenType token_type)
|
||||
{
|
||||
return binaryFunc(token_type)
|
||||
|| cmpFunc(token_type);
|
||||
}
|
||||
|
||||
bool leadingSpace(UDQTokenType token_type) {
|
||||
if (binaryFunc(token_type))
|
||||
return true;
|
||||
|
||||
if (cmpFunc(token_type))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
bool leadingSpace(const UDQTokenType token_type)
|
||||
{
|
||||
return binaryFunc(token_type)
|
||||
|| cmpFunc(token_type);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -401,7 +441,7 @@ namespace {
|
||||
throw std::logic_error {
|
||||
"Unrecognized enum type (" +
|
||||
std::to_string(static_cast<int>(control)) +
|
||||
"- internal error"
|
||||
") - internal error"
|
||||
};
|
||||
}
|
||||
|
||||
@ -683,5 +723,4 @@ std::string controlName(const UDAControl control)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}} // Opm::UDQ
|
||||
}} // namespace Opm::UDQ
|
||||
|
@ -17,78 +17,91 @@
|
||||
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/UDQAssign.hpp>
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
|
||||
UDQInput::UDQInput(const UDQIndex& index_arg, const UDQDefine& udq_define, const std::string& unit_arg) :
|
||||
index(index_arg),
|
||||
value(udq_define),
|
||||
m_keyword(udq_define.keyword()),
|
||||
m_var_type(udq_define.var_type()),
|
||||
m_unit(unit_arg)
|
||||
UDQInput::UDQInput(const UDQIndex& index_arg,
|
||||
const UDQDefine& udq_define,
|
||||
const std::string& unit_arg)
|
||||
: index (index_arg)
|
||||
, value (udq_define)
|
||||
, m_keyword (udq_define.keyword())
|
||||
, m_var_type(udq_define.var_type())
|
||||
, m_unit (unit_arg)
|
||||
{}
|
||||
|
||||
|
||||
UDQInput::UDQInput(const UDQIndex& index_arg, const UDQAssign& udq_assign, const std::string& unit_arg):
|
||||
index(index_arg),
|
||||
value(udq_assign),
|
||||
m_keyword(udq_assign.keyword()),
|
||||
m_var_type(udq_assign.var_type()),
|
||||
m_unit(unit_arg)
|
||||
UDQInput::UDQInput(const UDQIndex& index_arg,
|
||||
const UDQAssign& udq_assign,
|
||||
const std::string& unit_arg)
|
||||
: index (index_arg)
|
||||
, value (udq_assign)
|
||||
, m_keyword (udq_assign.keyword())
|
||||
, 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;
|
||||
}
|
||||
|
||||
const std::string& UDQInput::keyword() const {
|
||||
const std::string& UDQInput::keyword() const
|
||||
{
|
||||
return this->m_keyword;
|
||||
}
|
||||
|
||||
const UDQVarType& UDQInput::var_type() const {
|
||||
const UDQVarType& UDQInput::var_type() const
|
||||
{
|
||||
return this->m_var_type;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool UDQInput::is<UDQAssign>() const {
|
||||
bool UDQInput::is<UDQAssign>() const
|
||||
{
|
||||
return std::holds_alternative<UDQAssign>(this->value);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
bool UDQInput::is<UDQDefine>() const {
|
||||
bool UDQInput::is<UDQDefine>() const
|
||||
{
|
||||
return std::holds_alternative<UDQDefine>(this->value);
|
||||
}
|
||||
|
||||
template<>
|
||||
const UDQAssign& UDQInput::get<UDQAssign>() const {
|
||||
if (this->is<UDQAssign>())
|
||||
const UDQAssign& UDQInput::get<UDQAssign>() const
|
||||
{
|
||||
if (this->is<UDQAssign>()) {
|
||||
return std::get<UDQAssign>(this->value);
|
||||
}
|
||||
|
||||
throw std::runtime_error("Invalid get");
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
const UDQDefine& UDQInput::get<UDQDefine>() const {
|
||||
if (this->is<UDQDefine>())
|
||||
const UDQDefine& UDQInput::get<UDQDefine>() const
|
||||
{
|
||||
if (this->is<UDQDefine>()) {
|
||||
return std::get<UDQDefine>(this->value);
|
||||
}
|
||||
|
||||
throw std::runtime_error("Invalid get");
|
||||
}
|
||||
|
||||
|
||||
bool UDQInput::operator==(const UDQInput& other) const {
|
||||
return this->value == other.value &&
|
||||
this->m_keyword == other.m_keyword &&
|
||||
this->m_var_type == other.m_var_type &&
|
||||
this->m_unit == other.m_unit;
|
||||
bool UDQInput::operator==(const UDQInput& other) const
|
||||
{
|
||||
return (this->value == other.value)
|
||||
&& (this->m_keyword == other.m_keyword)
|
||||
&& (this->m_var_type == other.m_var_type)
|
||||
&& (this->m_unit == other.m_unit)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
@ -17,77 +17,131 @@
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
#include "UDQParser.hpp"
|
||||
|
||||
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
||||
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
||||
namespace {
|
||||
|
||||
#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 {
|
||||
|
||||
UDQTokenType UDQParser::get_type(const std::string& arg) const {
|
||||
UDQTokenType UDQParser::get_type(const std::string& arg) const
|
||||
{
|
||||
auto func_type = UDQ::funcType(arg);
|
||||
if (func_type == UDQTokenType::table_lookup)
|
||||
throw std::invalid_argument("Table lookup function TU*[] is not supported in UDQ");
|
||||
if (func_type == UDQTokenType::table_lookup) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (arg == "(")
|
||||
if (arg == "(") {
|
||||
return UDQTokenType::open_paren;
|
||||
}
|
||||
|
||||
if (arg == ")")
|
||||
if (arg == ")") {
|
||||
return UDQTokenType::close_paren;
|
||||
}
|
||||
|
||||
{
|
||||
char * end_ptr;
|
||||
char* 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::ecl_expr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool UDQParser::empty() const {
|
||||
return (static_cast<size_t>(this->current_pos) == this->tokens.size());
|
||||
bool UDQParser::empty() const
|
||||
{
|
||||
return static_cast<std::size_t>(this->current_pos) == this->tokens.size();
|
||||
}
|
||||
|
||||
UDQParseNode UDQParser::next() {
|
||||
UDQParseNode UDQParser::next()
|
||||
{
|
||||
this->current_pos += 1;
|
||||
return this->current();
|
||||
}
|
||||
|
||||
|
||||
|
||||
UDQParseNode UDQParser::current() const {
|
||||
if (this->empty())
|
||||
UDQParseNode UDQParser::current() const
|
||||
{
|
||||
if (this->empty()) {
|
||||
return UDQTokenType::end;
|
||||
}
|
||||
|
||||
const auto& token = this->tokens[current_pos];
|
||||
if (token.type() == UDQTokenType::number)
|
||||
if (token.type() == UDQTokenType::number) {
|
||||
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(this->get_type(std::get<std::string>(token.value())), token.value());
|
||||
}
|
||||
|
||||
|
||||
UDQASTNode UDQParser::parse_factor() {
|
||||
UDQASTNode UDQParser::parse_factor()
|
||||
{
|
||||
double sign = 1.0;
|
||||
auto current = this->current();
|
||||
if (current.type == UDQTokenType::binary_op_add || current.type == UDQTokenType::binary_op_sub) {
|
||||
if (current.type == UDQTokenType::binary_op_sub)
|
||||
if ((current.type == UDQTokenType::binary_op_add) ||
|
||||
(current.type == UDQTokenType::binary_op_sub))
|
||||
{
|
||||
if (current.type == UDQTokenType::binary_op_sub) {
|
||||
sign = -1.0;
|
||||
}
|
||||
|
||||
this->next();
|
||||
current = this->current();
|
||||
}
|
||||
@ -98,8 +152,9 @@ UDQASTNode UDQParser::parse_factor() {
|
||||
auto inner_expr = this->parse_set();
|
||||
|
||||
current = this->current();
|
||||
if (current.type != UDQTokenType::close_paren)
|
||||
if (current.type != UDQTokenType::close_paren) {
|
||||
return UDQASTNode(UDQTokenType::error);
|
||||
}
|
||||
|
||||
this->next();
|
||||
return sign * inner_expr;
|
||||
@ -113,30 +168,37 @@ UDQASTNode UDQParser::parse_factor() {
|
||||
auto arg_expr = this->parse_set();
|
||||
|
||||
current = this->current();
|
||||
if (current.type != UDQTokenType::close_paren)
|
||||
if (current.type != UDQTokenType::close_paren) {
|
||||
return UDQASTNode(UDQTokenType::error);
|
||||
}
|
||||
|
||||
this->next();
|
||||
return sign * UDQASTNode(func_node.type, func_node.value, arg_expr);
|
||||
} else
|
||||
}
|
||||
else {
|
||||
return UDQASTNode(UDQTokenType::error);
|
||||
}
|
||||
}
|
||||
|
||||
UDQASTNode node(current.type, current.value, current.selector);
|
||||
|
||||
this->next();
|
||||
return sign * node;
|
||||
}
|
||||
|
||||
UDQASTNode UDQParser::parse_pow() {
|
||||
UDQASTNode UDQParser::parse_pow()
|
||||
{
|
||||
auto left = this->parse_factor();
|
||||
if (this->empty())
|
||||
if (this->empty()) {
|
||||
return left;
|
||||
}
|
||||
|
||||
auto current = this->current();
|
||||
if (current.type == UDQTokenType::binary_op_pow) {
|
||||
this->next();
|
||||
if (this->empty())
|
||||
if (this->empty()) {
|
||||
return UDQASTNode(UDQTokenType::error);
|
||||
}
|
||||
|
||||
auto right = this->parse_mul();
|
||||
return UDQASTNode(current.type, current.value, left, right);
|
||||
@ -145,9 +207,8 @@ UDQASTNode UDQParser::parse_pow() {
|
||||
return left;
|
||||
}
|
||||
|
||||
|
||||
|
||||
UDQASTNode UDQParser::parse_mul() {
|
||||
UDQASTNode UDQParser::parse_mul()
|
||||
{
|
||||
std::vector<UDQASTNode> nodes;
|
||||
{
|
||||
std::unique_ptr<UDQASTNode> current_node;
|
||||
@ -156,36 +217,48 @@ UDQASTNode UDQParser::parse_mul() {
|
||||
if (current_node) {
|
||||
current_node->set_right(node);
|
||||
nodes.push_back(*current_node);
|
||||
} else
|
||||
}
|
||||
else {
|
||||
nodes.push_back(node);
|
||||
}
|
||||
|
||||
if (this->empty())
|
||||
if (this->empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto current_token = this->current();
|
||||
if (current_token.type == UDQTokenType::binary_op_mul || current_token.type == UDQTokenType::binary_op_div) {
|
||||
current_node.reset( new UDQASTNode(current_token.type, current_token.value) );
|
||||
if ((current_token.type == UDQTokenType::binary_op_mul) ||
|
||||
(current_token.type == UDQTokenType::binary_op_div))
|
||||
{
|
||||
current_node = std::make_unique<UDQASTNode>(current_token.type, current_token.value);
|
||||
|
||||
this->next();
|
||||
if (this->empty())
|
||||
if (this->empty()) {
|
||||
return UDQASTNode( UDQTokenType::error );
|
||||
} else break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UDQASTNode top_node = nodes.back();
|
||||
if (nodes.size() > 1) {
|
||||
UDQASTNode * current = &top_node;
|
||||
UDQASTNode* current = &top_node;
|
||||
for (std::size_t index = nodes.size() - 1; index > 0; index--) {
|
||||
current->set_left(nodes[index - 1]);
|
||||
current = current->get_left();
|
||||
}
|
||||
}
|
||||
|
||||
return top_node;
|
||||
}
|
||||
|
||||
|
||||
UDQASTNode UDQParser::parse_add() {
|
||||
UDQASTNode UDQParser::parse_add()
|
||||
{
|
||||
std::vector<UDQASTNode> nodes;
|
||||
|
||||
{
|
||||
std::unique_ptr<UDQASTNode> current_node;
|
||||
while (true) {
|
||||
@ -193,119 +266,117 @@ UDQASTNode UDQParser::parse_add() {
|
||||
if (current_node) {
|
||||
current_node->set_right(node);
|
||||
nodes.push_back(*current_node);
|
||||
} else
|
||||
}
|
||||
else {
|
||||
nodes.push_back(node);
|
||||
}
|
||||
|
||||
if (this->empty())
|
||||
if (this->empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto current_token = this->current();
|
||||
if (current_token.type == UDQTokenType::binary_op_add || current_token.type == UDQTokenType::binary_op_sub) {
|
||||
current_node.reset( new UDQASTNode(current_token.type, current_token.value) );
|
||||
if ((current_token.type == UDQTokenType::binary_op_add) ||
|
||||
(current_token.type == UDQTokenType::binary_op_sub))
|
||||
{
|
||||
current_node = std::make_unique<UDQASTNode>
|
||||
(current_token.type, current_token.value);
|
||||
|
||||
this->next();
|
||||
if (this->empty())
|
||||
return UDQASTNode( UDQTokenType::error );
|
||||
} else if (current_token.type == UDQTokenType::close_paren || UDQ::cmpFunc(current_token.type) || UDQ::setFunc(current_token.type))
|
||||
if (this->empty()) {
|
||||
return UDQASTNode(UDQTokenType::error);
|
||||
}
|
||||
}
|
||||
else if ((current_token.type == UDQTokenType::close_paren) ||
|
||||
UDQ::cmpFunc(current_token.type) ||
|
||||
UDQ::setFunc(current_token.type))
|
||||
{
|
||||
break;
|
||||
else
|
||||
return UDQASTNode( UDQTokenType::error );
|
||||
}
|
||||
else {
|
||||
return UDQASTNode(UDQTokenType::error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UDQASTNode top_node = nodes.back();
|
||||
if (nodes.size() > 1) {
|
||||
UDQASTNode * current = &top_node;
|
||||
UDQASTNode* current = &top_node;
|
||||
for (std::size_t index = nodes.size() - 1; index > 0; index--) {
|
||||
current->set_left(nodes[index - 1]);
|
||||
current = current->get_left();
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
/*
|
||||
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() {
|
||||
UDQASTNode UDQParser::parse_cmp()
|
||||
{
|
||||
auto left = this->parse_add();
|
||||
if (this->empty())
|
||||
if (this->empty()) {
|
||||
return left;
|
||||
}
|
||||
|
||||
auto current = this->current();
|
||||
if (UDQ::cmpFunc(current.type)) {
|
||||
auto func_node = current;
|
||||
|
||||
this->next();
|
||||
if (this->empty())
|
||||
if (this->empty()) {
|
||||
return UDQASTNode(UDQTokenType::error);
|
||||
}
|
||||
|
||||
auto right = this->parse_cmp();
|
||||
return UDQASTNode(current.type, current.value, left, right);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
|
||||
UDQASTNode UDQParser::parse_set() {
|
||||
UDQASTNode UDQParser::parse_set()
|
||||
{
|
||||
auto left = this->parse_cmp();
|
||||
if (this->empty())
|
||||
if (this->empty()) {
|
||||
return left;
|
||||
}
|
||||
|
||||
auto current = this->current();
|
||||
if (UDQ::setFunc(current.type)) {
|
||||
auto func_node = current;
|
||||
|
||||
this->next();
|
||||
if (this->empty())
|
||||
if (this->empty()) {
|
||||
return UDQASTNode(UDQTokenType::error);
|
||||
}
|
||||
|
||||
auto right = this->parse_set();
|
||||
return UDQASTNode(current.type, current.value, left, right);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
void dump_tokens(const std::string& target_var, const std::vector<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(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)
|
||||
UDQASTNode
|
||||
UDQParser::parse(const UDQParams& udq_params,
|
||||
const 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);
|
||||
parser.next();
|
||||
@ -315,20 +386,26 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type,
|
||||
auto current = parser.current();
|
||||
std::string msg_fmt = fmt::format("Problem parsing UDQ {}\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);
|
||||
return UDQASTNode( udq_params.undefinedValue() );
|
||||
}
|
||||
|
||||
if (!tree.valid()) {
|
||||
std::string token_string;
|
||||
for (const auto& token : tokens)
|
||||
for (const auto& token : tokens) {
|
||||
token_string += token.str() + " ";
|
||||
}
|
||||
|
||||
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
|
||||
"In {{file}} line {{line}}.\n"
|
||||
"This can be a bug in flow or a bug in the UDQ input string.\n"
|
||||
"UDQ input: '{}'", target_var, token_string);
|
||||
"This can be a bug in flow or a "
|
||||
"bug in the UDQ input string.\n"
|
||||
"UDQ input: '{}'",
|
||||
target_var, token_string);
|
||||
|
||||
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
|
||||
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)) {
|
||||
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\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);
|
||||
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE)
|
||||
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE) {
|
||||
dump_tokens(target_var, tokens);
|
||||
}
|
||||
|
||||
return UDQASTNode( udq_params.undefinedValue() );
|
||||
return UDQASTNode(udq_params.undefinedValue());
|
||||
}
|
||||
|
||||
if (tree.var_type == UDQVarType::NONE) {
|
||||
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
|
||||
"In {{file}} line {{line}}.\n"
|
||||
"Could not determine expression type.", target_var);
|
||||
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
|
||||
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE)
|
||||
dump_tokens(target_var, tokens);
|
||||
"Could not determine "
|
||||
"expression type.", target_var);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Opm
|
||||
|
@ -16,70 +16,85 @@
|
||||
OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef 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 <variant>
|
||||
#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 {
|
||||
|
||||
class ParseContext;
|
||||
class ErrorGuard;
|
||||
class KeywordLocation;
|
||||
|
||||
struct UDQParseNode {
|
||||
UDQParseNode(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)
|
||||
} // namespace Opm
|
||||
|
||||
namespace Opm {
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg) :
|
||||
UDQParseNode(type_arg, value_arg, {})
|
||||
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg)
|
||||
: UDQParseNode(type_arg, value_arg, {})
|
||||
{}
|
||||
|
||||
|
||||
// Implicit converting constructor.
|
||||
UDQParseNode(UDQTokenType type_arg) : UDQParseNode(type_arg, "")
|
||||
{}
|
||||
|
||||
std::string string() const {
|
||||
if (std::holds_alternative<std::string>(this->value))
|
||||
std::string string() const
|
||||
{
|
||||
if (std::holds_alternative<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;
|
||||
std::variant<std::string, double> value;
|
||||
std::vector<std::string> selector;
|
||||
UDQVarType var_type = UDQVarType::NONE;
|
||||
};
|
||||
|
||||
|
||||
class UDQParser {
|
||||
class UDQParser
|
||||
{
|
||||
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:
|
||||
UDQParser(const UDQParams& udq_params1, const std::vector<UDQToken>& tokens_) :
|
||||
udq_params(udq_params1),
|
||||
udqft(UDQFunctionTable(udq_params)),
|
||||
tokens(tokens_)
|
||||
UDQParser(const UDQParams& udq_params1,
|
||||
const std::vector<UDQToken>& tokens_)
|
||||
: udq_params(udq_params1)
|
||||
, udqft(UDQFunctionTable(udq_params))
|
||||
, tokens(tokens_)
|
||||
{}
|
||||
|
||||
UDQASTNode parse_set();
|
||||
@ -101,7 +116,6 @@ private:
|
||||
ssize_t current_pos = -1;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // UDQPARSER_HPP
|
||||
|
@ -16,12 +16,21 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.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 {
|
||||
|
||||
@ -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 {
|
||||
for (const auto& res : this->values) {
|
||||
if (res.wgname() == name)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
bool UDQSet::has(const std::string& name) const
|
||||
{
|
||||
return std::any_of(this->values.begin(), this->values.end(),
|
||||
[&name](const UDQScalar& value)
|
||||
{
|
||||
return value.wgname() == name;
|
||||
});
|
||||
}
|
||||
|
||||
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 dsize = 0;
|
||||
for (const auto& v : this->values) {
|
||||
if (v)
|
||||
dsize += 1;
|
||||
}
|
||||
return dsize;
|
||||
std::size_t UDQSet::defined_size() const
|
||||
{
|
||||
return std::count_if(this->values.begin(), this->values.end(),
|
||||
[](const UDQScalar& value)
|
||||
{
|
||||
return value.defined();
|
||||
});
|
||||
}
|
||||
|
||||
const UDQScalar& UDQSet::operator[](std::size_t index) const {
|
||||
if (index >= this->size())
|
||||
const UDQScalar& UDQSet::operator[](std::size_t index) const
|
||||
{
|
||||
if (index >= this->size()) {
|
||||
throw std::out_of_range("Index out of range in UDQset::operator[]");
|
||||
}
|
||||
|
||||
return this->values[index];
|
||||
}
|
||||
|
||||
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())
|
||||
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()) {
|
||||
throw std::out_of_range("No such well/group: " + wgname);
|
||||
}
|
||||
|
||||
return *value_iter;
|
||||
}
|
||||
|
||||
@ -453,54 +474,58 @@ UDQScalar operator/(double lhs, const UDQScalar& rhs) {
|
||||
|
||||
namespace {
|
||||
|
||||
bool is_scalar(const UDQSet& udq_set) {
|
||||
if (udq_set.var_type() == UDQVarType::SCALAR)
|
||||
return true;
|
||||
bool is_scalar(const UDQSet& udq_set)
|
||||
{
|
||||
const auto vtype = udq_set.var_type();
|
||||
|
||||
if (udq_set.var_type() == UDQVarType::FIELD_VAR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return (vtype == UDQVarType::SCALAR)
|
||||
|| (vtype == UDQVarType::FIELD_VAR);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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 subconcious about FIELD / SCALAR.
|
||||
*/
|
||||
// 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.
|
||||
std::pair<UDQSet, UDQSet> udq_cast(const UDQSet& lhs, const UDQSet& rhs)
|
||||
{
|
||||
if (lhs.var_type() == rhs.var_type())
|
||||
return std::make_pair(lhs,rhs);
|
||||
if (lhs.var_type() == rhs.var_type()) {
|
||||
return { lhs, rhs };
|
||||
}
|
||||
|
||||
if (lhs.size() == rhs.size())
|
||||
return std::make_pair(lhs,rhs);
|
||||
if (is_scalar(lhs) && is_scalar(rhs)) {
|
||||
return { lhs, rhs };
|
||||
}
|
||||
|
||||
if (is_scalar(lhs)) {
|
||||
if (rhs.var_type() == UDQVarType::WELL_VAR)
|
||||
return std::make_pair(UDQSet::wells(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs);
|
||||
if (rhs.var_type() == UDQVarType::WELL_VAR) {
|
||||
return { UDQSet::wells(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs };
|
||||
}
|
||||
|
||||
if (rhs.var_type() == UDQVarType::GROUP_VAR)
|
||||
return std::make_pair(UDQSet::groups(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs);
|
||||
if (rhs.var_type() == UDQVarType::GROUP_VAR) {
|
||||
return { UDQSet::groups(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs };
|
||||
}
|
||||
}
|
||||
|
||||
if (is_scalar(rhs)) {
|
||||
if (lhs.var_type() == UDQVarType::WELL_VAR)
|
||||
return std::make_pair(lhs, UDQSet::wells(rhs.name(), lhs.wgnames(), rhs[0].get()));
|
||||
if (lhs.var_type() == UDQVarType::WELL_VAR) {
|
||||
return { lhs, UDQSet::wells(rhs.name(), lhs.wgnames(), rhs[0].get()) };
|
||||
}
|
||||
|
||||
if (lhs.var_type() == UDQVarType::GROUP_VAR)
|
||||
return std::make_pair(lhs, UDQSet::groups(rhs.name(), lhs.wgnames(), rhs[0].get()));
|
||||
if (lhs.var_type() == UDQVarType::GROUP_VAR) {
|
||||
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={})",
|
||||
lhs.name(), lhs.size(), static_cast<int>(lhs.var_type()),
|
||||
rhs.name(), rhs.size(), static_cast<int>(rhs.var_type()));
|
||||
throw std::logic_error(msg);
|
||||
throw std::logic_error {
|
||||
fmt::format("Type/size mismatch when combining UDQs "
|
||||
"{}(size={}, type={}) and "
|
||||
"{}(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) {
|
||||
auto [left,right] = udq_cast(lhs, rhs);
|
||||
@ -584,4 +609,4 @@ bool UDQSet::operator==(const UDQSet& other) const {
|
||||
this->values == other.values;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Opm
|
||||
|
@ -36,47 +36,57 @@ namespace {
|
||||
|
||||
namespace Opm {
|
||||
|
||||
UDQToken::UDQToken(const std::string& string_token, UDQTokenType token_type_) :
|
||||
token_type(token_type_)
|
||||
UDQToken::UDQToken(const std::string& string_token,
|
||||
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);
|
||||
else
|
||||
}
|
||||
else {
|
||||
this->m_value = string_token;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
UDQToken::UDQToken(const std::string& string_token, const std::vector<std::string>& selector_):
|
||||
token_type(UDQTokenType::ecl_expr),
|
||||
m_value(string_token),
|
||||
m_selector(selector_)
|
||||
UDQToken::UDQToken(const std::string& string_token,
|
||||
const std::vector<std::string>& selector_)
|
||||
: token_type(UDQTokenType::ecl_expr)
|
||||
, 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;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& UDQToken::selector() const {
|
||||
const std::vector<std::string>& UDQToken::selector() const
|
||||
{
|
||||
return this->m_selector;
|
||||
}
|
||||
|
||||
UDQTokenType UDQToken::type() const {
|
||||
UDQTokenType UDQToken::type() const
|
||||
{
|
||||
return this->token_type;
|
||||
}
|
||||
|
||||
std::string UDQToken::str() const {
|
||||
std::string UDQToken::str() const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
std::string quoted_selector;
|
||||
for (const auto& s : this->m_selector)
|
||||
for (const auto& s : this->m_selector) {
|
||||
quoted_selector += " '" + s + "'";
|
||||
}
|
||||
|
||||
return std::get<std::string>(this->m_value) + quoted_selector;
|
||||
} else
|
||||
}
|
||||
else {
|
||||
return format_double(std::get<double>(this->m_value));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
|
Loading…
Reference in New Issue
Block a user