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
|
#ifndef UDQASTNODE_HPP
|
||||||
#define UDQASTNODE_HPP
|
#define UDQASTNODE_HPP
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -27,16 +31,13 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
class UDQASTNode {
|
class UDQASTNode
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
|
UDQVarType var_type = UDQVarType::NONE;
|
||||||
|
|
||||||
UDQASTNode();
|
UDQASTNode();
|
||||||
explicit UDQASTNode(UDQTokenType type_arg);
|
explicit UDQASTNode(UDQTokenType type_arg);
|
||||||
explicit UDQASTNode(double scalar_value);
|
explicit UDQASTNode(double scalar_value);
|
||||||
@ -48,21 +49,20 @@ public:
|
|||||||
static UDQASTNode serializationTestObject();
|
static UDQASTNode serializationTestObject();
|
||||||
|
|
||||||
UDQSet eval(UDQVarType eval_target, const UDQContext& context) const;
|
UDQSet eval(UDQVarType eval_target, const UDQContext& context) const;
|
||||||
|
|
||||||
bool valid() const;
|
bool valid() const;
|
||||||
UDQVarType var_type = UDQVarType::NONE;
|
|
||||||
std::set<UDQTokenType> func_tokens() const;
|
std::set<UDQTokenType> func_tokens() const;
|
||||||
|
|
||||||
void update_type(const UDQASTNode& arg);
|
void update_type(const UDQASTNode& arg);
|
||||||
void set_left(const UDQASTNode& arg);
|
void set_left(const UDQASTNode& arg);
|
||||||
void set_right(const UDQASTNode& arg);
|
void set_right(const UDQASTNode& arg);
|
||||||
UDQASTNode* get_left() const;
|
|
||||||
UDQASTNode* get_right() const;
|
|
||||||
void scale(double sign_factor);
|
void scale(double sign_factor);
|
||||||
|
|
||||||
|
UDQASTNode* get_left() const;
|
||||||
|
UDQASTNode* get_right() const;
|
||||||
bool operator==(const UDQASTNode& data) const;
|
bool operator==(const UDQASTNode& data) const;
|
||||||
void required_summary(std::unordered_set<std::string>& summary_keys) const;
|
void required_summary(std::unordered_set<std::string>& summary_keys) const;
|
||||||
|
|
||||||
template<class Serializer>
|
template <class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
{
|
{
|
||||||
serializer(var_type);
|
serializer(var_type);
|
||||||
@ -76,13 +76,34 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
UDQTokenType type;
|
UDQTokenType type;
|
||||||
void func_tokens(std::set<UDQTokenType>& tokens) const;
|
|
||||||
|
|
||||||
std::variant<std::string, double> value;
|
std::variant<std::string, double> value;
|
||||||
double sign = 1.0;
|
double sign = 1.0;
|
||||||
std::vector<std::string> selector;
|
std::vector<std::string> selector;
|
||||||
std::shared_ptr<UDQASTNode> left;
|
std::shared_ptr<UDQASTNode> left;
|
||||||
std::shared_ptr<UDQASTNode> right;
|
std::shared_ptr<UDQASTNode> right;
|
||||||
|
|
||||||
|
UDQSet eval_expression(const UDQContext& context) const;
|
||||||
|
|
||||||
|
UDQSet eval_well_expression(const std::string& string_value,
|
||||||
|
const UDQContext& context) const;
|
||||||
|
|
||||||
|
UDQSet eval_group_expression(const std::string& string_value,
|
||||||
|
const UDQContext& context) const;
|
||||||
|
|
||||||
|
UDQSet eval_scalar_function(const UDQVarType target_type,
|
||||||
|
const UDQContext& context) const;
|
||||||
|
|
||||||
|
UDQSet eval_elemental_unary_function(const UDQVarType target_type,
|
||||||
|
const UDQContext& context) const;
|
||||||
|
|
||||||
|
UDQSet eval_binary_function(const UDQVarType target_type,
|
||||||
|
const UDQContext& context) const;
|
||||||
|
|
||||||
|
UDQSet eval_number(const UDQVarType target_type,
|
||||||
|
const UDQContext& context) const;
|
||||||
|
|
||||||
|
void func_tokens(std::set<UDQTokenType>& tokens) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
UDQASTNode operator*(const UDQASTNode&lhs, double rhs);
|
UDQASTNode operator*(const UDQASTNode&lhs, double rhs);
|
||||||
|
@ -20,20 +20,22 @@
|
|||||||
#ifndef UDQINPUT_HPP_
|
#ifndef UDQINPUT_HPP_
|
||||||
#define UDQINPUT_HPP_
|
#define UDQINPUT_HPP_
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <map>
|
|
||||||
#include <unordered_set>
|
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
|
||||||
|
|
||||||
#include <opm/input/eclipse/EclipseState/Util/OrderedMap.hpp>
|
#include <opm/input/eclipse/EclipseState/Util/OrderedMap.hpp>
|
||||||
#include <opm/input/eclipse/EclipseState/Util/IOrderSet.hpp>
|
#include <opm/input/eclipse/EclipseState/Util/IOrderSet.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
@ -43,12 +45,16 @@ namespace Opm {
|
|||||||
class KeywordLocation;
|
class KeywordLocation;
|
||||||
class WellMatcher;
|
class WellMatcher;
|
||||||
|
|
||||||
namespace RestartIO {
|
} // namespace Opm
|
||||||
struct RstState;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
namespace Opm { namespace RestartIO {
|
||||||
|
struct RstState;
|
||||||
|
}} // namespace Opm::RestartIO
|
||||||
|
|
||||||
class UDQConfig {
|
namespace Opm {
|
||||||
|
|
||||||
|
class UDQConfig
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
UDQConfig() = default;
|
UDQConfig() = default;
|
||||||
explicit UDQConfig(const UDQParams& params);
|
explicit UDQConfig(const UDQParams& params);
|
||||||
@ -91,7 +97,6 @@ namespace Opm {
|
|||||||
bool operator==(const UDQConfig& config) const;
|
bool operator==(const UDQConfig& config) const;
|
||||||
void required_summary(std::unordered_set<std::string>& summary_keys) const;
|
void required_summary(std::unordered_set<std::string>& summary_keys) const;
|
||||||
|
|
||||||
|
|
||||||
template<class Serializer>
|
template<class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
{
|
{
|
||||||
@ -113,20 +118,16 @@ namespace Opm {
|
|||||||
void eval_assign(std::size_t report_step, SummaryState& st, UDQState& udq_state, UDQContext& context) const;
|
void eval_assign(std::size_t report_step, SummaryState& st, UDQState& udq_state, UDQContext& context) const;
|
||||||
void eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const;
|
void eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const;
|
||||||
|
|
||||||
|
|
||||||
UDQParams udq_params;
|
UDQParams udq_params;
|
||||||
UDQFunctionTable udqft;
|
UDQFunctionTable udqft;
|
||||||
|
|
||||||
|
// The choices of data structures are strongly motivated by the
|
||||||
/*
|
// constraints imposed by the ECLIPSE formatted restart files; for
|
||||||
The choices of datastructures are strongly motivated by the
|
// writing restart files it is essential to keep meticulous control
|
||||||
constraints imposed by the Eclipse formatted restart files; for
|
// over the ordering of the keywords. In this class the ordering is
|
||||||
writing restart files it is essential to keep meticolous control over
|
// mainly maintained by the input_index map which keeps track of the
|
||||||
the ordering of the keywords. In this class the ordering is mainly
|
// insert order of each keyword, and whether the keyword is
|
||||||
maintained by the input_index map which keeps track of the insert
|
// currently DEFINE'ed or ASSIGN'ed.
|
||||||
order of each keyword, and whether the keyword is currently DEFINE'ed
|
|
||||||
or ASSIGN'ed.
|
|
||||||
*/
|
|
||||||
std::unordered_map<std::string, UDQDefine> m_definitions;
|
std::unordered_map<std::string, UDQDefine> m_definitions;
|
||||||
std::unordered_map<std::string, UDQAssign> m_assignments;
|
std::unordered_map<std::string, UDQAssign> m_assignments;
|
||||||
std::unordered_map<std::string, std::string> units;
|
std::unordered_map<std::string, std::string> units;
|
||||||
|
@ -17,30 +17,38 @@
|
|||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef UDQ_DEFINE_HPP
|
#ifndef UDQ_DEFINE_HPP
|
||||||
#define UDQ_DEFINE_HPP
|
#define UDQ_DEFINE_HPP
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
|
||||||
|
|
||||||
|
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQContext.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
|
|
||||||
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
|
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
class UDQASTNode;
|
class UDQASTNode;
|
||||||
class ParseContext;
|
class ParseContext;
|
||||||
class ErrorGuard;
|
class ErrorGuard;
|
||||||
|
|
||||||
class UDQDefine{
|
} // Namespace Opm
|
||||||
|
|
||||||
|
namespace Opm {
|
||||||
|
|
||||||
|
class UDQDefine
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
UDQDefine();
|
UDQDefine();
|
||||||
|
|
||||||
@ -73,7 +81,7 @@ public:
|
|||||||
const std::string& keyword() const;
|
const std::string& keyword() const;
|
||||||
const std::string& input_string() const;
|
const std::string& input_string() const;
|
||||||
const KeywordLocation& location() const;
|
const KeywordLocation& location() const;
|
||||||
UDQVarType var_type() const;
|
UDQVarType var_type() const;
|
||||||
std::set<UDQTokenType> func_tokens() const;
|
std::set<UDQTokenType> func_tokens() const;
|
||||||
void required_summary(std::unordered_set<std::string>& summary_keys) const;
|
void required_summary(std::unordered_set<std::string>& summary_keys) const;
|
||||||
void update_status(UDQUpdate update_status, std::size_t report_step);
|
void update_status(UDQUpdate update_status, std::size_t report_step);
|
||||||
@ -82,7 +90,7 @@ public:
|
|||||||
|
|
||||||
bool operator==(const UDQDefine& data) const;
|
bool operator==(const UDQDefine& data) const;
|
||||||
|
|
||||||
template<class Serializer>
|
template <class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
{
|
{
|
||||||
serializer(m_keyword);
|
serializer(m_keyword);
|
||||||
@ -104,8 +112,7 @@ private:
|
|||||||
UDQUpdate m_update_status;
|
UDQUpdate m_update_status;
|
||||||
mutable std::optional<std::string> string_data;
|
mutable std::optional<std::string> string_data;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
} // Namespace Opm
|
||||||
|
|
||||||
|
#endif // UDQ_DEFINE_HPP
|
||||||
#endif
|
|
||||||
|
@ -25,40 +25,41 @@
|
|||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
/*
|
// The UDQ variables can be of many different types. Additionally they can
|
||||||
The UDQ variables can be of of many different types. In addition they can be
|
// be either scalars or vector sets. The archetypal example of a vector set
|
||||||
either scalars or vector sets. The arch example of a vector set is well
|
// is well variables. For instance, in the expressions:
|
||||||
variables - in the expressions:
|
//
|
||||||
|
// UDQ
|
||||||
|
// DEFINE WUBHP WBHP * 1.15 /
|
||||||
|
// DEFINE WUORAT 1000 /
|
||||||
|
// /
|
||||||
|
//
|
||||||
|
// we define two UDQ values 'WUBHP' and 'WUORAT'. Both of these UDQ values
|
||||||
|
// will apply to all wells; the WUBHP vector will correspond to the normal
|
||||||
|
// BHP scaled up 15%, the WUORAT has the scalar value 1000 for all wells.
|
||||||
|
// The well sets can be constrained with a well name. If the well name is a
|
||||||
|
// template, we get a well set. Otherwise, i.e., if the well name is fully
|
||||||
|
// qualified we have a scalar:
|
||||||
|
//
|
||||||
|
// UDQ
|
||||||
|
// DEFINE WUWCT WWCT 'OP*' /
|
||||||
|
// DEFINE FUORAT WOPR 'OPX' * 100 /
|
||||||
|
// /
|
||||||
|
//
|
||||||
|
// Here the UDQ WUCWT corresponds to the well WWCT for all wells matching
|
||||||
|
// the template 'OP*', and it is undefined for other wells. The UDQ FUORAT
|
||||||
|
// is a scalar, given by the WOPR of well 'OPX' - multiplied by 100.
|
||||||
|
//
|
||||||
|
// There are clearly rules for how the different variable types can be
|
||||||
|
// combined in expressions, and what will be resulting type from an
|
||||||
|
// expression - unfortunately that is not yet very well implemented in the
|
||||||
|
// opm codebase. In UDQParser.cpp there is a function static_type_check and
|
||||||
|
// in UDQDefine there is a function dynamic_type_check - these functions try
|
||||||
|
// to verfiy that the type conversions are legitimate, but currently they
|
||||||
|
// are woefully inadequate.
|
||||||
|
|
||||||
UDQ
|
enum class UDQVarType
|
||||||
DEFINE WUBHP WBHP * 1.15 /
|
{
|
||||||
DEFINE WUORAT 1000 /
|
|
||||||
/
|
|
||||||
|
|
||||||
we define two UDQ values 'WUBHP' and 'WUORAT'. Both of these UDQ values will
|
|
||||||
apply to all wells; the WUBHP vector will correspond to the normal BHP scaled
|
|
||||||
up 15%, the WUORAT has the scalar value 1000 for all the wells. The well sets
|
|
||||||
can be qualified with a wellname, if the wellname has a wildcard we will get a
|
|
||||||
well set, if the wellname is fully qualified we have a scalar:
|
|
||||||
|
|
||||||
UDQ
|
|
||||||
DEFINE WUWCT WWCT 'OP*' /
|
|
||||||
DEFINE FUORAT WOPR 'OPX' * 100 /
|
|
||||||
/
|
|
||||||
|
|
||||||
Here the UDQ WUCWT corresponds to the well WWCT for all wells matching the
|
|
||||||
name 'OP*', and it is undefined for the remaing wells. The UDQ FUORAT is a
|
|
||||||
scalar, given by the WOPR of well 'OPX' - multiplied by 100.
|
|
||||||
|
|
||||||
There are clearly rules for how the different variable types can be combined
|
|
||||||
in expressions, and what will be resulting type from an expression -
|
|
||||||
unfortunately that is not yet very well implemented in the opm codebase. In
|
|
||||||
UDQParser.cpp there is a function static_type_check and in UDQDefine there is
|
|
||||||
a function dynamic_type_check - these functions try to verfiy that the type
|
|
||||||
conversions are legitimate, but currently they are woefully inadequate.
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum class UDQVarType {
|
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
SCALAR = 1,
|
SCALAR = 1,
|
||||||
CONNECTION_VAR = 2,
|
CONNECTION_VAR = 2,
|
||||||
@ -68,10 +69,11 @@ enum class UDQVarType {
|
|||||||
AQUIFER_VAR = 6,
|
AQUIFER_VAR = 6,
|
||||||
BLOCK_VAR = 7,
|
BLOCK_VAR = 7,
|
||||||
WELL_VAR = 8,
|
WELL_VAR = 8,
|
||||||
GROUP_VAR = 9
|
GROUP_VAR = 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UDQTokenType{
|
enum class UDQTokenType
|
||||||
|
{
|
||||||
error = 0,
|
error = 0,
|
||||||
number = 1,
|
number = 1,
|
||||||
open_paren = 2,
|
open_paren = 2,
|
||||||
@ -123,23 +125,26 @@ enum class UDQTokenType{
|
|||||||
//
|
//
|
||||||
table_lookup = 47,
|
table_lookup = 47,
|
||||||
//
|
//
|
||||||
end = 100
|
end = 100,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UDQAction {
|
enum class UDQAction
|
||||||
|
{
|
||||||
ASSIGN,
|
ASSIGN,
|
||||||
DEFINE,
|
DEFINE,
|
||||||
UNITS,
|
UNITS,
|
||||||
UPDATE
|
UPDATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UDQUpdate {
|
enum class UDQUpdate
|
||||||
|
{
|
||||||
ON,
|
ON,
|
||||||
OFF,
|
OFF,
|
||||||
NEXT
|
NEXT,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UDAControl {
|
enum class UDAControl
|
||||||
|
{
|
||||||
WCONPROD_ORAT,
|
WCONPROD_ORAT,
|
||||||
WCONPROD_WRAT,
|
WCONPROD_WRAT,
|
||||||
WCONPROD_GRAT,
|
WCONPROD_GRAT,
|
||||||
@ -173,7 +178,8 @@ enum class UDAControl {
|
|||||||
WELTARG_LIFT,
|
WELTARG_LIFT,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class UDAKeyword {
|
enum class UDAKeyword
|
||||||
|
{
|
||||||
WCONPROD,
|
WCONPROD,
|
||||||
WCONINJE,
|
WCONINJE,
|
||||||
WELTARG,
|
WELTARG,
|
||||||
@ -187,11 +193,15 @@ namespace UDQ {
|
|||||||
UDQVarType targetType(const std::string& keyword);
|
UDQVarType targetType(const std::string& keyword);
|
||||||
UDQVarType varType(const std::string& keyword);
|
UDQVarType varType(const std::string& keyword);
|
||||||
UDQVarType coerce(UDQVarType t1, UDQVarType t2);
|
UDQVarType coerce(UDQVarType t1, UDQVarType t2);
|
||||||
|
|
||||||
UDQAction actionType(const std::string& action_string);
|
UDQAction actionType(const std::string& action_string);
|
||||||
|
|
||||||
UDQUpdate updateType(const std::string& update_string);
|
UDQUpdate updateType(const std::string& update_string);
|
||||||
UDQUpdate updateType(int int_value);
|
UDQUpdate updateType(int int_value);
|
||||||
|
|
||||||
UDQTokenType tokenType(const std::string& func_name);
|
UDQTokenType tokenType(const std::string& func_name);
|
||||||
UDQTokenType funcType(const std::string& func_name);
|
UDQTokenType funcType(const std::string& func_name);
|
||||||
|
|
||||||
bool binaryFunc(UDQTokenType token_type);
|
bool binaryFunc(UDQTokenType token_type);
|
||||||
bool elementalUnaryFunc(UDQTokenType token_type);
|
bool elementalUnaryFunc(UDQTokenType token_type);
|
||||||
bool scalarFunc(UDQTokenType token_type);
|
bool scalarFunc(UDQTokenType token_type);
|
||||||
@ -208,12 +218,15 @@ namespace UDQ {
|
|||||||
|
|
||||||
std::string typeName(UDQVarType var_type);
|
std::string typeName(UDQVarType var_type);
|
||||||
std::string controlName(UDAControl control);
|
std::string controlName(UDAControl control);
|
||||||
|
|
||||||
UDAKeyword keyword(UDAControl control);
|
UDAKeyword keyword(UDAControl control);
|
||||||
int udaCode(UDAControl control);
|
int udaCode(UDAControl control);
|
||||||
UDAControl udaControl(int uda_code);
|
UDAControl udaControl(int uda_code);
|
||||||
|
|
||||||
constexpr double restart_default = -0.3E+21;
|
constexpr double restart_default = -0.3E+21;
|
||||||
} // UDQ
|
|
||||||
} // Opm
|
|
||||||
|
|
||||||
#endif // UDQ_ENUMS_HPP
|
} // namespace UDQ
|
||||||
|
|
||||||
|
} // namespace Opm
|
||||||
|
|
||||||
|
#endif // UDQ_ENUMS_HPP
|
||||||
|
@ -17,32 +17,33 @@
|
|||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef UDQINPUT__HPP_
|
#ifndef UDQINPUT__HPP_
|
||||||
#define UDQINPUT__HPP_
|
#define UDQINPUT__HPP_
|
||||||
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
class UDQAssign;
|
class UDQIndex
|
||||||
class UDQDefine;
|
{
|
||||||
|
|
||||||
class UDQIndex {
|
|
||||||
public:
|
public:
|
||||||
UDQIndex() = default;
|
UDQIndex() = default;
|
||||||
|
|
||||||
UDQIndex(std::size_t insert_index_arg, std::size_t typed_insert_index_arg, UDQAction action_arg, UDQVarType var_type_arg) :
|
UDQIndex(const std::size_t insert_index_arg,
|
||||||
insert_index(insert_index_arg),
|
const std::size_t typed_insert_index_arg,
|
||||||
typed_insert_index(typed_insert_index_arg),
|
const UDQAction action_arg,
|
||||||
action(action_arg),
|
const UDQVarType var_type_arg)
|
||||||
var_type(var_type_arg)
|
: insert_index (insert_index_arg)
|
||||||
{
|
, typed_insert_index(typed_insert_index_arg)
|
||||||
}
|
, action (action_arg)
|
||||||
|
, var_type (var_type_arg)
|
||||||
|
{}
|
||||||
|
|
||||||
static UDQIndex serializationTestObject()
|
static UDQIndex serializationTestObject()
|
||||||
{
|
{
|
||||||
@ -55,14 +56,16 @@ public:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const UDQIndex& data) const {
|
bool operator==(const UDQIndex& data) const
|
||||||
return insert_index == data.insert_index &&
|
{
|
||||||
typed_insert_index == data.typed_insert_index &&
|
return (insert_index == data.insert_index)
|
||||||
action == data.action &&
|
&& (typed_insert_index == data.typed_insert_index)
|
||||||
var_type == data.var_type;
|
&& (action == data.action)
|
||||||
|
&& (var_type == data.var_type)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Serializer>
|
template <class Serializer>
|
||||||
void serializeOp(Serializer& serializer)
|
void serializeOp(Serializer& serializer)
|
||||||
{
|
{
|
||||||
serializer(insert_index);
|
serializer(insert_index);
|
||||||
@ -77,16 +80,16 @@ public:
|
|||||||
UDQVarType var_type;
|
UDQVarType var_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UDQInput
|
||||||
class UDQInput{
|
{
|
||||||
public:
|
public:
|
||||||
UDQInput(const UDQIndex& index, const UDQDefine& udq_define, const std::string& unit);
|
UDQInput(const UDQIndex& index, const UDQDefine& udq_define, const std::string& unit);
|
||||||
UDQInput(const UDQIndex& index, const UDQAssign& udq_assign, const std::string& unit);
|
UDQInput(const UDQIndex& index, const UDQAssign& udq_assign, const std::string& unit);
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
const T& get() const;
|
const T& get() const;
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
bool is() const;
|
bool is() const;
|
||||||
|
|
||||||
const std::string& keyword() const;
|
const std::string& keyword() const;
|
||||||
@ -95,14 +98,14 @@ public:
|
|||||||
const UDQIndex index;
|
const UDQIndex index;
|
||||||
|
|
||||||
bool operator==(const UDQInput& other) const;
|
bool operator==(const UDQInput& other) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::variant<UDQDefine, UDQAssign> value;
|
std::variant<UDQDefine, UDQAssign> value;
|
||||||
const std::string m_keyword;
|
std::string m_keyword;
|
||||||
UDQVarType m_var_type;
|
UDQVarType m_var_type;
|
||||||
const std::string m_unit;
|
std::string m_unit;
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
} // namespace Opm
|
||||||
|
|
||||||
|
#endif // UDQINPUT__HPP_
|
||||||
#endif
|
|
||||||
|
@ -20,17 +20,19 @@
|
|||||||
#ifndef UDQSET_HPP
|
#ifndef UDQSET_HPP
|
||||||
#define UDQSET_HPP
|
#define UDQSET_HPP
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
class UDQScalar {
|
class UDQScalar
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
UDQScalar() = default;
|
UDQScalar() = default;
|
||||||
explicit UDQScalar(double value);
|
explicit UDQScalar(double value);
|
||||||
@ -60,12 +62,14 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class UDQSet {
|
class UDQSet
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
UDQSet(const std::string& name, UDQVarType var_type);
|
UDQSet(const std::string& name, UDQVarType var_type);
|
||||||
UDQSet(const std::string& name, UDQVarType var_type, const std::vector<std::string>& wgnames);
|
UDQSet(const std::string& name, UDQVarType var_type, const std::vector<std::string>& wgnames);
|
||||||
UDQSet(const std::string& name, UDQVarType var_type, std::size_t size);
|
UDQSet(const std::string& name, UDQVarType var_type, std::size_t size);
|
||||||
UDQSet(const std::string& name, std::size_t size);
|
UDQSet(const std::string& name, std::size_t size);
|
||||||
|
|
||||||
static UDQSet scalar(const std::string& name, const std::optional<double>& scalar_value);
|
static UDQSet scalar(const std::string& name, const std::optional<double>& scalar_value);
|
||||||
static UDQSet scalar(const std::string& name, double value);
|
static UDQSet scalar(const std::string& name, double value);
|
||||||
static UDQSet empty(const std::string& name);
|
static UDQSet empty(const std::string& name);
|
||||||
@ -84,6 +88,7 @@ public:
|
|||||||
|
|
||||||
bool has(const std::string& name) const;
|
bool has(const std::string& name) const;
|
||||||
std::size_t size() const;
|
std::size_t size() const;
|
||||||
|
|
||||||
void operator+=(const UDQSet& rhs);
|
void operator+=(const UDQSet& rhs);
|
||||||
void operator+=(double rhs);
|
void operator+=(double rhs);
|
||||||
void operator-=(const UDQSet& rhs);
|
void operator-=(const UDQSet& rhs);
|
||||||
@ -105,6 +110,7 @@ public:
|
|||||||
void name(const std::string& name);
|
void name(const std::string& name);
|
||||||
UDQVarType var_type() const;
|
UDQVarType var_type() const;
|
||||||
bool operator==(const UDQSet& other) const;
|
bool operator==(const UDQSet& other) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UDQSet() = default;
|
UDQSet() = default;
|
||||||
|
|
||||||
|
@ -16,91 +16,131 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQFunction.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQFunction.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
|
||||||
|
|
||||||
namespace Opm {
|
|
||||||
|
|
||||||
UDQASTNode::UDQASTNode() :
|
|
||||||
UDQASTNode(UDQTokenType::error)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
UDQASTNode::UDQASTNode(UDQTokenType type_arg) :
|
|
||||||
var_type(UDQVarType::NONE),
|
|
||||||
type(type_arg)
|
|
||||||
{
|
|
||||||
if (type == UDQTokenType::error)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (type == UDQTokenType::binary_op_add)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (type == UDQTokenType::binary_op_sub)
|
|
||||||
return;
|
|
||||||
throw std::invalid_argument("The one argument constructor is only available for error and end");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
UDQVarType init_type(UDQTokenType token_type)
|
bool is_udq(const std::string& key)
|
||||||
{
|
{
|
||||||
if (token_type == UDQTokenType::number)
|
return (key.size() >= std::string::size_type{2})
|
||||||
return UDQVarType::SCALAR;
|
&& (key[1] == 'U');
|
||||||
|
|
||||||
if (UDQ::scalarFunc(token_type))
|
|
||||||
return UDQVarType::SCALAR;
|
|
||||||
|
|
||||||
return UDQVarType::NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opm::UDQVarType init_type(const Opm::UDQTokenType token_type)
|
||||||
|
{
|
||||||
|
if (token_type == Opm::UDQTokenType::number) {
|
||||||
|
return Opm::UDQVarType::SCALAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Opm::UDQ::scalarFunc(token_type)) {
|
||||||
|
return Opm::UDQVarType::SCALAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Opm::UDQVarType::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
UDQASTNode::UDQASTNode(double numeric_value) :
|
namespace Opm {
|
||||||
var_type(init_type(UDQTokenType::number)),
|
|
||||||
type(UDQTokenType::number),
|
UDQASTNode::UDQASTNode()
|
||||||
value(numeric_value)
|
: UDQASTNode(UDQTokenType::error)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
UDQASTNode::UDQASTNode(const UDQTokenType type_arg)
|
||||||
UDQASTNode::UDQASTNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg) :
|
: var_type(UDQVarType::NONE)
|
||||||
var_type(init_type(type_arg)),
|
, type (type_arg)
|
||||||
type(type_arg),
|
|
||||||
value(value_arg)
|
|
||||||
{
|
{
|
||||||
|
if ((this->type == UDQTokenType::error) ||
|
||||||
|
(this->type == UDQTokenType::binary_op_add) ||
|
||||||
|
(this->type == UDQTokenType::binary_op_sub))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::invalid_argument {
|
||||||
|
"Single argument AST node constructor available only "
|
||||||
|
"for error and binary addition/subtraction tokens"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQASTNode::UDQASTNode(double numeric_value)
|
||||||
|
: var_type(init_type(UDQTokenType::number))
|
||||||
|
, type (UDQTokenType::number)
|
||||||
|
, value (numeric_value)
|
||||||
|
{}
|
||||||
|
|
||||||
UDQASTNode::UDQASTNode(UDQTokenType type_arg,
|
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
|
||||||
|
const std::variant<std::string, double>& value_arg)
|
||||||
|
: var_type(init_type(type_arg))
|
||||||
|
, type (type_arg)
|
||||||
|
, value (value_arg)
|
||||||
|
{}
|
||||||
|
|
||||||
|
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
|
||||||
const std::variant<std::string, double>& value_arg,
|
const std::variant<std::string, double>& value_arg,
|
||||||
const UDQASTNode& left_arg)
|
const UDQASTNode& left_arg)
|
||||||
: UDQASTNode(type_arg, value_arg)
|
: UDQASTNode(type_arg, value_arg)
|
||||||
{
|
{
|
||||||
if (UDQ::scalarFunc(type_arg))
|
if (UDQ::scalarFunc(type_arg)) {
|
||||||
this->var_type = UDQVarType::SCALAR;
|
this->var_type = UDQVarType::SCALAR;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
this->var_type = left_arg.var_type;
|
this->var_type = left_arg.var_type;
|
||||||
|
}
|
||||||
|
|
||||||
this->left = std::make_unique<UDQASTNode>(left_arg);
|
this->left = std::make_unique<UDQASTNode>(left_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
|
||||||
UDQASTNode::UDQASTNode(UDQTokenType type_arg,
|
|
||||||
const std::variant<std::string, double>& value_arg,
|
const std::variant<std::string, double>& value_arg,
|
||||||
const UDQASTNode& left_arg,
|
const UDQASTNode& left_arg,
|
||||||
const UDQASTNode& right_arg) :
|
const UDQASTNode& right_arg)
|
||||||
var_type(init_type(type_arg)),
|
: var_type(init_type(type_arg))
|
||||||
type(type_arg),
|
, type (type_arg)
|
||||||
value(value_arg)
|
, value (value_arg)
|
||||||
{
|
{
|
||||||
this->set_left(left_arg);
|
this->set_left(left_arg);
|
||||||
this->set_right(right_arg);
|
this->set_right(right_arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQASTNode::UDQASTNode(const UDQTokenType type_arg,
|
||||||
|
const std::variant<std::string, double>& value_arg,
|
||||||
|
const std::vector<std::string>& selector_arg)
|
||||||
|
: var_type(init_type(type_arg))
|
||||||
|
, type (type_arg)
|
||||||
|
, value (value_arg)
|
||||||
|
, selector(selector_arg)
|
||||||
|
{
|
||||||
|
if (type_arg == UDQTokenType::ecl_expr) {
|
||||||
|
this->var_type = UDQ::targetType(std::get<std::string>(this->value), this->selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((this->var_type == UDQVarType::CONNECTION_VAR) ||
|
||||||
|
(this->var_type == UDQVarType::REGION_VAR) ||
|
||||||
|
(this->var_type == UDQVarType::SEGMENT_VAR) ||
|
||||||
|
(this->var_type == UDQVarType::AQUIFER_VAR) ||
|
||||||
|
(this->var_type == UDQVarType::BLOCK_VAR))
|
||||||
|
{
|
||||||
|
throw std::invalid_argument {
|
||||||
|
"UDQ variable of type: " + UDQ::typeName(this->var_type) + " not yet supported in flow"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UDQASTNode UDQASTNode::serializationTestObject()
|
UDQASTNode UDQASTNode::serializationTestObject()
|
||||||
{
|
{
|
||||||
@ -110,257 +150,323 @@ UDQASTNode UDQASTNode::serializationTestObject()
|
|||||||
result.value = "test1";
|
result.value = "test1";
|
||||||
result.selector = {"test2"};
|
result.selector = {"test2"};
|
||||||
result.sign = -1;
|
result.sign = -1;
|
||||||
|
|
||||||
UDQASTNode left = result;
|
UDQASTNode left = result;
|
||||||
result.left = std::make_shared<UDQASTNode>(left);
|
result.left = std::make_shared<UDQASTNode>(left);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQASTNode::UDQASTNode(UDQTokenType type_arg,
|
UDQSet
|
||||||
const std::variant<std::string, double>& value_arg,
|
UDQASTNode::eval(const UDQVarType target_type,
|
||||||
const std::vector<std::string>& selector_arg) :
|
const UDQContext& context) const
|
||||||
var_type(init_type(type_arg)),
|
|
||||||
type(type_arg),
|
|
||||||
value(value_arg),
|
|
||||||
selector(selector_arg)
|
|
||||||
{
|
{
|
||||||
if (type_arg == UDQTokenType::ecl_expr)
|
|
||||||
this->var_type = UDQ::targetType(std::get<std::string>(this->value), this->selector);
|
|
||||||
|
|
||||||
if (this->var_type == UDQVarType::CONNECTION_VAR ||
|
|
||||||
this->var_type == UDQVarType::REGION_VAR ||
|
|
||||||
this->var_type == UDQVarType::SEGMENT_VAR ||
|
|
||||||
this->var_type == UDQVarType::AQUIFER_VAR ||
|
|
||||||
this->var_type == UDQVarType::BLOCK_VAR)
|
|
||||||
throw std::logic_error("UDQ variable of type: " + UDQ::typeName(this->var_type) + " not yet supported in flow");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UDQSet UDQASTNode::eval(UDQVarType target_type, const UDQContext& context) const {
|
|
||||||
if (this->type == UDQTokenType::ecl_expr) {
|
if (this->type == UDQTokenType::ecl_expr) {
|
||||||
const auto& string_value = std::get<std::string>( this->value );
|
return this->sign * this->eval_expression(context);
|
||||||
auto data_type = UDQ::targetType(string_value);
|
|
||||||
if (data_type == UDQVarType::WELL_VAR) {
|
|
||||||
const auto& all_wells = context.wells();
|
|
||||||
|
|
||||||
if (this->selector.empty()) {
|
|
||||||
auto res = UDQSet::wells(string_value, all_wells);
|
|
||||||
for (const auto& well : all_wells)
|
|
||||||
res.assign(well, context.get_well_var(well, string_value));
|
|
||||||
return this->sign * res;
|
|
||||||
} else {
|
|
||||||
const std::string& well_pattern = this->selector[0];
|
|
||||||
if (well_pattern.find('*') == std::string::npos)
|
|
||||||
/*
|
|
||||||
The right hand side is a fully qualified well name without
|
|
||||||
any '*', in this case the right hand side evaluates to a
|
|
||||||
*scalar* - and that scalar value is distributed among all
|
|
||||||
the wells in the result set.
|
|
||||||
*/
|
|
||||||
return this->sign * UDQSet::scalar(string_value, context.get_well_var(well_pattern, string_value));
|
|
||||||
else {
|
|
||||||
/*
|
|
||||||
The right hand side is a set of wells. The result set will
|
|
||||||
be updated for all wells in the right hand set, wells
|
|
||||||
missing in the right hand set will be undefined in the
|
|
||||||
result set.
|
|
||||||
*/
|
|
||||||
auto res = UDQSet::wells(string_value, all_wells);
|
|
||||||
for (const auto& wname : context.wells(well_pattern))
|
|
||||||
res.assign(wname, context.get_well_var(wname, string_value));
|
|
||||||
return this->sign * res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data_type == UDQVarType::GROUP_VAR) {
|
|
||||||
if (this->selector.size() > 0) {
|
|
||||||
const std::string& group_pattern = this->selector[0];
|
|
||||||
if (group_pattern.find("*") == std::string::npos)
|
|
||||||
return UDQSet::scalar(string_value, context.get_group_var(group_pattern, string_value));
|
|
||||||
else
|
|
||||||
throw std::logic_error("Group names with wildcards is not yet supported");
|
|
||||||
} else {
|
|
||||||
const auto& groups = context.groups();
|
|
||||||
auto res = UDQSet::groups(string_value, groups);
|
|
||||||
for (const auto& group : groups)
|
|
||||||
res.assign(group, context.get_group_var(group, string_value));
|
|
||||||
return this->sign * res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data_type == UDQVarType::FIELD_VAR)
|
|
||||||
return this->sign * UDQSet::scalar(string_value, context.get(string_value));
|
|
||||||
|
|
||||||
auto scalar = context.get(string_value);
|
|
||||||
if (scalar.has_value())
|
|
||||||
return this->sign * UDQSet::scalar(string_value, scalar.value());
|
|
||||||
|
|
||||||
throw std::logic_error("Should not be here: var_type: " + UDQ::typeName(data_type) + " stringvalue:" + string_value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (UDQ::scalarFunc(this->type)) {
|
if (UDQ::scalarFunc(this->type)) {
|
||||||
const auto& string_value = std::get<std::string>( this->value );
|
return this->sign * this->eval_scalar_function(target_type, context);
|
||||||
const auto& udqft = context.function_table();
|
|
||||||
const UDQScalarFunction& func = dynamic_cast<const UDQScalarFunction&>(udqft.get(string_value));
|
|
||||||
return this->sign * func.eval( this->left->eval(target_type, context) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (UDQ::elementalUnaryFunc(this->type)) {
|
if (UDQ::elementalUnaryFunc(this->type)) {
|
||||||
const auto& string_value = std::get<std::string>( this->value );
|
return this->sign * this->eval_elemental_unary_function(target_type, context);
|
||||||
auto func_arg = this->left->eval(target_type, context);
|
|
||||||
|
|
||||||
const auto& udqft = context.function_table();
|
|
||||||
const UDQUnaryElementalFunction& func = dynamic_cast<const UDQUnaryElementalFunction&>(udqft.get(string_value));
|
|
||||||
return this->sign * func.eval(func_arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (UDQ::binaryFunc(this->type)) {
|
if (UDQ::binaryFunc(this->type)) {
|
||||||
auto left_arg = this->left->eval(target_type, context);
|
return this->sign * this->eval_binary_function(target_type, context);
|
||||||
auto right_arg = this->right->eval(target_type, context);
|
|
||||||
const auto& string_value = std::get<std::string>( this->value );
|
|
||||||
|
|
||||||
const auto& udqft = context.function_table();
|
|
||||||
const UDQBinaryFunction& func = dynamic_cast<const UDQBinaryFunction&>(udqft.get(string_value));
|
|
||||||
auto res = func.eval(left_arg, right_arg);
|
|
||||||
return this->sign * res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->type == UDQTokenType::number) {
|
if (this->type == UDQTokenType::number) {
|
||||||
const std::string dummy_name = "DUMMY";
|
return this->sign * this->eval_number(target_type, context);
|
||||||
double numeric_value = std::get<double>(this->value);
|
|
||||||
switch(target_type) {
|
|
||||||
case UDQVarType::WELL_VAR:
|
|
||||||
return this->sign * UDQSet::wells(dummy_name, context.wells(), numeric_value);
|
|
||||||
case UDQVarType::GROUP_VAR:
|
|
||||||
return this->sign * UDQSet::groups(dummy_name, context.groups(), numeric_value);
|
|
||||||
case UDQVarType::SCALAR:
|
|
||||||
return this->sign * UDQSet::scalar(dummy_name, numeric_value);
|
|
||||||
case UDQVarType::FIELD_VAR:
|
|
||||||
return this->sign * UDQSet::field(dummy_name, numeric_value);
|
|
||||||
default:
|
|
||||||
throw std::invalid_argument("Unsupported target_type: " + std::to_string(static_cast<int>(target_type)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw std::invalid_argument("Should not be here ... this->type: " + std::to_string(static_cast<int>(this->type)));
|
throw std::invalid_argument {
|
||||||
|
"Should not be here ... this->type: " + std::to_string(static_cast<int>(this->type))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQASTNode::func_tokens(std::set<UDQTokenType>& tokens) const {
|
bool UDQASTNode::valid() const
|
||||||
tokens.insert( this->type );
|
{
|
||||||
if (this->left)
|
return this->type != UDQTokenType::error;
|
||||||
this->left->func_tokens(tokens);
|
|
||||||
if (this->right)
|
|
||||||
this->right->func_tokens(tokens);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<UDQTokenType> UDQASTNode::func_tokens() const {
|
std::set<UDQTokenType> UDQASTNode::func_tokens() const
|
||||||
std::set<UDQTokenType> tokens;
|
{
|
||||||
|
auto tokens = std::set<UDQTokenType>{};
|
||||||
this->func_tokens(tokens);
|
this->func_tokens(tokens);
|
||||||
|
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDQASTNode::update_type(const UDQASTNode& arg)
|
||||||
UDQASTNode* UDQASTNode::get_left() const {
|
{
|
||||||
return this->left.get();
|
if (this->var_type == UDQVarType::NONE) {
|
||||||
}
|
|
||||||
|
|
||||||
UDQASTNode* UDQASTNode::get_right() const {
|
|
||||||
return this->right.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UDQASTNode::update_type(const UDQASTNode& arg) {
|
|
||||||
if (this->var_type == UDQVarType::NONE)
|
|
||||||
this->var_type = arg.var_type;
|
this->var_type = arg.var_type;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
this->var_type = UDQ::coerce(this->var_type, arg.var_type);
|
this->var_type = UDQ::coerce(this->var_type, arg.var_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDQASTNode::set_left(const UDQASTNode& arg)
|
||||||
bool UDQASTNode::valid() const {
|
{
|
||||||
return (this->type != UDQTokenType::error);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UDQASTNode::set_left(const UDQASTNode& arg) {
|
|
||||||
this->left = std::make_unique<UDQASTNode>(arg);
|
this->left = std::make_unique<UDQASTNode>(arg);
|
||||||
this->update_type(arg);
|
this->update_type(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQASTNode::set_right(const UDQASTNode& arg) {
|
void UDQASTNode::set_right(const UDQASTNode& arg)
|
||||||
|
{
|
||||||
this->right = std::make_unique<UDQASTNode>(arg);
|
this->right = std::make_unique<UDQASTNode>(arg);
|
||||||
this->update_type(arg);
|
this->update_type(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQASTNode::scale(double sign_factor) {
|
void UDQASTNode::scale(double sign_factor)
|
||||||
|
{
|
||||||
this->sign *= sign_factor;
|
this->sign *= sign_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UDQASTNode::operator==(const UDQASTNode& data) const {
|
UDQASTNode* UDQASTNode::get_left() const
|
||||||
|
{
|
||||||
|
return this->left.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
UDQASTNode* UDQASTNode::get_right() const
|
||||||
|
{
|
||||||
|
return this->right.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UDQASTNode::operator==(const UDQASTNode& data) const
|
||||||
|
{
|
||||||
if ((this->left && !data.left) ||
|
if ((this->left && !data.left) ||
|
||||||
(!this->left && data.left))
|
(!this->left && data.left))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->left && !(*this->left == *data.left))
|
if (this->left && !(*this->left == *data.left)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((this->right && !data.right) ||
|
if ((this->right && !data.right) ||
|
||||||
(!this->right && data.right))
|
(!this->right && data.right))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->right && !(*this->right == *data.right))
|
if (this->right && !(*this->right == *data.right)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return type == data.type &&
|
return (type == data.type)
|
||||||
var_type == data.var_type &&
|
&& (var_type == data.var_type)
|
||||||
value == data.value &&
|
&& (value == data.value)
|
||||||
selector == data.selector;
|
&& (selector == data.selector)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
void UDQASTNode::required_summary(std::unordered_set<std::string>& summary_keys) const
|
||||||
|
{
|
||||||
bool is_udq(const std::string& key) {
|
|
||||||
if (key.size() < 2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (key[1] != 'U')
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void UDQASTNode::required_summary(std::unordered_set<std::string>& summary_keys) const {
|
|
||||||
if (this->type == UDQTokenType::ecl_expr) {
|
if (this->type == UDQTokenType::ecl_expr) {
|
||||||
if (std::holds_alternative<std::string>(this->value)) {
|
if (std::holds_alternative<std::string>(this->value)) {
|
||||||
const auto& keyword = std::get<std::string>(this->value);
|
const auto& keyword = std::get<std::string>(this->value);
|
||||||
if (!is_udq(keyword))
|
if (!is_udq(keyword)) {
|
||||||
summary_keys.insert(keyword);
|
summary_keys.insert(keyword);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->left)
|
if (this->left) {
|
||||||
this->left->required_summary(summary_keys);
|
this->left->required_summary(summary_keys);
|
||||||
|
}
|
||||||
|
|
||||||
if (this->right)
|
if (this->right) {
|
||||||
this->right->required_summary(summary_keys);
|
this->right->required_summary(summary_keys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQASTNode operator*(const UDQASTNode&lhs, double sign_factor) {
|
UDQSet
|
||||||
|
UDQASTNode::eval_expression(const UDQContext& context) const
|
||||||
|
{
|
||||||
|
const auto& string_value = std::get<std::string>(this->value);
|
||||||
|
const auto data_type = UDQ::targetType(string_value);
|
||||||
|
|
||||||
|
if (data_type == UDQVarType::WELL_VAR) {
|
||||||
|
return this->eval_well_expression(string_value, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_type == UDQVarType::GROUP_VAR) {
|
||||||
|
return this->eval_group_expression(string_value, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_type == UDQVarType::FIELD_VAR) {
|
||||||
|
return UDQSet::scalar(string_value, context.get(string_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto scalar = context.get(string_value); scalar.has_value()) {
|
||||||
|
return UDQSet::scalar(string_value, scalar.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::logic_error {
|
||||||
|
"Should not be here: var_type: '"
|
||||||
|
+ UDQ::typeName(data_type)
|
||||||
|
+ "' stringvalue: '"
|
||||||
|
+ string_value + '\''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
UDQSet
|
||||||
|
UDQASTNode::eval_well_expression(const std::string& string_value,
|
||||||
|
const UDQContext& context) const
|
||||||
|
{
|
||||||
|
const auto& all_wells = context.wells();
|
||||||
|
|
||||||
|
if (this->selector.empty()) {
|
||||||
|
auto res = UDQSet::wells(string_value, all_wells);
|
||||||
|
|
||||||
|
for (const auto& well : all_wells) {
|
||||||
|
res.assign(well, context.get_well_var(well, string_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& well_pattern = this->selector.front();
|
||||||
|
|
||||||
|
if (well_pattern.find('*') == std::string::npos) {
|
||||||
|
// The right hand side is a fully qualified well name without any
|
||||||
|
// '*', in this case the right hand side evaluates to a *scalar* -
|
||||||
|
// and that scalar value is distributed among all the wells in the
|
||||||
|
// result set.
|
||||||
|
return UDQSet::scalar(string_value, context.get_well_var(well_pattern, string_value));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The right hand side is a set of wells. The result set will be
|
||||||
|
// updated for all wells in the right hand set, wells missing in the
|
||||||
|
// right hand set will be undefined in the result set.
|
||||||
|
auto res = UDQSet::wells(string_value, all_wells);
|
||||||
|
for (const auto& wname : context.wells(well_pattern)) {
|
||||||
|
res.assign(wname, context.get_well_var(wname, string_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UDQSet
|
||||||
|
UDQASTNode::eval_group_expression(const std::string& string_value,
|
||||||
|
const UDQContext& context) const
|
||||||
|
{
|
||||||
|
if (! this->selector.empty()) {
|
||||||
|
const std::string& group_pattern = this->selector[0];
|
||||||
|
if (group_pattern.find("*") == std::string::npos) {
|
||||||
|
return UDQSet::scalar(string_value, context.get_group_var(group_pattern, string_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::logic_error("Group names with wildcards is not yet supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& groups = context.groups();
|
||||||
|
|
||||||
|
auto res = UDQSet::groups(string_value, groups);
|
||||||
|
for (const auto& group : groups) {
|
||||||
|
res.assign(group, context.get_group_var(group, string_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
UDQSet
|
||||||
|
UDQASTNode::eval_scalar_function(const UDQVarType target_type,
|
||||||
|
const UDQContext& context) const
|
||||||
|
{
|
||||||
|
const auto& string_value = std::get<std::string>(this->value);
|
||||||
|
const auto& udqft = context.function_table();
|
||||||
|
|
||||||
|
const auto& func = dynamic_cast<const UDQScalarFunction&>(udqft.get(string_value));
|
||||||
|
|
||||||
|
return func.eval(this->left->eval(target_type, context));
|
||||||
|
}
|
||||||
|
|
||||||
|
UDQSet
|
||||||
|
UDQASTNode::eval_elemental_unary_function(const UDQVarType target_type,
|
||||||
|
const UDQContext& context) const
|
||||||
|
{
|
||||||
|
const auto& string_value = std::get<std::string>(this->value);
|
||||||
|
const auto func_arg = this->left->eval(target_type, context);
|
||||||
|
|
||||||
|
const auto& udqft = context.function_table();
|
||||||
|
const auto& func = dynamic_cast<const UDQUnaryElementalFunction&>(udqft.get(string_value));
|
||||||
|
|
||||||
|
return func.eval(func_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
UDQSet
|
||||||
|
UDQASTNode::eval_binary_function(const UDQVarType target_type,
|
||||||
|
const UDQContext& context) const
|
||||||
|
{
|
||||||
|
const auto left_arg = this->left->eval(target_type, context);
|
||||||
|
const auto right_arg = this->right->eval(target_type, context);
|
||||||
|
const auto& string_value = std::get<std::string>(this->value);
|
||||||
|
|
||||||
|
const auto& udqft = context.function_table();
|
||||||
|
const auto& func = dynamic_cast<const UDQBinaryFunction&>(udqft.get(string_value));
|
||||||
|
|
||||||
|
return func.eval(left_arg, right_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
UDQSet
|
||||||
|
UDQASTNode::eval_number(const UDQVarType target_type,
|
||||||
|
const UDQContext& context) const
|
||||||
|
{
|
||||||
|
const auto dummy_name = std::string { "DUMMY" };
|
||||||
|
const auto numeric_value = std::get<double>(this->value);
|
||||||
|
|
||||||
|
switch (target_type) {
|
||||||
|
case UDQVarType::WELL_VAR:
|
||||||
|
return UDQSet::wells(dummy_name, context.wells(), numeric_value);
|
||||||
|
|
||||||
|
case UDQVarType::GROUP_VAR:
|
||||||
|
return UDQSet::groups(dummy_name, context.groups(), numeric_value);
|
||||||
|
|
||||||
|
case UDQVarType::SCALAR:
|
||||||
|
return UDQSet::scalar(dummy_name, numeric_value);
|
||||||
|
|
||||||
|
case UDQVarType::FIELD_VAR:
|
||||||
|
return UDQSet::field(dummy_name, numeric_value);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw std::invalid_argument {
|
||||||
|
"Unsupported target_type: " + std::to_string(static_cast<int>(target_type))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UDQASTNode::func_tokens(std::set<UDQTokenType>& tokens) const
|
||||||
|
{
|
||||||
|
tokens.insert(this->type);
|
||||||
|
|
||||||
|
if (this->left) {
|
||||||
|
this->left->func_tokens(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->right) {
|
||||||
|
this->right->func_tokens(tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UDQASTNode operator*(const UDQASTNode&lhs, double sign_factor)
|
||||||
|
{
|
||||||
UDQASTNode prod = lhs;
|
UDQASTNode prod = lhs;
|
||||||
|
|
||||||
prod.scale(sign_factor);
|
prod.scale(sign_factor);
|
||||||
|
|
||||||
return prod;
|
return prod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQASTNode operator*(double lhs, const UDQASTNode& rhs)
|
||||||
UDQASTNode operator*(double lhs, const UDQASTNode& rhs) {
|
{
|
||||||
return rhs * lhs;
|
return rhs * lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Opm
|
||||||
|
@ -17,45 +17,69 @@
|
|||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
|
||||||
|
|
||||||
#include <opm/io/eclipse/rst/state.hpp>
|
#include <opm/io/eclipse/rst/state.hpp>
|
||||||
|
|
||||||
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
||||||
#include <opm/common/utility/OpmInputError.hpp>
|
#include <opm/common/utility/OpmInputError.hpp>
|
||||||
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
#include <opm/input/eclipse/Schedule/SummaryState.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQConfig.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQState.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Parser/ParserKeywords/U.hpp> // UDQ
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Deck/DeckRecord.hpp>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::string strip_quotes(const std::string& s)
|
||||||
|
{
|
||||||
|
if (s[0] == '\'') {
|
||||||
|
return s.substr(1, s.size() - 2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
namespace {
|
UDQConfig::UDQConfig(const UDQParams& params)
|
||||||
std::string strip_quotes(const std::string& s) {
|
: udq_params(params)
|
||||||
if (s[0] == '\'')
|
, udqft(this->udq_params)
|
||||||
return s.substr(1, s.size() - 2);
|
|
||||||
else
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
UDQConfig::UDQConfig(const UDQParams& params) :
|
|
||||||
udq_params(params),
|
|
||||||
udqft(this->udq_params)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
UDQConfig::UDQConfig(const UDQParams& params, const RestartIO::RstState& rst_state)
|
||||||
UDQConfig::UDQConfig(const UDQParams& params, const RestartIO::RstState& rst_state) :
|
: UDQConfig(params)
|
||||||
UDQConfig(params)
|
|
||||||
{
|
{
|
||||||
for (const auto& rst_udq : rst_state.udqs) {
|
for (const auto& rst_udq : rst_state.udqs) {
|
||||||
if (rst_udq.is_define()) {
|
if (rst_udq.is_define()) {
|
||||||
KeywordLocation location("UDQ", "Restart file", 0);
|
KeywordLocation location("UDQ", "Restart file", 0);
|
||||||
this->add_define(rst_udq.name, location, {rst_udq.expression()}, rst_state.header.report_step);
|
this->add_define(rst_udq.name,
|
||||||
} else
|
location,
|
||||||
this->add_assign(rst_udq.name, rst_udq.assign_selector(), rst_udq.assign_value(), rst_state.header.report_step);
|
{ rst_udq.expression() },
|
||||||
|
rst_state.header.report_step);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->add_assign(rst_udq.name,
|
||||||
|
rst_udq.assign_selector(),
|
||||||
|
rst_udq.assign_value(),
|
||||||
|
rst_state.header.report_step);
|
||||||
|
}
|
||||||
|
|
||||||
this->add_unit(rst_udq.name, rst_udq.unit);
|
this->add_unit(rst_udq.name, rst_udq.unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,113 +98,172 @@ namespace Opm {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UDQParams& UDQConfig::params() const {
|
const UDQParams& UDQConfig::params() const
|
||||||
|
{
|
||||||
return this->udq_params;
|
return this->udq_params;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQConfig::add_node( const std::string& quantity, UDQAction action) {
|
void UDQConfig::add_node(const std::string& quantity, const UDQAction action)
|
||||||
|
{
|
||||||
auto index_iter = this->input_index.find(quantity);
|
auto index_iter = this->input_index.find(quantity);
|
||||||
if (this->input_index.find(quantity) == this->input_index.end()) {
|
if (this->input_index.find(quantity) == this->input_index.end()) {
|
||||||
auto var_type = UDQ::varType(quantity);
|
auto var_type = UDQ::varType(quantity);
|
||||||
auto insert_index = this->input_index.size();
|
auto insert_index = this->input_index.size();
|
||||||
|
|
||||||
this->type_count[var_type] += 1;
|
this->type_count[var_type] += 1;
|
||||||
this->input_index[quantity] = UDQIndex(insert_index, this->type_count[var_type], action, var_type);
|
this->input_index[quantity] = UDQIndex(insert_index, this->type_count[var_type], action, var_type);
|
||||||
} else
|
}
|
||||||
|
else {
|
||||||
index_iter->second.action = action;
|
index_iter->second.action = action;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQConfig::add_assign(const std::string& quantity, const std::vector<std::string>& selector, double value, std::size_t report_step) {
|
void UDQConfig::add_assign(const std::string& quantity,
|
||||||
|
const std::vector<std::string>& selector,
|
||||||
|
const double value,
|
||||||
|
const std::size_t report_step)
|
||||||
|
{
|
||||||
this->add_node(quantity, UDQAction::ASSIGN);
|
this->add_node(quantity, UDQAction::ASSIGN);
|
||||||
|
|
||||||
auto assignment = this->m_assignments.find(quantity);
|
auto assignment = this->m_assignments.find(quantity);
|
||||||
if (assignment == this->m_assignments.end())
|
if (assignment == this->m_assignments.end()) {
|
||||||
this->m_assignments.insert( std::make_pair(quantity, UDQAssign(quantity, selector, value, report_step )));
|
this->m_assignments.emplace(std::piecewise_construct,
|
||||||
else
|
std::forward_as_tuple(quantity),
|
||||||
|
std::forward_as_tuple(quantity, selector,
|
||||||
|
value, report_step));
|
||||||
|
}
|
||||||
|
else {
|
||||||
assignment->second.add_record(selector, value, report_step);
|
assignment->second.add_record(selector, value, report_step);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQConfig::add_assign(const std::string& quantity, const std::unordered_set<std::string>& selector, double value, std::size_t report_step) {
|
void UDQConfig::add_assign(const std::string& quantity,
|
||||||
|
const std::unordered_set<std::string>& selector,
|
||||||
|
const double value,
|
||||||
|
const std::size_t report_step)
|
||||||
|
{
|
||||||
this->add_node(quantity, UDQAction::ASSIGN);
|
this->add_node(quantity, UDQAction::ASSIGN);
|
||||||
|
|
||||||
auto assignment = this->m_assignments.find(quantity);
|
auto assignment = this->m_assignments.find(quantity);
|
||||||
if (assignment == this->m_assignments.end())
|
if (assignment == this->m_assignments.end()) {
|
||||||
this->m_assignments.insert( std::make_pair(quantity, UDQAssign(quantity, selector, value, report_step )));
|
this->m_assignments.emplace(std::piecewise_construct,
|
||||||
else
|
std::forward_as_tuple(quantity),
|
||||||
|
std::forward_as_tuple(quantity, selector,
|
||||||
|
value, report_step));
|
||||||
|
}
|
||||||
|
else {
|
||||||
assignment->second.add_record(selector, value, report_step);
|
assignment->second.add_record(selector, value, report_step);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDQConfig::add_define(const std::string& quantity,
|
||||||
void UDQConfig::add_define(const std::string& quantity, const KeywordLocation& location, const std::vector<std::string>& expression, std::size_t report_step) {
|
const KeywordLocation& location,
|
||||||
|
const std::vector<std::string>& expression,
|
||||||
|
const std::size_t report_step)
|
||||||
|
{
|
||||||
this->add_node(quantity, UDQAction::DEFINE);
|
this->add_node(quantity, UDQAction::DEFINE);
|
||||||
auto defined_iter = this->m_definitions.find( quantity );
|
|
||||||
if (defined_iter != this->m_definitions.end())
|
|
||||||
this->m_definitions.erase( defined_iter );
|
|
||||||
|
|
||||||
this->m_definitions.insert( std::make_pair(quantity, UDQDefine(this->udq_params, quantity, report_step, location, expression)));
|
this->m_definitions.insert_or_assign(quantity,
|
||||||
|
UDQDefine {
|
||||||
|
this->udq_params,
|
||||||
|
quantity,
|
||||||
|
report_step,
|
||||||
|
location,
|
||||||
|
expression
|
||||||
|
});
|
||||||
|
|
||||||
this->define_order.insert(quantity);
|
this->define_order.insert(quantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDQConfig::add_unit(const std::string& keyword, const std::string& quoted_unit)
|
||||||
void UDQConfig::add_unit(const std::string& keyword, const std::string& quoted_unit) {
|
{
|
||||||
const std::string unit = strip_quotes(quoted_unit);
|
const auto unit = strip_quotes(quoted_unit);
|
||||||
const auto pair_ptr = this->units.find(keyword);
|
const auto pair_ptr = this->units.find(keyword);
|
||||||
if (pair_ptr != this->units.end()) {
|
if (pair_ptr != this->units.end()) {
|
||||||
if (pair_ptr->second != unit)
|
if (pair_ptr->second != unit) {
|
||||||
throw std::invalid_argument("Illegal to change unit of UDQ keyword runtime");
|
throw std::invalid_argument("Illegal to change unit of UDQ keyword runtime");
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->units[keyword] = unit;
|
this->units[keyword] = unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDQConfig::add_update(const std::string& keyword,
|
||||||
|
const std::size_t report_step,
|
||||||
|
const KeywordLocation& location,
|
||||||
|
const std::vector<std::string>& data)
|
||||||
|
{
|
||||||
|
if (data.empty()) {
|
||||||
|
throw OpmInputError {
|
||||||
|
fmt::format("Missing third item: ON|OFF|NEXT for UDQ update of {}", keyword),
|
||||||
|
location
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void UDQConfig::add_update(const std::string& keyword, std::size_t report_step, const KeywordLocation& location, const std::vector<std::string>& data) {
|
if (this->m_definitions.count(keyword) == 0) {
|
||||||
if (data.empty())
|
throw OpmInputError {
|
||||||
throw OpmInputError( fmt::format("Missing third item: ON|OFF|NEXT for UDQ update of {}", keyword), location);
|
fmt::format("UDQ variable: {} must be defined before you can use UPDATE", keyword),
|
||||||
|
location
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (this->m_definitions.count(keyword) == 0)
|
const auto update_status = UDQ::updateType(data[0]);
|
||||||
throw OpmInputError( fmt::format("UDQ variable: {} must be defined before you can use UPDATE", keyword), location);
|
|
||||||
|
|
||||||
auto update_status = UDQ::updateType(data[0]);
|
|
||||||
auto& define = this->m_definitions[keyword];
|
auto& define = this->m_definitions[keyword];
|
||||||
define.update_status( update_status, report_step );
|
define.update_status(update_status, report_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDQConfig::add_record(const DeckRecord& record,
|
||||||
|
const KeywordLocation& location,
|
||||||
|
const std::size_t report_step)
|
||||||
|
{
|
||||||
|
using KW = ParserKeywords::UDQ;
|
||||||
|
|
||||||
|
const auto action = UDQ::actionType(record.getItem<KW::ACTION>().get<RawString>(0));
|
||||||
|
const auto& quantity = record.getItem<KW::QUANTITY>().get<std::string>(0);
|
||||||
|
const auto data = RawString::strings(record.getItem<KW::DATA>().getData<RawString>());
|
||||||
|
|
||||||
void UDQConfig::add_record(const DeckRecord& record, const KeywordLocation& location, std::size_t report_step) {
|
if (action == UDQAction::UPDATE) {
|
||||||
auto action = UDQ::actionType(record.getItem("ACTION").get<RawString>(0));
|
|
||||||
const auto& quantity = record.getItem("QUANTITY").get<std::string>(0);
|
|
||||||
const auto& data = RawString::strings( record.getItem("DATA").getData<RawString>() );
|
|
||||||
|
|
||||||
if (action == UDQAction::UPDATE)
|
|
||||||
this->add_update(quantity, report_step, location, data);
|
this->add_update(quantity, report_step, location, data);
|
||||||
else if (action == UDQAction::UNITS)
|
}
|
||||||
this->add_unit( quantity, data[0] );
|
else if (action == UDQAction::UNITS) {
|
||||||
|
this->add_unit(quantity, data.front());
|
||||||
|
}
|
||||||
|
else if (action == UDQAction::ASSIGN) {
|
||||||
|
const auto selector = std::vector<std::string>(data.begin(), data.end() - 1);
|
||||||
|
const auto value = std::stod(data.back());
|
||||||
|
this->add_assign(quantity, selector, value, report_step);
|
||||||
|
}
|
||||||
|
else if (action == UDQAction::DEFINE) {
|
||||||
|
this->add_define(quantity, location, data, report_step);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (action == UDQAction::ASSIGN) {
|
throw std::runtime_error {
|
||||||
std::vector<std::string> selector(data.begin(), data.end() - 1);
|
"Unknown UDQ Operation " + std::to_string(static_cast<int>(action))
|
||||||
double value = std::stod(data.back());
|
};
|
||||||
this->add_assign(quantity, selector, value, report_step);
|
|
||||||
} else if (action == UDQAction::DEFINE)
|
|
||||||
this->add_define(quantity, location, data, report_step);
|
|
||||||
else
|
|
||||||
throw std::runtime_error("Internal error - should not be here");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const UDQAssign& UDQConfig::assign(const std::string& key) const {
|
const UDQAssign& UDQConfig::assign(const std::string& key) const
|
||||||
|
{
|
||||||
return this->m_assignments.at(key);
|
return this->m_assignments.at(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
const UDQDefine& UDQConfig::define(const std::string& key) const {
|
const UDQDefine& UDQConfig::define(const std::string& key) const
|
||||||
|
{
|
||||||
return this->m_definitions.at(key);
|
return this->m_definitions.at(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQAction UDQConfig::action_type(const std::string& udq_key) const {
|
UDQAction UDQConfig::action_type(const std::string& udq_key) const
|
||||||
|
{
|
||||||
auto action_iter = this->input_index.find(udq_key);
|
auto action_iter = this->input_index.find(udq_key);
|
||||||
return action_iter->second.action;
|
return action_iter->second.action;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<UDQDefine> UDQConfig::definitions() const {
|
std::vector<UDQDefine> UDQConfig::definitions() const
|
||||||
|
{
|
||||||
std::vector<UDQDefine> ret;
|
std::vector<UDQDefine> ret;
|
||||||
|
|
||||||
for (const auto& index_pair : this->input_index) {
|
for (const auto& index_pair : this->input_index) {
|
||||||
@ -193,164 +276,184 @@ namespace Opm {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<UDQDefine> UDQConfig::definitions(const UDQVarType var_type) const
|
||||||
std::vector<UDQDefine> UDQConfig::definitions(UDQVarType var_type) const {
|
{
|
||||||
std::vector<UDQDefine> filtered_defines;
|
std::vector<UDQDefine> filtered_defines;
|
||||||
|
|
||||||
for (const auto& index_pair : this->input_index) {
|
for (const auto& index_pair : this->input_index) {
|
||||||
if (index_pair.second.action == UDQAction::DEFINE) {
|
if (index_pair.second.action == UDQAction::DEFINE) {
|
||||||
const std::string& key = index_pair.first;
|
const std::string& key = index_pair.first;
|
||||||
const auto& udq_define = this->m_definitions.at(key);
|
const auto& udq_define = this->m_definitions.at(key);
|
||||||
if (udq_define.var_type() == var_type)
|
if (udq_define.var_type() == var_type) {
|
||||||
filtered_defines.push_back(udq_define);
|
filtered_defines.push_back(udq_define);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return filtered_defines;
|
return filtered_defines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<UDQInput> UDQConfig::input() const
|
||||||
std::vector<UDQInput> UDQConfig::input() const {
|
{
|
||||||
std::vector<UDQInput> res;
|
std::vector<UDQInput> res;
|
||||||
|
|
||||||
for (const auto& index_pair : this->input_index) {
|
for (const auto& index_pair : this->input_index) {
|
||||||
const UDQIndex& index = index_pair.second;
|
const UDQIndex& index = index_pair.second;
|
||||||
std::string u;
|
std::string u;
|
||||||
if (this->has_unit(index_pair.first))
|
if (this->has_unit(index_pair.first)) {
|
||||||
u = this->unit(index_pair.first);
|
u = this->unit(index_pair.first);
|
||||||
|
}
|
||||||
|
|
||||||
if (index.action == UDQAction::DEFINE) {
|
if (index.action == UDQAction::DEFINE) {
|
||||||
const std::string& key = index_pair.first;
|
const std::string& key = index_pair.first;
|
||||||
res.push_back(UDQInput(index, this->m_definitions.at(key), u));
|
res.push_back(UDQInput(index, this->m_definitions.at(key), u));
|
||||||
} else if (index_pair.second.action == UDQAction::ASSIGN) {
|
}
|
||||||
|
else if (index_pair.second.action == UDQAction::ASSIGN) {
|
||||||
const std::string& key = index_pair.first;
|
const std::string& key = index_pair.first;
|
||||||
res.push_back(UDQInput(index, this->m_assignments.at(key), u));
|
res.push_back(UDQInput(index, this->m_assignments.at(key), u));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t UDQConfig::size() const {
|
std::size_t UDQConfig::size() const
|
||||||
std::size_t s = 0;
|
{
|
||||||
for (const auto& index_pair : this->input_index) {
|
return std::count_if(this->input_index.begin(), this->input_index.end(),
|
||||||
if (index_pair.second.action == UDQAction::DEFINE)
|
[](const auto& index_pair)
|
||||||
s += 1;
|
{
|
||||||
else if (index_pair.second.action == UDQAction::ASSIGN)
|
const auto action = index_pair.second.action;
|
||||||
s += 1;
|
|
||||||
}
|
return (action == UDQAction::DEFINE)
|
||||||
return s;
|
|| (action == UDQAction::ASSIGN);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<UDQAssign> UDQConfig::assignments() const
|
||||||
std::vector<UDQAssign> UDQConfig::assignments() const {
|
{
|
||||||
std::vector<UDQAssign> ret;
|
std::vector<UDQAssign> ret;
|
||||||
|
|
||||||
for (const auto& index_pair : this->input_index) {
|
for (const auto& index_pair : this->input_index) {
|
||||||
if (index_pair.second.action == UDQAction::ASSIGN) {
|
if (index_pair.second.action == UDQAction::ASSIGN) {
|
||||||
const std::string& key = index_pair.first;
|
const std::string& key = index_pair.first;
|
||||||
ret.push_back(this->m_assignments.at(key));
|
ret.push_back(this->m_assignments.at(key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<UDQAssign> UDQConfig::assignments(const UDQVarType var_type) const
|
||||||
std::vector<UDQAssign> UDQConfig::assignments(UDQVarType var_type) const {
|
{
|
||||||
std::vector<UDQAssign> filtered_assigns;
|
std::vector<UDQAssign> filtered_assigns;
|
||||||
|
|
||||||
for (const auto& index_pair : this->input_index) {
|
for (const auto& index_pair : this->input_index) {
|
||||||
const std::string& key = index_pair.first;
|
const std::string& key = index_pair.first;
|
||||||
const auto& assign_iter = this->m_assignments.find(key);
|
const auto& assign_iter = this->m_assignments.find(key);
|
||||||
if (assign_iter != this->m_assignments.end()) {
|
if (assign_iter != this->m_assignments.end()) {
|
||||||
if (assign_iter->second.var_type() == var_type)
|
if (assign_iter->second.var_type() == var_type) {
|
||||||
filtered_assigns.push_back(assign_iter->second);
|
filtered_assigns.push_back(assign_iter->second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return filtered_assigns;
|
return filtered_assigns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& UDQConfig::unit(const std::string& key) const
|
||||||
|
{
|
||||||
const std::string& UDQConfig::unit(const std::string& key) const {
|
|
||||||
const auto pair_ptr = this->units.find(key);
|
const auto pair_ptr = this->units.find(key);
|
||||||
if (pair_ptr == this->units.end())
|
if (pair_ptr == this->units.end()) {
|
||||||
throw std::invalid_argument("No such UDQ quantity: " + key);
|
throw std::invalid_argument("No such UDQ quantity: " + key);
|
||||||
|
}
|
||||||
|
|
||||||
return pair_ptr->second;
|
return pair_ptr->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UDQConfig::has_unit(const std::string& keyword) const {
|
bool UDQConfig::has_unit(const std::string& keyword) const
|
||||||
|
{
|
||||||
return (this->units.count(keyword) > 0);
|
return (this->units.count(keyword) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UDQConfig::has_keyword(const std::string& keyword) const
|
||||||
bool UDQConfig::has_keyword(const std::string& keyword) const {
|
{
|
||||||
if (this->m_assignments.count(keyword) > 0)
|
return (this->m_assignments.find(keyword) != this->m_assignments.end())
|
||||||
return true;
|
|| (this->m_definitions.find(keyword) != this->m_definitions.end());
|
||||||
|
|
||||||
if (this->m_definitions.count(keyword) > 0)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQInput UDQConfig::operator[](const std::string& keyword) const
|
||||||
UDQInput UDQConfig::operator[](const std::string& keyword) const {
|
{
|
||||||
const auto index_iter = this->input_index.find(keyword);
|
const auto index_iter = this->input_index.find(keyword);
|
||||||
if (index_iter == this->input_index.end())
|
if (index_iter == this->input_index.end()) {
|
||||||
throw std::invalid_argument("Keyword: " + keyword + " not recognized as ASSIGN/DEFINE UDQ");
|
throw std::invalid_argument("Keyword: '" + keyword +
|
||||||
|
"' not recognized as ASSIGN/DEFINE UDQ");
|
||||||
|
}
|
||||||
|
|
||||||
std::string u;
|
const auto u = this->has_unit(keyword)
|
||||||
if (this->has_unit(keyword))
|
? this->unit(keyword) : std::string{};
|
||||||
u = this->unit(keyword);
|
|
||||||
|
|
||||||
if (index_iter->second.action == UDQAction::ASSIGN)
|
if (index_iter->second.action == UDQAction::ASSIGN) {
|
||||||
return UDQInput(this->input_index.at(keyword), this->m_assignments.at(keyword), u);
|
return UDQInput(this->input_index.at(keyword), this->m_assignments.at(keyword), u);
|
||||||
|
}
|
||||||
|
|
||||||
if (index_iter->second.action == UDQAction::DEFINE)
|
if (index_iter->second.action == UDQAction::DEFINE) {
|
||||||
return UDQInput(this->input_index.at(keyword), this->m_definitions.at(keyword), u);
|
return UDQInput(this->input_index.at(keyword), this->m_definitions.at(keyword), u);
|
||||||
|
}
|
||||||
|
|
||||||
throw std::logic_error("Internal error - should not be here");
|
throw std::logic_error("Internal error - should not be here");
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQInput UDQConfig::operator[](std::size_t insert_index) const {
|
UDQInput UDQConfig::operator[](const std::size_t insert_index) const
|
||||||
|
{
|
||||||
auto index_iter = std::find_if(this->input_index.begin(), this->input_index.end(),
|
auto index_iter = std::find_if(this->input_index.begin(), this->input_index.end(),
|
||||||
[&insert_index](const std::pair<std::string, UDQIndex>& name_index)
|
[insert_index](const std::pair<std::string, UDQIndex>& name_index)
|
||||||
{
|
{
|
||||||
const auto& [_, index] = name_index;
|
return name_index.second.insert_index == insert_index;
|
||||||
(void)_;
|
});
|
||||||
return index.insert_index == insert_index;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (index_iter == this->input_index.end())
|
if (index_iter == this->input_index.end()) {
|
||||||
throw std::invalid_argument("Insert index not recognized");
|
throw std::invalid_argument("Insert index not recognized");
|
||||||
|
}
|
||||||
|
|
||||||
const auto& [keyword, index] = *index_iter;
|
const auto& [keyword, index] = *index_iter;
|
||||||
std::string u;
|
std::string u;
|
||||||
if (this->has_unit(keyword))
|
if (this->has_unit(keyword)) {
|
||||||
u = this->unit(keyword);
|
u = this->unit(keyword);
|
||||||
|
}
|
||||||
|
|
||||||
if (index.action == UDQAction::ASSIGN)
|
if (index.action == UDQAction::ASSIGN) {
|
||||||
return UDQInput(index, this->m_assignments.at(keyword), u);
|
return UDQInput(index, this->m_assignments.at(keyword), u);
|
||||||
|
}
|
||||||
|
|
||||||
if (index.action == UDQAction::DEFINE)
|
if (index.action == UDQAction::DEFINE) {
|
||||||
return UDQInput(index, this->m_definitions.at(keyword), u);
|
return UDQInput(index, this->m_definitions.at(keyword), u);
|
||||||
|
}
|
||||||
|
|
||||||
throw std::logic_error("Internal error - should not be here");
|
throw std::logic_error("Internal error - should not be here");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const UDQFunctionTable& UDQConfig::function_table() const
|
||||||
const UDQFunctionTable& UDQConfig::function_table() const {
|
{
|
||||||
return this->udqft;
|
return this->udqft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UDQConfig::operator==(const UDQConfig& data) const
|
||||||
bool UDQConfig::operator==(const UDQConfig& data) const {
|
{
|
||||||
return this->params() == data.params() &&
|
return (this->params() == data.params())
|
||||||
this->function_table() == data.function_table() &&
|
&& (this->function_table() == data.function_table())
|
||||||
this->m_definitions == data.m_definitions &&
|
&& (this->m_definitions == data.m_definitions)
|
||||||
this->m_assignments == data.m_assignments &&
|
&& (this->m_assignments == data.m_assignments)
|
||||||
this->units == data.units &&
|
&& (this->units == data.units)
|
||||||
this->input_index == data.input_index &&
|
&& (this->input_index == data.input_index)
|
||||||
this->type_count == data.type_count;
|
&& (this->type_count == data.type_count)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQConfig::eval_assign(std::size_t report_step, SummaryState& st, UDQState& udq_state, UDQContext& context) const {
|
void UDQConfig::eval_assign(const std::size_t report_step,
|
||||||
|
SummaryState& st,
|
||||||
|
UDQState& udq_state,
|
||||||
|
UDQContext& context) const
|
||||||
|
{
|
||||||
for (const auto& assign : this->assignments(UDQVarType::WELL_VAR)) {
|
for (const auto& assign : this->assignments(UDQVarType::WELL_VAR)) {
|
||||||
if (udq_state.assign(report_step, assign.keyword())) {
|
if (udq_state.assign(report_step, assign.keyword())) {
|
||||||
auto ws = assign.eval(st.wells());
|
auto ws = assign.eval(st.wells());
|
||||||
@ -373,8 +476,10 @@ namespace Opm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDQConfig::eval_define(const std::size_t report_step,
|
||||||
void UDQConfig::eval_define(std::size_t report_step, UDQState& udq_state, UDQContext& context) const {
|
UDQState& udq_state,
|
||||||
|
UDQContext& context) const
|
||||||
|
{
|
||||||
for (const auto& def : this->definitions(UDQVarType::WELL_VAR)) {
|
for (const auto& def : this->definitions(UDQVarType::WELL_VAR)) {
|
||||||
if (udq_state.define(def.keyword(), def.status())) {
|
if (udq_state.define(def.keyword(), def.status())) {
|
||||||
auto ws = def.eval(context);
|
auto ws = def.eval(context);
|
||||||
@ -397,26 +502,31 @@ namespace Opm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQConfig::eval(std::size_t report_step, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const {
|
void UDQConfig::eval(const std::size_t report_step,
|
||||||
|
const WellMatcher& wm,
|
||||||
|
SummaryState& st,
|
||||||
|
UDQState& udq_state) const
|
||||||
|
{
|
||||||
UDQContext context(this->function_table(), wm, st, udq_state);
|
UDQContext context(this->function_table(), wm, st, udq_state);
|
||||||
this->eval_assign(report_step, st, udq_state, context);
|
this->eval_assign(report_step, st, udq_state, context);
|
||||||
this->eval_define(report_step, udq_state, context);
|
this->eval_define(report_step, udq_state, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQConfig::eval_assign(std::size_t report_step, const WellMatcher& wm, SummaryState& st, UDQState& udq_state) const {
|
void UDQConfig::eval_assign(const std::size_t report_step,
|
||||||
|
const WellMatcher& wm,
|
||||||
|
SummaryState& st,
|
||||||
|
UDQState& udq_state) const
|
||||||
|
{
|
||||||
UDQContext context(this->function_table(), wm, st, udq_state);
|
UDQContext context(this->function_table(), wm, st, udq_state);
|
||||||
this->eval_assign(report_step, st, udq_state, context);
|
this->eval_assign(report_step, st, udq_state, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDQConfig::required_summary(std::unordered_set<std::string>& summary_keys) const
|
||||||
void UDQConfig::required_summary(std::unordered_set<std::string>& summary_keys) const {
|
{
|
||||||
for (const auto& def_pair : this->m_definitions) {
|
for (const auto& def_pair : this->m_definitions) {
|
||||||
const auto& udq_def = def_pair.second;
|
const auto& udq_def = def_pair.second;
|
||||||
udq_def.required_summary(summary_keys);
|
udq_def.required_summary(summary_keys);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Opm
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,127 +16,126 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <iostream>
|
|
||||||
#include <cstring>
|
|
||||||
#include <tuple>
|
|
||||||
#include <fmt/format.h>
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
#include <opm/common/utility/String.hpp>
|
|
||||||
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
|
||||||
#include <opm/input/eclipse/Parser/ErrorGuard.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
|
||||||
|
|
||||||
|
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||||
|
#include <opm/common/utility/String.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
|
||||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
|
||||||
|
#include <opm/input/eclipse/Parser/ErrorGuard.hpp>
|
||||||
|
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
||||||
|
|
||||||
#include "../../Parser/raw/RawConsts.hpp"
|
#include "../../Parser/raw/RawConsts.hpp"
|
||||||
#include "UDQParser.hpp"
|
#include "UDQParser.hpp"
|
||||||
|
|
||||||
namespace Opm {
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::vector<std::string> quote_split(const std::string& item) {
|
std::vector<std::string> quote_split(const std::string& item)
|
||||||
|
{
|
||||||
char quote_char = '\'';
|
char quote_char = '\'';
|
||||||
std::vector<std::string> items;
|
std::vector<std::string> items;
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
auto quote_pos1 = item.find(quote_char, offset);
|
auto quote_pos1 = item.find(quote_char, offset);
|
||||||
if (quote_pos1 == std::string::npos) {
|
if (quote_pos1 == std::string::npos) {
|
||||||
if (offset < item.size())
|
if (offset < item.size()) {
|
||||||
items.push_back(item.substr(offset));
|
items.push_back(item.substr(offset));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto quote_pos2 = item.find(quote_char, quote_pos1 + 1);
|
auto quote_pos2 = item.find(quote_char, quote_pos1 + 1);
|
||||||
if (quote_pos2 == std::string::npos)
|
if (quote_pos2 == std::string::npos) {
|
||||||
throw std::invalid_argument("Unbalanced quotes in: " + item);
|
throw std::invalid_argument("Unbalanced quotes in: " + item);
|
||||||
|
}
|
||||||
|
|
||||||
if (quote_pos1 > offset)
|
if (quote_pos1 > offset) {
|
||||||
items.push_back(item.substr(offset, quote_pos1 - offset));
|
items.push_back(item.substr(offset, quote_pos1 - offset));
|
||||||
|
}
|
||||||
|
|
||||||
items.push_back(item.substr(quote_pos1, 1 + quote_pos2 - quote_pos1));
|
items.push_back(item.substr(quote_pos1, 1 + quote_pos2 - quote_pos1));
|
||||||
offset = quote_pos2 + 1;
|
offset = quote_pos2 + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Opm::UDQToken>
|
||||||
|
make_tokens(const std::vector<std::string>& string_tokens)
|
||||||
|
{
|
||||||
std::vector<UDQToken> make_tokens(const std::vector<std::string>& string_tokens) {
|
if (string_tokens.empty()) {
|
||||||
if (string_tokens.empty())
|
|
||||||
return {};
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<UDQToken> tokens;
|
std::vector<Opm::UDQToken> tokens;
|
||||||
std::size_t token_index = 0;
|
std::size_t token_index = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
const auto& string_token = string_tokens[token_index];
|
const auto& string_token = string_tokens[token_index];
|
||||||
auto token_type = UDQ::tokenType(string_tokens[token_index]);
|
auto token_type = Opm::UDQ::tokenType(string_tokens[token_index]);
|
||||||
token_index += 1;
|
token_index += 1;
|
||||||
|
|
||||||
if (token_type == UDQTokenType::ecl_expr) {
|
if (token_type == Opm::UDQTokenType::ecl_expr) {
|
||||||
std::vector<std::string> selector;
|
std::vector<std::string> selector;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (token_index == string_tokens.size())
|
if (token_index == string_tokens.size()) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
auto next_type = UDQ::tokenType(string_tokens[token_index]);
|
auto next_type = Opm::UDQ::tokenType(string_tokens[token_index]);
|
||||||
if (next_type == UDQTokenType::ecl_expr) {
|
if (next_type == Opm::UDQTokenType::ecl_expr) {
|
||||||
const auto& select_token = string_tokens[token_index];
|
const auto& select_token = string_tokens[token_index];
|
||||||
if (RawConsts::is_quote()(select_token[0]))
|
if (Opm::RawConsts::is_quote()(select_token[0])) {
|
||||||
selector.push_back(select_token.substr(1, select_token.size() - 2));
|
selector.push_back(select_token.substr(1, select_token.size() - 2));
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
selector.push_back(select_token);
|
selector.push_back(select_token);
|
||||||
token_index += 1;
|
}
|
||||||
} else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tokens.emplace_back( string_token, selector );
|
|
||||||
} else
|
|
||||||
tokens.emplace_back( string_token, token_type );
|
|
||||||
|
|
||||||
if (token_index == string_tokens.size())
|
token_index += 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens.emplace_back(string_token, selector);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tokens.emplace_back(string_token, token_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token_index == string_tokens.size()) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
}
|
next_token(const std::string& item,
|
||||||
|
std::size_t& offset,
|
||||||
UDQDefine::UDQDefine()
|
const std::vector<std::string>& splitters)
|
||||||
: m_var_type(UDQVarType::NONE)
|
{
|
||||||
{}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
|
|
||||||
const std::string& keyword,
|
|
||||||
std::size_t report_step,
|
|
||||||
const KeywordLocation& location,
|
|
||||||
const std::vector<std::string>& deck_data,
|
|
||||||
const ParseContext& parseContext,
|
|
||||||
T&& errors) :
|
|
||||||
UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, parseContext, errors)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
|
||||||
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
|
|
||||||
const std::string& keyword,
|
|
||||||
std::size_t report_step,
|
|
||||||
const KeywordLocation& location,
|
|
||||||
const std::vector<std::string>& deck_data) :
|
|
||||||
UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, ParseContext(), ErrorGuard())
|
|
||||||
{}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
std::string next_token(const std::string& item, std::size_t& offset, const std::vector<std::string>& splitters) {
|
|
||||||
if (std::isdigit(item[offset])) {
|
if (std::isdigit(item[offset])) {
|
||||||
auto substring = item.substr(offset);
|
auto substring = item.substr(offset);
|
||||||
char * end_ptr;
|
char* end_ptr;
|
||||||
std::ignore = std::strtod(substring.c_str(), &end_ptr);
|
std::ignore = std::strtod(substring.c_str(), &end_ptr);
|
||||||
|
|
||||||
std::size_t token_size = end_ptr - substring.c_str();
|
std::size_t token_size = end_ptr - substring.c_str();
|
||||||
@ -153,32 +152,86 @@ std::string next_token(const std::string& item, std::size_t& offset, const std::
|
|||||||
auto pos = item.find(splitter, offset);
|
auto pos = item.find(splitter, offset);
|
||||||
if (pos < min_pos) {
|
if (pos < min_pos) {
|
||||||
min_pos = pos;
|
min_pos = pos;
|
||||||
if (pos == offset)
|
if (pos == offset) {
|
||||||
token = splitter;
|
token = splitter;
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
token = item.substr(offset, pos - offset);
|
token = item.substr(offset, pos - offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset += token.size();
|
offset += token.size();
|
||||||
return trim_copy(token);
|
|
||||||
|
return Opm::trim_copy(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function unconditionally returns true and is therefore not a real
|
||||||
|
// predicate at the moment. We nevertheless keep the predicate here in the
|
||||||
|
// hope that it is possible to actually make it useful in the future. See
|
||||||
|
// the comment in UDQEnums.hpp about 'UDQ type system'.
|
||||||
|
bool dynamic_type_check(const Opm::UDQVarType lhs,
|
||||||
|
const Opm::UDQVarType rhs)
|
||||||
|
{
|
||||||
|
if (lhs == rhs) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rhs == Opm::UDQVarType::SCALAR) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
UDQDefine::UDQDefine(const UDQParams& udq_params,
|
namespace Opm {
|
||||||
const std::string& keyword,
|
|
||||||
std::size_t report_step,
|
UDQDefine::UDQDefine()
|
||||||
const KeywordLocation& location,
|
: m_var_type(UDQVarType::NONE)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
|
||||||
|
const std::string& keyword,
|
||||||
|
const std::size_t report_step,
|
||||||
|
const KeywordLocation& location,
|
||||||
const std::vector<std::string>& deck_data,
|
const std::vector<std::string>& deck_data,
|
||||||
const ParseContext& parseContext,
|
const ParseContext& parseContext,
|
||||||
ErrorGuard& errors) :
|
T&& errors)
|
||||||
m_keyword(keyword),
|
: UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, parseContext, errors)
|
||||||
m_var_type(UDQ::varType(keyword)),
|
{}
|
||||||
m_location(location),
|
|
||||||
m_report_step(report_step),
|
|
||||||
m_update_status(UDQUpdate::ON)
|
UDQDefine::UDQDefine(const UDQParams& udq_params_arg,
|
||||||
|
const std::string& keyword,
|
||||||
|
const std::size_t report_step,
|
||||||
|
const KeywordLocation& location,
|
||||||
|
const std::vector<std::string>& deck_data)
|
||||||
|
: UDQDefine(udq_params_arg, keyword, report_step, location, deck_data, ParseContext(), ErrorGuard())
|
||||||
|
{}
|
||||||
|
|
||||||
|
UDQDefine::UDQDefine(const UDQParams& udq_params,
|
||||||
|
const std::string& keyword,
|
||||||
|
const std::size_t report_step,
|
||||||
|
const KeywordLocation& location,
|
||||||
|
const std::vector<std::string>& deck_data,
|
||||||
|
const ParseContext& parseContext,
|
||||||
|
ErrorGuard& errors)
|
||||||
|
: m_keyword (keyword)
|
||||||
|
, m_var_type (UDQ::varType(keyword))
|
||||||
|
, m_location (location)
|
||||||
|
, m_report_step (report_step)
|
||||||
|
, m_update_status(UDQUpdate::ON)
|
||||||
{
|
{
|
||||||
std::vector<std::string> string_tokens;
|
const auto splitters = std::vector<std::string> {
|
||||||
|
" ", "TU*[]", "(", ")", "[", "]", ",",
|
||||||
|
"+", "-", "/", "*",
|
||||||
|
"==", "!=", "^", ">=", "<=", ">", "<",
|
||||||
|
};
|
||||||
|
|
||||||
|
auto string_tokens = std::vector<std::string>{};
|
||||||
for (const std::string& deck_item : deck_data) {
|
for (const std::string& deck_item : deck_data) {
|
||||||
for (const std::string& item : quote_split(deck_item)) {
|
for (const std::string& item : quote_split(deck_item)) {
|
||||||
if (RawConsts::is_quote()(item[0])) {
|
if (RawConsts::is_quote()(item[0])) {
|
||||||
@ -186,26 +239,35 @@ UDQDefine::UDQDefine(const UDQParams& udq_params,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> splitters = {" ", "TU*[]", "(", ")", "[", "]", ",", "+", "-", "/", "*", "==", "!=", "^", ">=", "<=", ">", "<"};
|
std::size_t offset = 0;
|
||||||
size_t offset = 0;
|
|
||||||
while (offset < item.size()) {
|
while (offset < item.size()) {
|
||||||
auto token = next_token(item, offset, splitters);
|
auto token = next_token(item, offset, splitters);
|
||||||
if (!token.empty())
|
if (!token.empty()) {
|
||||||
string_tokens.push_back( token );
|
string_tokens.push_back(std::move(token));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_tokens = make_tokens(string_tokens);
|
this->m_tokens = make_tokens(string_tokens);
|
||||||
this->ast = std::make_shared<UDQASTNode>( UDQParser::parse(udq_params, this->m_var_type, this->m_keyword, this->m_location, this->m_tokens, parseContext, errors) );
|
|
||||||
|
this->ast = std::make_shared<UDQASTNode>
|
||||||
|
(UDQParser::parse(udq_params,
|
||||||
|
this->m_var_type,
|
||||||
|
this->m_keyword,
|
||||||
|
this->m_location,
|
||||||
|
this->m_tokens,
|
||||||
|
parseContext,
|
||||||
|
errors));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UDQDefine::update_status(UDQUpdate update, std::size_t report_step) {
|
void UDQDefine::update_status(const UDQUpdate update,
|
||||||
|
const std::size_t report_step)
|
||||||
|
{
|
||||||
this->m_update_status = update;
|
this->m_update_status = update;
|
||||||
this->m_report_step = report_step;
|
this->m_report_step = report_step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UDQDefine UDQDefine::serializationTestObject()
|
UDQDefine UDQDefine::serializationTestObject()
|
||||||
{
|
{
|
||||||
UDQDefine result;
|
UDQDefine result;
|
||||||
@ -219,76 +281,63 @@ UDQDefine UDQDefine::serializationTestObject()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UDQDefine::required_summary(std::unordered_set<std::string>& summary_keys) const
|
||||||
namespace {
|
{
|
||||||
|
|
||||||
/*
|
|
||||||
This function unconditinally returns true and is of-course quite useless at
|
|
||||||
the moment; it is retained here in the hope that it is possible to actually
|
|
||||||
make it useful in the future. See the comment in UDQEnums.hpp about 'UDQ type
|
|
||||||
system'.
|
|
||||||
*/
|
|
||||||
bool dynamic_type_check(UDQVarType lhs, UDQVarType rhs) {
|
|
||||||
if (lhs == rhs)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (rhs == UDQVarType::SCALAR)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UDQDefine::required_summary(std::unordered_set<std::string>& summary_keys) const {
|
|
||||||
this->ast->required_summary(summary_keys);
|
this->ast->required_summary(summary_keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQSet UDQDefine::eval(const UDQContext& context) const {
|
UDQSet UDQDefine::eval(const UDQContext& context) const
|
||||||
|
{
|
||||||
std::optional<UDQSet> res;
|
std::optional<UDQSet> res;
|
||||||
try {
|
try {
|
||||||
res = this->ast->eval(this->m_var_type, context);
|
res = this->ast->eval(this->m_var_type, context);
|
||||||
res->name( this->m_keyword );
|
res->name(this->m_keyword);
|
||||||
|
|
||||||
if (!dynamic_type_check(this->var_type(), res->var_type())) {
|
if (!dynamic_type_check(this->var_type(), res->var_type())) {
|
||||||
std::string msg = "Invalid runtime type conversion detected when evaluating UDQ";
|
throw std::invalid_argument {
|
||||||
throw std::invalid_argument(msg);
|
"Invalid runtime type conversion detected when evaluating UDQ"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} catch (const std::exception& exc) {
|
}
|
||||||
auto msg = fmt::format("Problem evaluating UDQ {}\n"
|
catch (const std::exception& exc) {
|
||||||
"In {} line {}\n"
|
const auto msg = fmt::format("Problem evaluating UDQ {}\n"
|
||||||
"Internal error: {}", this->m_keyword, this->m_location.filename, this->m_location.lineno, exc.what());
|
"In {} line {}\n"
|
||||||
|
"Internal error: {}",
|
||||||
|
this->m_keyword,
|
||||||
|
this->m_location.filename,
|
||||||
|
this->m_location.lineno,
|
||||||
|
exc.what());
|
||||||
OpmLog::error(msg);
|
OpmLog::error(msg);
|
||||||
std::throw_with_nested(exc);
|
std::throw_with_nested(exc);
|
||||||
}
|
}
|
||||||
if (!res)
|
|
||||||
throw std::logic_error("Bug in UDQDefine::eval()");
|
|
||||||
|
|
||||||
|
if (!res) {
|
||||||
|
throw std::logic_error("Bug in UDQDefine::eval()");
|
||||||
|
}
|
||||||
|
|
||||||
if (res->var_type() == UDQVarType::SCALAR) {
|
if (res->var_type() == UDQVarType::SCALAR) {
|
||||||
/*
|
// If the right hand side evaluates to a scalar that scalar value
|
||||||
If the right hand side evaluates to a scalar that scalar value should
|
// should be set for all wells in the wellset:
|
||||||
be set for all wells in the wellset:
|
//
|
||||||
|
// UDQ
|
||||||
|
// DEFINE WUINJ1 SUM(WOPR) * 1.25 /
|
||||||
|
// DEFINE WUINJ2 WOPR OP1 * 5.0 /
|
||||||
|
// /
|
||||||
|
//
|
||||||
|
// Both the expressions "SUM(WOPR)" and "WOPR OP1" evaluate to a
|
||||||
|
// scalar, this should then be copied all wells, so that
|
||||||
|
// WUINJ1:$WELL should evaulate to the same numerical value for all
|
||||||
|
// wells. We implement the same behavior for group sets - but there
|
||||||
|
// is lots of uncertainty regarding the semantics of group sets.
|
||||||
|
|
||||||
UDQ
|
const auto& scalar_value = (*res)[0].value();
|
||||||
DEFINE WUINJ1 SUM(WOPR) * 1.25 /
|
|
||||||
DEFINE WUINJ2 WOPR OP1 * 5.0 /
|
|
||||||
/
|
|
||||||
|
|
||||||
Both the expressions "SUM(WOPR)" and "WOPR OP1" evaluate to a scalar,
|
|
||||||
this should then be copied all wells, so that WUINJ1:$WELL should
|
|
||||||
evaulate to the same numerical value for all wells. We implement the
|
|
||||||
same behavior for group sets - but there is lots of uncertainty
|
|
||||||
regarding the semantics of group sets.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const auto& scalar_value = res->operator[](0).value();
|
|
||||||
if (this->var_type() == UDQVarType::WELL_VAR) {
|
if (this->var_type() == UDQVarType::WELL_VAR) {
|
||||||
const std::vector<std::string> wells = context.wells();
|
const std::vector<std::string> wells = context.wells();
|
||||||
UDQSet well_res = UDQSet::wells(this->m_keyword, wells);
|
UDQSet well_res = UDQSet::wells(this->m_keyword, wells);
|
||||||
|
|
||||||
for (const auto& well : wells)
|
for (const auto& well : wells) {
|
||||||
well_res.assign(well, scalar_value);
|
well_res.assign(well, scalar_value);
|
||||||
|
}
|
||||||
|
|
||||||
return well_res;
|
return well_res;
|
||||||
}
|
}
|
||||||
@ -297,8 +346,9 @@ UDQSet UDQDefine::eval(const UDQContext& context) const {
|
|||||||
const std::vector<std::string> groups = context.groups();
|
const std::vector<std::string> groups = context.groups();
|
||||||
UDQSet group_res = UDQSet::groups(this->m_keyword, groups);
|
UDQSet group_res = UDQSet::groups(this->m_keyword, groups);
|
||||||
|
|
||||||
for (const auto& group : groups)
|
for (const auto& group : groups) {
|
||||||
group_res.assign(group, scalar_value);
|
group_res.assign(group, scalar_value);
|
||||||
|
}
|
||||||
|
|
||||||
return group_res;
|
return group_res;
|
||||||
}
|
}
|
||||||
@ -307,72 +357,85 @@ UDQSet UDQDefine::eval(const UDQContext& context) const {
|
|||||||
return *res;
|
return *res;
|
||||||
}
|
}
|
||||||
|
|
||||||
const KeywordLocation& UDQDefine::location() const {
|
const KeywordLocation& UDQDefine::location() const
|
||||||
|
{
|
||||||
return this->m_location;
|
return this->m_location;
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQVarType UDQDefine::var_type() const {
|
UDQVarType UDQDefine::var_type() const
|
||||||
|
{
|
||||||
return this->m_var_type;
|
return this->m_var_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string& UDQDefine::keyword() const
|
||||||
const std::string& UDQDefine::keyword() const {
|
{
|
||||||
return this->m_keyword;
|
return this->m_keyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& UDQDefine::input_string() const {
|
const std::string& UDQDefine::input_string() const
|
||||||
|
{
|
||||||
if (!this->string_data.has_value()) {
|
if (!this->string_data.has_value()) {
|
||||||
std::string s;
|
std::string s;
|
||||||
/*
|
|
||||||
A string representation equivalent to the input string is assembled by
|
// A string representation equivalent to the input string is
|
||||||
joining tokens and sprinkle with ' ' at semi random locations. The
|
// assembled by joining tokens and sprinkle with ' ' at semi random
|
||||||
main use of this function is to output the definition string in form
|
// locations. The main use of this function is to output the
|
||||||
usable for the restart file.
|
// definition string in form usable for the restart file.
|
||||||
*/
|
|
||||||
|
|
||||||
for (std::size_t token_index = 0; token_index < this->m_tokens.size(); token_index++) {
|
for (std::size_t token_index = 0; token_index < this->m_tokens.size(); token_index++) {
|
||||||
const auto& token = this->m_tokens[token_index];
|
const auto& token = this->m_tokens[token_index];
|
||||||
if (UDQ::leadingSpace(token.type()))
|
if (UDQ::leadingSpace(token.type())) {
|
||||||
s += " ";
|
s += " ";
|
||||||
|
}
|
||||||
|
|
||||||
s += token.str();
|
s += token.str();
|
||||||
if (token_index == (this->m_tokens.size() - 1))
|
if (token_index == (this->m_tokens.size() - 1)) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (UDQ::trailingSpace(token.type())) {
|
if (UDQ::trailingSpace(token.type())) {
|
||||||
s += " ";
|
s += " ";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->string_data = s;
|
|
||||||
|
|
||||||
|
this->string_data = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->string_data.value();
|
return this->string_data.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<UDQTokenType> UDQDefine::func_tokens() const {
|
std::set<UDQTokenType> UDQDefine::func_tokens() const
|
||||||
|
{
|
||||||
return this->ast->func_tokens();
|
return this->ast->func_tokens();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<UDQUpdate, std::size_t> UDQDefine::status() const {
|
std::pair<UDQUpdate, std::size_t> UDQDefine::status() const
|
||||||
|
{
|
||||||
return std::make_pair(this->m_update_status, this->m_report_step);
|
return std::make_pair(this->m_update_status, this->m_report_step);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<UDQToken> UDQDefine::tokens() const {
|
const std::vector<UDQToken> UDQDefine::tokens() const
|
||||||
|
{
|
||||||
return this->m_tokens;
|
return this->m_tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UDQDefine::operator==(const UDQDefine& data) const {
|
bool UDQDefine::operator==(const UDQDefine& data) const
|
||||||
if ((ast && !data.ast) || (!ast && data.ast))
|
{
|
||||||
return false;
|
if ((ast && !data.ast) || (!ast && data.ast)) {
|
||||||
if (ast && !(*ast == *data.ast))
|
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return this->keyword() == data.keyword() &&
|
if (ast && !(*ast == *data.ast)) {
|
||||||
this->m_location == data.location() &&
|
return false;
|
||||||
this->var_type() == data.var_type() &&
|
}
|
||||||
this->status() == data.status() &&
|
|
||||||
this->input_string() == data.input_string();
|
return (this->keyword() == data.keyword())
|
||||||
|
&& (this->m_location == data.location())
|
||||||
|
&& (this->var_type() == data.var_type())
|
||||||
|
&& (this->status() == data.status())
|
||||||
|
&& (this->input_string() == data.input_string())
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Opm
|
||||||
|
@ -28,367 +28,407 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Opm { namespace UDQ {
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const std::set<UDQTokenType> cmp_func = {UDQTokenType::binary_cmp_eq,
|
bool is_no_mix(const Opm::UDQVarType t)
|
||||||
UDQTokenType::binary_cmp_ne,
|
{
|
||||||
UDQTokenType::binary_cmp_le,
|
return (t == Opm::UDQVarType::CONNECTION_VAR)
|
||||||
UDQTokenType::binary_cmp_ge,
|
|| (t == Opm::UDQVarType::REGION_VAR)
|
||||||
UDQTokenType::binary_cmp_lt,
|
|| (t == Opm::UDQVarType::SEGMENT_VAR)
|
||||||
UDQTokenType::binary_cmp_gt};
|
|| (t == Opm::UDQVarType::AQUIFER_VAR)
|
||||||
|
|| (t == Opm::UDQVarType::BLOCK_VAR)
|
||||||
|
|| (t == Opm::UDQVarType::WELL_VAR)
|
||||||
|
|| (t == Opm::UDQVarType::GROUP_VAR)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
const std::set<UDQTokenType> binary_func = {UDQTokenType::binary_op_add,
|
bool is_valid_vartype(const Opm::UDQVarType t)
|
||||||
UDQTokenType::binary_op_mul,
|
{
|
||||||
UDQTokenType::binary_op_sub,
|
return is_no_mix(t)
|
||||||
UDQTokenType::binary_op_div,
|
|| (t == Opm::UDQVarType::NONE)
|
||||||
UDQTokenType::binary_op_pow,
|
|| (t == Opm::UDQVarType::SCALAR)
|
||||||
UDQTokenType::binary_op_uadd,
|
|| (t == Opm::UDQVarType::FIELD_VAR)
|
||||||
UDQTokenType::binary_op_umul,
|
;
|
||||||
UDQTokenType::binary_op_umin,
|
}
|
||||||
UDQTokenType::binary_op_umax,
|
|
||||||
UDQTokenType::binary_cmp_eq,
|
|
||||||
UDQTokenType::binary_cmp_ne,
|
|
||||||
UDQTokenType::binary_cmp_le,
|
|
||||||
UDQTokenType::binary_cmp_ge,
|
|
||||||
UDQTokenType::binary_cmp_lt,
|
|
||||||
UDQTokenType::binary_cmp_gt};
|
|
||||||
|
|
||||||
const std::set<UDQTokenType> set_func = {UDQTokenType::binary_op_uadd,
|
const auto cmp_func = std::set<Opm::UDQTokenType> {
|
||||||
UDQTokenType::binary_op_umul,
|
Opm::UDQTokenType::binary_cmp_eq,
|
||||||
UDQTokenType::binary_op_umin,
|
Opm::UDQTokenType::binary_cmp_ne,
|
||||||
UDQTokenType::binary_op_umax};
|
Opm::UDQTokenType::binary_cmp_le,
|
||||||
|
Opm::UDQTokenType::binary_cmp_ge,
|
||||||
|
Opm::UDQTokenType::binary_cmp_lt,
|
||||||
|
Opm::UDQTokenType::binary_cmp_gt,
|
||||||
|
};
|
||||||
|
|
||||||
const std::set<UDQTokenType> scalar_func = {UDQTokenType::scalar_func_sum,
|
const auto binary_func = std::set<Opm::UDQTokenType> {
|
||||||
UDQTokenType::scalar_func_avea,
|
Opm::UDQTokenType::binary_op_add,
|
||||||
UDQTokenType::scalar_func_aveg,
|
Opm::UDQTokenType::binary_op_mul,
|
||||||
UDQTokenType::scalar_func_aveh,
|
Opm::UDQTokenType::binary_op_sub,
|
||||||
UDQTokenType::scalar_func_max,
|
Opm::UDQTokenType::binary_op_div,
|
||||||
UDQTokenType::scalar_func_min,
|
Opm::UDQTokenType::binary_op_pow,
|
||||||
UDQTokenType::scalar_func_norm1,
|
Opm::UDQTokenType::binary_op_uadd,
|
||||||
UDQTokenType::scalar_func_norm2,
|
Opm::UDQTokenType::binary_op_umul,
|
||||||
UDQTokenType::scalar_func_normi,
|
Opm::UDQTokenType::binary_op_umin,
|
||||||
UDQTokenType::scalar_func_prod};
|
Opm::UDQTokenType::binary_op_umax,
|
||||||
|
Opm::UDQTokenType::binary_cmp_eq,
|
||||||
|
Opm::UDQTokenType::binary_cmp_ne,
|
||||||
|
Opm::UDQTokenType::binary_cmp_le,
|
||||||
|
Opm::UDQTokenType::binary_cmp_ge,
|
||||||
|
Opm::UDQTokenType::binary_cmp_lt,
|
||||||
|
Opm::UDQTokenType::binary_cmp_gt,
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto set_func = std::set<Opm::UDQTokenType> {
|
||||||
|
Opm::UDQTokenType::binary_op_uadd,
|
||||||
|
Opm::UDQTokenType::binary_op_umul,
|
||||||
|
Opm::UDQTokenType::binary_op_umin,
|
||||||
|
Opm::UDQTokenType::binary_op_umax,
|
||||||
|
};
|
||||||
|
|
||||||
const std::set<UDQTokenType> unary_elemental_func = {UDQTokenType::elemental_func_randn,
|
const auto scalar_func = std::set<Opm::UDQTokenType> {
|
||||||
UDQTokenType::elemental_func_randu,
|
Opm::UDQTokenType::scalar_func_sum,
|
||||||
UDQTokenType::elemental_func_rrandn,
|
Opm::UDQTokenType::scalar_func_avea,
|
||||||
UDQTokenType::elemental_func_rrandu,
|
Opm::UDQTokenType::scalar_func_aveg,
|
||||||
UDQTokenType::elemental_func_abs,
|
Opm::UDQTokenType::scalar_func_aveh,
|
||||||
UDQTokenType::elemental_func_def,
|
Opm::UDQTokenType::scalar_func_max,
|
||||||
UDQTokenType::elemental_func_exp,
|
Opm::UDQTokenType::scalar_func_min,
|
||||||
UDQTokenType::elemental_func_idv,
|
Opm::UDQTokenType::scalar_func_norm1,
|
||||||
UDQTokenType::elemental_func_ln,
|
Opm::UDQTokenType::scalar_func_norm2,
|
||||||
UDQTokenType::elemental_func_log,
|
Opm::UDQTokenType::scalar_func_normi,
|
||||||
UDQTokenType::elemental_func_nint,
|
Opm::UDQTokenType::scalar_func_prod,
|
||||||
UDQTokenType::elemental_func_sorta,
|
};
|
||||||
UDQTokenType::elemental_func_sortd,
|
|
||||||
UDQTokenType::elemental_func_undef};
|
|
||||||
|
|
||||||
|
const auto unary_elemental_func = std::set<Opm::UDQTokenType> {
|
||||||
|
Opm::UDQTokenType::elemental_func_randn,
|
||||||
|
Opm::UDQTokenType::elemental_func_randu,
|
||||||
|
Opm::UDQTokenType::elemental_func_rrandn,
|
||||||
|
Opm::UDQTokenType::elemental_func_rrandu,
|
||||||
|
Opm::UDQTokenType::elemental_func_abs,
|
||||||
|
Opm::UDQTokenType::elemental_func_def,
|
||||||
|
Opm::UDQTokenType::elemental_func_exp,
|
||||||
|
Opm::UDQTokenType::elemental_func_idv,
|
||||||
|
Opm::UDQTokenType::elemental_func_ln,
|
||||||
|
Opm::UDQTokenType::elemental_func_log,
|
||||||
|
Opm::UDQTokenType::elemental_func_nint,
|
||||||
|
Opm::UDQTokenType::elemental_func_sorta,
|
||||||
|
Opm::UDQTokenType::elemental_func_sortd,
|
||||||
|
Opm::UDQTokenType::elemental_func_undef,
|
||||||
|
};
|
||||||
|
|
||||||
const std::unordered_map<std::string, UDQTokenType> func_type = {{"+", UDQTokenType::binary_op_add},
|
const auto func_type = std::unordered_map<std::string, Opm::UDQTokenType> {
|
||||||
{"-", UDQTokenType::binary_op_sub},
|
{"+" , Opm::UDQTokenType::binary_op_add},
|
||||||
{"/", UDQTokenType::binary_op_div},
|
{"-" , Opm::UDQTokenType::binary_op_sub},
|
||||||
{"DIV", UDQTokenType::binary_op_div},
|
{"/" , Opm::UDQTokenType::binary_op_div},
|
||||||
{"*", UDQTokenType::binary_op_mul},
|
{"DIV" , Opm::UDQTokenType::binary_op_div},
|
||||||
{"^", UDQTokenType::binary_op_pow},
|
{"*" , Opm::UDQTokenType::binary_op_mul},
|
||||||
{"UADD", UDQTokenType::binary_op_uadd},
|
{"^" , Opm::UDQTokenType::binary_op_pow},
|
||||||
{"UMUL", UDQTokenType::binary_op_umul},
|
{"UADD" , Opm::UDQTokenType::binary_op_uadd},
|
||||||
{"UMIN", UDQTokenType::binary_op_umin},
|
{"UMUL" , Opm::UDQTokenType::binary_op_umul},
|
||||||
{"UMAX", UDQTokenType::binary_op_umax},
|
{"UMIN" , Opm::UDQTokenType::binary_op_umin},
|
||||||
{"==", UDQTokenType::binary_cmp_eq},
|
{"UMAX" , Opm::UDQTokenType::binary_op_umax},
|
||||||
{"!=", UDQTokenType::binary_cmp_ne},
|
{"==" , Opm::UDQTokenType::binary_cmp_eq},
|
||||||
{"<=", UDQTokenType::binary_cmp_le},
|
{"!=" , Opm::UDQTokenType::binary_cmp_ne},
|
||||||
{">=", UDQTokenType::binary_cmp_ge},
|
{"<=" , Opm::UDQTokenType::binary_cmp_le},
|
||||||
{"<", UDQTokenType::binary_cmp_lt},
|
{">=" , Opm::UDQTokenType::binary_cmp_ge},
|
||||||
{">", UDQTokenType::binary_cmp_gt},
|
{"<" , Opm::UDQTokenType::binary_cmp_lt},
|
||||||
{"RANDN", UDQTokenType::elemental_func_randn},
|
{">" , Opm::UDQTokenType::binary_cmp_gt},
|
||||||
{"RANDU", UDQTokenType::elemental_func_randu},
|
{"RANDN", Opm::UDQTokenType::elemental_func_randn},
|
||||||
{"RRNDN", UDQTokenType::elemental_func_rrandn},
|
{"RANDU", Opm::UDQTokenType::elemental_func_randu},
|
||||||
{"RRNDU", UDQTokenType::elemental_func_rrandu},
|
{"RRNDN", Opm::UDQTokenType::elemental_func_rrandn},
|
||||||
{"ABS", UDQTokenType::elemental_func_abs},
|
{"RRNDU", Opm::UDQTokenType::elemental_func_rrandu},
|
||||||
{"DEF", UDQTokenType::elemental_func_def},
|
{"ABS" , Opm::UDQTokenType::elemental_func_abs},
|
||||||
{"EXP", UDQTokenType::elemental_func_exp},
|
{"DEF" , Opm::UDQTokenType::elemental_func_def},
|
||||||
{"IDV", UDQTokenType::elemental_func_idv},
|
{"EXP" , Opm::UDQTokenType::elemental_func_exp},
|
||||||
{"LN", UDQTokenType::elemental_func_ln},
|
{"IDV" , Opm::UDQTokenType::elemental_func_idv},
|
||||||
{"LOG", UDQTokenType::elemental_func_log},
|
{"LN" , Opm::UDQTokenType::elemental_func_ln},
|
||||||
{"NINT", UDQTokenType::elemental_func_nint},
|
{"LOG" , Opm::UDQTokenType::elemental_func_log},
|
||||||
{"SORTA", UDQTokenType::elemental_func_sorta},
|
{"NINT" , Opm::UDQTokenType::elemental_func_nint},
|
||||||
{"SORTD", UDQTokenType::elemental_func_sortd},
|
{"SORTA", Opm::UDQTokenType::elemental_func_sorta},
|
||||||
{"UNDEF", UDQTokenType::elemental_func_undef},
|
{"SORTD", Opm::UDQTokenType::elemental_func_sortd},
|
||||||
{"SUM", UDQTokenType::scalar_func_sum},
|
{"UNDEF", Opm::UDQTokenType::elemental_func_undef},
|
||||||
{"AVEA", UDQTokenType::scalar_func_avea},
|
{"SUM" , Opm::UDQTokenType::scalar_func_sum},
|
||||||
{"AVEG", UDQTokenType::scalar_func_aveg},
|
{"AVEA" , Opm::UDQTokenType::scalar_func_avea},
|
||||||
{"AVEH", UDQTokenType::scalar_func_aveh},
|
{"AVEG" , Opm::UDQTokenType::scalar_func_aveg},
|
||||||
{"MAX", UDQTokenType::scalar_func_max},
|
{"AVEH" , Opm::UDQTokenType::scalar_func_aveh},
|
||||||
{"MIN", UDQTokenType::scalar_func_min},
|
{"MAX" , Opm::UDQTokenType::scalar_func_max},
|
||||||
{"NORM1", UDQTokenType::scalar_func_norm1},
|
{"MIN" , Opm::UDQTokenType::scalar_func_min},
|
||||||
{"NORM2", UDQTokenType::scalar_func_norm2},
|
{"NORM1", Opm::UDQTokenType::scalar_func_norm1},
|
||||||
{"NORMI", UDQTokenType::scalar_func_normi},
|
{"NORM2", Opm::UDQTokenType::scalar_func_norm2},
|
||||||
{"PROD", UDQTokenType::scalar_func_prod}};
|
{"NORMI", Opm::UDQTokenType::scalar_func_normi},
|
||||||
|
{"PROD" , Opm::UDQTokenType::scalar_func_prod},
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
}
|
namespace Opm { namespace UDQ {
|
||||||
|
|
||||||
UDQVarType targetType(const std::string& keyword) {
|
UDQVarType targetType(const std::string& keyword)
|
||||||
|
{
|
||||||
|
const char first_char = keyword[0];
|
||||||
|
switch (first_char) {
|
||||||
|
case 'C': return UDQVarType::CONNECTION_VAR;
|
||||||
|
case 'R': return UDQVarType::REGION_VAR;
|
||||||
|
case 'F': return UDQVarType::FIELD_VAR;
|
||||||
|
case 'S': return UDQVarType::SEGMENT_VAR;
|
||||||
|
case 'A': return UDQVarType::AQUIFER_VAR;
|
||||||
|
case 'B': return UDQVarType::BLOCK_VAR;
|
||||||
|
case 'W': return UDQVarType::WELL_VAR;
|
||||||
|
case 'G': return UDQVarType::GROUP_VAR;
|
||||||
|
|
||||||
char first_char = keyword[0];
|
|
||||||
switch(first_char) {
|
|
||||||
case 'C':
|
|
||||||
return UDQVarType::CONNECTION_VAR;
|
|
||||||
case 'R':
|
|
||||||
return UDQVarType::REGION_VAR;
|
|
||||||
case 'F':
|
|
||||||
return UDQVarType::FIELD_VAR;
|
|
||||||
case 'S':
|
|
||||||
return UDQVarType::SEGMENT_VAR;
|
|
||||||
case 'A':
|
|
||||||
return UDQVarType::AQUIFER_VAR;
|
|
||||||
case 'B':
|
|
||||||
return UDQVarType::BLOCK_VAR;
|
|
||||||
case 'W':
|
|
||||||
return UDQVarType::WELL_VAR;
|
|
||||||
case 'G':
|
|
||||||
return UDQVarType::GROUP_VAR;
|
|
||||||
default:
|
default:
|
||||||
const auto& double_value = try_parse_double(keyword);
|
if (const auto double_value = try_parse_double(keyword);
|
||||||
if (double_value.has_value())
|
double_value.has_value())
|
||||||
|
{
|
||||||
return UDQVarType::SCALAR;
|
return UDQVarType::SCALAR;
|
||||||
|
}
|
||||||
|
|
||||||
return UDQVarType::NONE;
|
return UDQVarType::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQVarType targetType(const std::string& keyword, const std::vector<std::string>& selector) {
|
UDQVarType targetType(const std::string& keyword,
|
||||||
auto tt = targetType(keyword);
|
const std::vector<std::string>& selector)
|
||||||
|
{
|
||||||
if (tt == UDQVarType::WELL_VAR || tt == UDQVarType::GROUP_VAR) {
|
const auto tt = targetType(keyword);
|
||||||
if (selector.empty())
|
if ((tt == UDQVarType::WELL_VAR) || (tt == UDQVarType::GROUP_VAR)) {
|
||||||
|
if (selector.empty() || (selector.front().find("*") != std::string::npos)) {
|
||||||
return tt;
|
return tt;
|
||||||
else {
|
|
||||||
const auto& wgname = selector[0];
|
|
||||||
if (wgname.find("*") != std::string::npos)
|
|
||||||
return tt;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return UDQVarType::SCALAR;
|
return UDQVarType::SCALAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQVarType varType(const std::string& keyword)
|
||||||
|
{
|
||||||
|
if ((keyword.size() < std::string::size_type{2}) || (keyword[1] != 'U')) {
|
||||||
|
throw std::invalid_argument("Keyword: '" + keyword + "' is not of UDQ type");
|
||||||
|
}
|
||||||
|
|
||||||
UDQVarType varType(const std::string& keyword) {
|
const char first_char = keyword[0];
|
||||||
if (keyword[1] != 'U')
|
switch (first_char) {
|
||||||
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type");
|
case 'W': return UDQVarType::WELL_VAR;
|
||||||
|
case 'G': return UDQVarType::GROUP_VAR;
|
||||||
|
case 'C': return UDQVarType::CONNECTION_VAR;
|
||||||
|
case 'R': return UDQVarType::REGION_VAR;
|
||||||
|
case 'F': return UDQVarType::FIELD_VAR;
|
||||||
|
case 'S': return UDQVarType::SEGMENT_VAR;
|
||||||
|
case 'A': return UDQVarType::AQUIFER_VAR;
|
||||||
|
case 'B': return UDQVarType::BLOCK_VAR;
|
||||||
|
|
||||||
char first_char = keyword[0];
|
|
||||||
switch(first_char) {
|
|
||||||
case 'W':
|
|
||||||
return UDQVarType::WELL_VAR;
|
|
||||||
case 'G':
|
|
||||||
return UDQVarType::GROUP_VAR;
|
|
||||||
case 'C':
|
|
||||||
return UDQVarType::CONNECTION_VAR;
|
|
||||||
case 'R':
|
|
||||||
return UDQVarType::REGION_VAR;
|
|
||||||
case 'F':
|
|
||||||
return UDQVarType::FIELD_VAR;
|
|
||||||
case 'S':
|
|
||||||
return UDQVarType::SEGMENT_VAR;
|
|
||||||
case 'A':
|
|
||||||
return UDQVarType::AQUIFER_VAR;
|
|
||||||
case 'B':
|
|
||||||
return UDQVarType::BLOCK_VAR;
|
|
||||||
default:
|
default:
|
||||||
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type");
|
throw std::invalid_argument("Keyword: " + keyword + " is not of UDQ type");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQAction actionType(const std::string& action_string)
|
||||||
UDQAction actionType(const std::string& action_string) {
|
{
|
||||||
if (action_string == "ASSIGN")
|
if (action_string == "ASSIGN") {
|
||||||
return UDQAction::ASSIGN;
|
return UDQAction::ASSIGN;
|
||||||
|
}
|
||||||
|
|
||||||
if (action_string == "DEFINE")
|
if (action_string == "DEFINE") {
|
||||||
return UDQAction::DEFINE;
|
return UDQAction::DEFINE;
|
||||||
|
}
|
||||||
|
|
||||||
if (action_string == "UNITS")
|
if (action_string == "UNITS") {
|
||||||
return UDQAction::UNITS;
|
return UDQAction::UNITS;
|
||||||
|
}
|
||||||
|
|
||||||
if (action_string == "UPDATE")
|
if (action_string == "UPDATE") {
|
||||||
return UDQAction::UPDATE;
|
return UDQAction::UPDATE;
|
||||||
|
}
|
||||||
|
|
||||||
throw std::invalid_argument("Invalid action string " + action_string);
|
throw std::invalid_argument("Invalid action string " + action_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQUpdate updateType(const std::string& update_string)
|
||||||
UDQUpdate updateType(const std::string& update_string) {
|
{
|
||||||
if (update_string == "ON")
|
if (update_string == "ON") {
|
||||||
return UDQUpdate::ON;
|
return UDQUpdate::ON;
|
||||||
|
}
|
||||||
|
|
||||||
if (update_string == "OFF")
|
if (update_string == "OFF") {
|
||||||
return UDQUpdate::OFF;
|
return UDQUpdate::OFF;
|
||||||
|
}
|
||||||
|
|
||||||
if (update_string == "NEXT")
|
if (update_string == "NEXT") {
|
||||||
return UDQUpdate::NEXT;
|
return UDQUpdate::NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
throw std::invalid_argument("Invalid status update string " + update_string);
|
throw std::invalid_argument("Invalid status update string " + update_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQUpdate updateType(int int_value) {
|
UDQUpdate updateType(const int int_value)
|
||||||
|
{
|
||||||
switch (int_value) {
|
switch (int_value) {
|
||||||
case 0: return UDQUpdate::OFF;
|
case 0: return UDQUpdate::OFF;
|
||||||
case 1: return UDQUpdate::NEXT;
|
case 1: return UDQUpdate::NEXT;
|
||||||
case 2: return UDQUpdate::ON;
|
case 2: return UDQUpdate::ON;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw std::logic_error("Invalid integer for UDQUpdate type");
|
throw std::logic_error("Invalid integer for UDQUpdate type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool binaryFunc(const UDQTokenType token_type)
|
||||||
bool binaryFunc(UDQTokenType token_type) {
|
{
|
||||||
return (binary_func.count(token_type) > 0);
|
return binary_func.find(token_type) != binary_func.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool scalarFunc(UDQTokenType token_type) {
|
bool scalarFunc(const UDQTokenType token_type)
|
||||||
return (scalar_func.count(token_type) > 0);
|
{
|
||||||
|
return scalar_func.find(token_type) != scalar_func.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool elementalUnaryFunc(UDQTokenType token_type) {
|
bool elementalUnaryFunc(const UDQTokenType token_type)
|
||||||
return (unary_elemental_func.count(token_type) > 0);
|
{
|
||||||
|
return unary_elemental_func.find(token_type) != unary_elemental_func.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cmpFunc(UDQTokenType token_type) {
|
bool cmpFunc(const UDQTokenType token_type)
|
||||||
return (cmp_func.count(token_type) > 0);
|
{
|
||||||
|
return cmp_func.find(token_type) != cmp_func.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setFunc(UDQTokenType token_type) {
|
bool setFunc(const UDQTokenType token_type)
|
||||||
return (set_func.count(token_type) > 0);
|
{
|
||||||
|
return set_func.find(token_type) != set_func.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQTokenType funcType(const std::string& func_name)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
auto func = func_type.find(func_name);
|
||||||
|
if (func != func_type.end()) {
|
||||||
|
return func->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UDQTokenType funcType(const std::string& func_name) {
|
if (func_name.substr(0, 2) == "TU") {
|
||||||
if (func_type.count(func_name) > 0)
|
|
||||||
return func_type.at(func_name);
|
|
||||||
|
|
||||||
if (func_name.substr(0,2) == "TU") {
|
|
||||||
return UDQTokenType::table_lookup;
|
return UDQTokenType::table_lookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
return UDQTokenType::error;
|
return UDQTokenType::error;
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQTokenType tokenType(const std::string& token) {
|
UDQTokenType tokenType(const std::string& token)
|
||||||
auto token_type = funcType(token);
|
{
|
||||||
if (token_type == UDQTokenType::error) {
|
if (const auto token_type = funcType(token);
|
||||||
if (token == "(")
|
token_type != UDQTokenType::error)
|
||||||
token_type = UDQTokenType::open_paren;
|
{
|
||||||
else if (token == ")")
|
return token_type;
|
||||||
token_type = UDQTokenType::close_paren;
|
|
||||||
else {
|
|
||||||
auto value = try_parse_double(token);
|
|
||||||
if (value.has_value())
|
|
||||||
token_type = UDQTokenType::number;
|
|
||||||
else
|
|
||||||
token_type = UDQTokenType::ecl_expr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return token_type;
|
|
||||||
|
if (token == "(") {
|
||||||
|
return UDQTokenType::open_paren;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token == ")") {
|
||||||
|
return UDQTokenType::close_paren;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto number = try_parse_double(token);
|
||||||
|
number.has_value())
|
||||||
|
{
|
||||||
|
return UDQTokenType::number;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UDQTokenType::ecl_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQVarType coerce(const UDQVarType t1, const UDQVarType t2)
|
||||||
|
{
|
||||||
|
if (! (is_valid_vartype(t1) && is_valid_vartype(t2))) {
|
||||||
|
// Note: Can't use typeName() here since that would throw another
|
||||||
|
// exception.
|
||||||
|
throw std::logic_error {
|
||||||
|
"Cannot coerce between " + std::to_string(static_cast<int>(t1))
|
||||||
|
+ " and " + std::to_string(static_cast<int>(t2))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
UDQVarType coerce(UDQVarType t1, UDQVarType t2) {
|
if (t1 == t2) {
|
||||||
if (t1 == t2)
|
|
||||||
return t1;
|
|
||||||
|
|
||||||
if (t1 == UDQVarType::WELL_VAR ) {
|
|
||||||
if (t2 == UDQVarType::GROUP_VAR)
|
|
||||||
throw std::logic_error("Can not coerce well variable and group variable");
|
|
||||||
|
|
||||||
return t1;
|
return t1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t1 == UDQVarType::GROUP_VAR ) {
|
const auto is_restricted_t1 = is_no_mix(t1);
|
||||||
if (t2 == UDQVarType::WELL_VAR)
|
const auto is_restricted_t2 = is_no_mix(t2);
|
||||||
throw std::logic_error("Can not coerce well variable and group variable");
|
|
||||||
|
|
||||||
|
if (is_restricted_t1 && is_restricted_t2) {
|
||||||
|
// t1 != t2, but neither can be coerced into the other.
|
||||||
|
throw std::logic_error {
|
||||||
|
"Cannot coerce between " + typeName(t1) + " and " + typeName(t2)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_restricted_t1) {
|
||||||
return t1;
|
return t1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t2 == UDQVarType::WELL_VAR ) {
|
if (is_restricted_t2) {
|
||||||
if (t1 == UDQVarType::GROUP_VAR)
|
|
||||||
throw std::logic_error("Can not coerce well variable and group variable");
|
|
||||||
|
|
||||||
return t2;
|
return t2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t2 == UDQVarType::GROUP_VAR ) {
|
if (t1 == UDQVarType::NONE) {
|
||||||
if (t1 == UDQVarType::WELL_VAR)
|
|
||||||
throw std::logic_error("Can not coerce well variable and group variable");
|
|
||||||
|
|
||||||
return t2;
|
return t2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t1 == UDQVarType::NONE)
|
if (t2 == UDQVarType::NONE) {
|
||||||
return t2;
|
|
||||||
|
|
||||||
if (t2 == UDQVarType::NONE)
|
|
||||||
return t1;
|
return t1;
|
||||||
|
}
|
||||||
|
|
||||||
return t1;
|
return t1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string typeName(const UDQVarType var_type)
|
||||||
|
{
|
||||||
|
|
||||||
std::string typeName(UDQVarType var_type) {
|
|
||||||
switch (var_type) {
|
switch (var_type) {
|
||||||
case UDQVarType::NONE:
|
case UDQVarType::NONE:
|
||||||
return "NONE";
|
return "NONE";
|
||||||
|
|
||||||
case UDQVarType::SCALAR:
|
case UDQVarType::SCALAR:
|
||||||
return "SCALAR";
|
return "SCALAR";
|
||||||
|
|
||||||
case UDQVarType::WELL_VAR:
|
case UDQVarType::WELL_VAR:
|
||||||
return "WELL_VAR";
|
return "WELL_VAR";
|
||||||
|
|
||||||
case UDQVarType::CONNECTION_VAR:
|
case UDQVarType::CONNECTION_VAR:
|
||||||
return "CONNECTION_VAR";
|
return "CONNECTION_VAR";
|
||||||
|
|
||||||
case UDQVarType::FIELD_VAR:
|
case UDQVarType::FIELD_VAR:
|
||||||
return "FIELD_VAR";
|
return "FIELD_VAR";
|
||||||
|
|
||||||
case UDQVarType::GROUP_VAR:
|
case UDQVarType::GROUP_VAR:
|
||||||
return "GROUP_VAR";
|
return "GROUP_VAR";
|
||||||
|
|
||||||
case UDQVarType::REGION_VAR:
|
case UDQVarType::REGION_VAR:
|
||||||
return "REGION_VAR";
|
return "REGION_VAR";
|
||||||
|
|
||||||
case UDQVarType::SEGMENT_VAR:
|
case UDQVarType::SEGMENT_VAR:
|
||||||
return "SEGMENT_VAR";
|
return "SEGMENT_VAR";
|
||||||
|
|
||||||
case UDQVarType::AQUIFER_VAR:
|
case UDQVarType::AQUIFER_VAR:
|
||||||
return "AQUIFER_VAR";
|
return "AQUIFER_VAR";
|
||||||
|
|
||||||
case UDQVarType::BLOCK_VAR:
|
case UDQVarType::BLOCK_VAR:
|
||||||
return "BLOCK_VAR";
|
return "BLOCK_VAR";
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw std::runtime_error("Should not be here: " + std::to_string(static_cast<int>(var_type)));
|
throw std::runtime_error("Should not be here: " + std::to_string(static_cast<int>(var_type)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool trailingSpace(UDQTokenType token_type) {
|
bool trailingSpace(const UDQTokenType token_type)
|
||||||
if (binaryFunc(token_type))
|
{
|
||||||
return true;
|
return binaryFunc(token_type)
|
||||||
|
|| cmpFunc(token_type);
|
||||||
if (cmpFunc(token_type))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool leadingSpace(UDQTokenType token_type) {
|
bool leadingSpace(const UDQTokenType token_type)
|
||||||
if (binaryFunc(token_type))
|
{
|
||||||
return true;
|
return binaryFunc(token_type)
|
||||||
|
|| cmpFunc(token_type);
|
||||||
if (cmpFunc(token_type))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -401,7 +441,7 @@ namespace {
|
|||||||
throw std::logic_error {
|
throw std::logic_error {
|
||||||
"Unrecognized enum type (" +
|
"Unrecognized enum type (" +
|
||||||
std::to_string(static_cast<int>(control)) +
|
std::to_string(static_cast<int>(control)) +
|
||||||
"- internal error"
|
") - internal error"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,5 +723,4 @@ std::string controlName(const UDAControl control)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}} // namespace Opm::UDQ
|
||||||
}} // Opm::UDQ
|
|
||||||
|
@ -17,78 +17,91 @@
|
|||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQInput.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQAssign.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQDefine.hpp>
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
|
UDQInput::UDQInput(const UDQIndex& index_arg,
|
||||||
UDQInput::UDQInput(const UDQIndex& index_arg, const UDQDefine& udq_define, const std::string& unit_arg) :
|
const UDQDefine& udq_define,
|
||||||
index(index_arg),
|
const std::string& unit_arg)
|
||||||
value(udq_define),
|
: index (index_arg)
|
||||||
m_keyword(udq_define.keyword()),
|
, value (udq_define)
|
||||||
m_var_type(udq_define.var_type()),
|
, m_keyword (udq_define.keyword())
|
||||||
m_unit(unit_arg)
|
, m_var_type(udq_define.var_type())
|
||||||
|
, m_unit (unit_arg)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
UDQInput::UDQInput(const UDQIndex& index_arg,
|
||||||
UDQInput::UDQInput(const UDQIndex& index_arg, const UDQAssign& udq_assign, const std::string& unit_arg):
|
const UDQAssign& udq_assign,
|
||||||
index(index_arg),
|
const std::string& unit_arg)
|
||||||
value(udq_assign),
|
: index (index_arg)
|
||||||
m_keyword(udq_assign.keyword()),
|
, value (udq_assign)
|
||||||
m_var_type(udq_assign.var_type()),
|
, m_keyword (udq_assign.keyword())
|
||||||
m_unit(unit_arg)
|
, m_var_type(udq_assign.var_type())
|
||||||
|
, m_unit (unit_arg)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
const std::string& UDQInput::unit() const {
|
const std::string& UDQInput::unit() const
|
||||||
|
{
|
||||||
return this->m_unit;
|
return this->m_unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& UDQInput::keyword() const {
|
const std::string& UDQInput::keyword() const
|
||||||
|
{
|
||||||
return this->m_keyword;
|
return this->m_keyword;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UDQVarType& UDQInput::var_type() const {
|
const UDQVarType& UDQInput::var_type() const
|
||||||
|
{
|
||||||
return this->m_var_type;
|
return this->m_var_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
bool UDQInput::is<UDQAssign>() const {
|
bool UDQInput::is<UDQAssign>() const
|
||||||
|
{
|
||||||
return std::holds_alternative<UDQAssign>(this->value);
|
return std::holds_alternative<UDQAssign>(this->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
bool UDQInput::is<UDQDefine>() const {
|
bool UDQInput::is<UDQDefine>() const
|
||||||
|
{
|
||||||
return std::holds_alternative<UDQDefine>(this->value);
|
return std::holds_alternative<UDQDefine>(this->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
const UDQAssign& UDQInput::get<UDQAssign>() const {
|
const UDQAssign& UDQInput::get<UDQAssign>() const
|
||||||
if (this->is<UDQAssign>())
|
{
|
||||||
|
if (this->is<UDQAssign>()) {
|
||||||
return std::get<UDQAssign>(this->value);
|
return std::get<UDQAssign>(this->value);
|
||||||
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Invalid get");
|
throw std::runtime_error("Invalid get");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
const UDQDefine& UDQInput::get<UDQDefine>() const {
|
const UDQDefine& UDQInput::get<UDQDefine>() const
|
||||||
if (this->is<UDQDefine>())
|
{
|
||||||
|
if (this->is<UDQDefine>()) {
|
||||||
return std::get<UDQDefine>(this->value);
|
return std::get<UDQDefine>(this->value);
|
||||||
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Invalid get");
|
throw std::runtime_error("Invalid get");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UDQInput::operator==(const UDQInput& other) const
|
||||||
bool UDQInput::operator==(const UDQInput& other) const {
|
{
|
||||||
return this->value == other.value &&
|
return (this->value == other.value)
|
||||||
this->m_keyword == other.m_keyword &&
|
&& (this->m_keyword == other.m_keyword)
|
||||||
this->m_var_type == other.m_var_type &&
|
&& (this->m_var_type == other.m_var_type)
|
||||||
this->m_unit == other.m_unit;
|
&& (this->m_unit == other.m_unit)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace Opm
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,77 +17,131 @@
|
|||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <iostream>
|
#include "UDQParser.hpp"
|
||||||
#include <cstring>
|
|
||||||
|
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Parser/ParseContext.hpp>
|
namespace {
|
||||||
#include <opm/common/OpmLog/KeywordLocation.hpp>
|
|
||||||
|
|
||||||
#include "UDQParser.hpp"
|
void dump_tokens(const std::string& target_var,
|
||||||
|
const std::vector<Opm::UDQToken>& tokens)
|
||||||
|
{
|
||||||
|
std::cout << target_var << " = ";
|
||||||
|
|
||||||
|
for (const auto& token : tokens) {
|
||||||
|
std::cout << token.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is extremely weak - hopefully it can be improved in the
|
||||||
|
// future. See the comment in UDQEnums.hpp about 'UDQ type system'.
|
||||||
|
bool static_type_check(const Opm::UDQVarType lhs,
|
||||||
|
const Opm::UDQVarType rhs)
|
||||||
|
{
|
||||||
|
if (lhs == rhs) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rhs == Opm::UDQVarType::SCALAR) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This does not check if the rhs evaluates to a scalar.
|
||||||
|
if (rhs == Opm::UDQVarType::WELL_VAR) {
|
||||||
|
return lhs == Opm::UDQVarType::WELL_VAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
UDQTokenType UDQParser::get_type(const std::string& arg) const {
|
UDQTokenType UDQParser::get_type(const std::string& arg) const
|
||||||
|
{
|
||||||
auto func_type = UDQ::funcType(arg);
|
auto func_type = UDQ::funcType(arg);
|
||||||
if (func_type == UDQTokenType::table_lookup)
|
if (func_type == UDQTokenType::table_lookup) {
|
||||||
throw std::invalid_argument("Table lookup function TU*[] is not supported in UDQ");
|
throw std::invalid_argument {
|
||||||
|
"Table lookup function TU*[] is not supported in UDQ"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (func_type != UDQTokenType::error)
|
if (func_type != UDQTokenType::error) {
|
||||||
return func_type;
|
return func_type;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg == "(")
|
if (arg == "(") {
|
||||||
return UDQTokenType::open_paren;
|
return UDQTokenType::open_paren;
|
||||||
|
}
|
||||||
|
|
||||||
if (arg == ")")
|
if (arg == ")") {
|
||||||
return UDQTokenType::close_paren;
|
return UDQTokenType::close_paren;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
char * end_ptr;
|
char* end_ptr;
|
||||||
std::strtod(arg.c_str(), &end_ptr);
|
std::strtod(arg.c_str(), &end_ptr);
|
||||||
if (std::strlen(end_ptr) == 0)
|
if (std::strlen(end_ptr) == 0) {
|
||||||
return UDQTokenType::number;
|
return UDQTokenType::number;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return UDQTokenType::ecl_expr;
|
return UDQTokenType::ecl_expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UDQParser::empty() const
|
||||||
|
{
|
||||||
bool UDQParser::empty() const {
|
return static_cast<std::size_t>(this->current_pos) == this->tokens.size();
|
||||||
return (static_cast<size_t>(this->current_pos) == this->tokens.size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQParseNode UDQParser::next() {
|
UDQParseNode UDQParser::next()
|
||||||
|
{
|
||||||
this->current_pos += 1;
|
this->current_pos += 1;
|
||||||
return this->current();
|
return this->current();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQParseNode UDQParser::current() const
|
||||||
|
{
|
||||||
UDQParseNode UDQParser::current() const {
|
if (this->empty()) {
|
||||||
if (this->empty())
|
|
||||||
return UDQTokenType::end;
|
return UDQTokenType::end;
|
||||||
|
}
|
||||||
|
|
||||||
const auto& token = this->tokens[current_pos];
|
const auto& token = this->tokens[current_pos];
|
||||||
if (token.type() == UDQTokenType::number)
|
if (token.type() == UDQTokenType::number) {
|
||||||
return UDQParseNode(UDQTokenType::number, token.value());
|
return UDQParseNode(UDQTokenType::number, token.value());
|
||||||
|
}
|
||||||
|
|
||||||
if (token.type() == UDQTokenType::ecl_expr)
|
if (token.type() == UDQTokenType::ecl_expr) {
|
||||||
return UDQParseNode(UDQTokenType::ecl_expr, token.value(), token.selector());
|
return UDQParseNode(UDQTokenType::ecl_expr, token.value(), token.selector());
|
||||||
|
}
|
||||||
|
|
||||||
return UDQParseNode(this->get_type(std::get<std::string>(token.value())), token.value());
|
return UDQParseNode(this->get_type(std::get<std::string>(token.value())), token.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQASTNode UDQParser::parse_factor()
|
||||||
UDQASTNode UDQParser::parse_factor() {
|
{
|
||||||
double sign = 1.0;
|
double sign = 1.0;
|
||||||
auto current = this->current();
|
auto current = this->current();
|
||||||
if (current.type == UDQTokenType::binary_op_add || current.type == UDQTokenType::binary_op_sub) {
|
if ((current.type == UDQTokenType::binary_op_add) ||
|
||||||
if (current.type == UDQTokenType::binary_op_sub)
|
(current.type == UDQTokenType::binary_op_sub))
|
||||||
|
{
|
||||||
|
if (current.type == UDQTokenType::binary_op_sub) {
|
||||||
sign = -1.0;
|
sign = -1.0;
|
||||||
|
}
|
||||||
|
|
||||||
this->next();
|
this->next();
|
||||||
current = this->current();
|
current = this->current();
|
||||||
}
|
}
|
||||||
@ -98,8 +152,9 @@ UDQASTNode UDQParser::parse_factor() {
|
|||||||
auto inner_expr = this->parse_set();
|
auto inner_expr = this->parse_set();
|
||||||
|
|
||||||
current = this->current();
|
current = this->current();
|
||||||
if (current.type != UDQTokenType::close_paren)
|
if (current.type != UDQTokenType::close_paren) {
|
||||||
return UDQASTNode(UDQTokenType::error);
|
return UDQASTNode(UDQTokenType::error);
|
||||||
|
}
|
||||||
|
|
||||||
this->next();
|
this->next();
|
||||||
return sign * inner_expr;
|
return sign * inner_expr;
|
||||||
@ -113,30 +168,37 @@ UDQASTNode UDQParser::parse_factor() {
|
|||||||
auto arg_expr = this->parse_set();
|
auto arg_expr = this->parse_set();
|
||||||
|
|
||||||
current = this->current();
|
current = this->current();
|
||||||
if (current.type != UDQTokenType::close_paren)
|
if (current.type != UDQTokenType::close_paren) {
|
||||||
return UDQASTNode(UDQTokenType::error);
|
return UDQASTNode(UDQTokenType::error);
|
||||||
|
}
|
||||||
|
|
||||||
this->next();
|
this->next();
|
||||||
return sign * UDQASTNode(func_node.type, func_node.value, arg_expr);
|
return sign * UDQASTNode(func_node.type, func_node.value, arg_expr);
|
||||||
} else
|
}
|
||||||
|
else {
|
||||||
return UDQASTNode(UDQTokenType::error);
|
return UDQASTNode(UDQTokenType::error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQASTNode node(current.type, current.value, current.selector);
|
UDQASTNode node(current.type, current.value, current.selector);
|
||||||
|
|
||||||
this->next();
|
this->next();
|
||||||
return sign * node;
|
return sign * node;
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQASTNode UDQParser::parse_pow() {
|
UDQASTNode UDQParser::parse_pow()
|
||||||
|
{
|
||||||
auto left = this->parse_factor();
|
auto left = this->parse_factor();
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
return left;
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
auto current = this->current();
|
auto current = this->current();
|
||||||
if (current.type == UDQTokenType::binary_op_pow) {
|
if (current.type == UDQTokenType::binary_op_pow) {
|
||||||
this->next();
|
this->next();
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
return UDQASTNode(UDQTokenType::error);
|
return UDQASTNode(UDQTokenType::error);
|
||||||
|
}
|
||||||
|
|
||||||
auto right = this->parse_mul();
|
auto right = this->parse_mul();
|
||||||
return UDQASTNode(current.type, current.value, left, right);
|
return UDQASTNode(current.type, current.value, left, right);
|
||||||
@ -145,9 +207,8 @@ UDQASTNode UDQParser::parse_pow() {
|
|||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQASTNode UDQParser::parse_mul()
|
||||||
|
{
|
||||||
UDQASTNode UDQParser::parse_mul() {
|
|
||||||
std::vector<UDQASTNode> nodes;
|
std::vector<UDQASTNode> nodes;
|
||||||
{
|
{
|
||||||
std::unique_ptr<UDQASTNode> current_node;
|
std::unique_ptr<UDQASTNode> current_node;
|
||||||
@ -156,36 +217,48 @@ UDQASTNode UDQParser::parse_mul() {
|
|||||||
if (current_node) {
|
if (current_node) {
|
||||||
current_node->set_right(node);
|
current_node->set_right(node);
|
||||||
nodes.push_back(*current_node);
|
nodes.push_back(*current_node);
|
||||||
} else
|
}
|
||||||
|
else {
|
||||||
nodes.push_back(node);
|
nodes.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
auto current_token = this->current();
|
auto current_token = this->current();
|
||||||
if (current_token.type == UDQTokenType::binary_op_mul || current_token.type == UDQTokenType::binary_op_div) {
|
if ((current_token.type == UDQTokenType::binary_op_mul) ||
|
||||||
current_node.reset( new UDQASTNode(current_token.type, current_token.value) );
|
(current_token.type == UDQTokenType::binary_op_div))
|
||||||
|
{
|
||||||
|
current_node = std::make_unique<UDQASTNode>(current_token.type, current_token.value);
|
||||||
|
|
||||||
this->next();
|
this->next();
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
return UDQASTNode( UDQTokenType::error );
|
return UDQASTNode( UDQTokenType::error );
|
||||||
} else break;
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQASTNode top_node = nodes.back();
|
UDQASTNode top_node = nodes.back();
|
||||||
if (nodes.size() > 1) {
|
if (nodes.size() > 1) {
|
||||||
UDQASTNode * current = &top_node;
|
UDQASTNode* current = &top_node;
|
||||||
for (std::size_t index = nodes.size() - 1; index > 0; index--) {
|
for (std::size_t index = nodes.size() - 1; index > 0; index--) {
|
||||||
current->set_left(nodes[index - 1]);
|
current->set_left(nodes[index - 1]);
|
||||||
current = current->get_left();
|
current = current->get_left();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return top_node;
|
return top_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQASTNode UDQParser::parse_add()
|
||||||
UDQASTNode UDQParser::parse_add() {
|
{
|
||||||
std::vector<UDQASTNode> nodes;
|
std::vector<UDQASTNode> nodes;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::unique_ptr<UDQASTNode> current_node;
|
std::unique_ptr<UDQASTNode> current_node;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -193,119 +266,117 @@ UDQASTNode UDQParser::parse_add() {
|
|||||||
if (current_node) {
|
if (current_node) {
|
||||||
current_node->set_right(node);
|
current_node->set_right(node);
|
||||||
nodes.push_back(*current_node);
|
nodes.push_back(*current_node);
|
||||||
} else
|
}
|
||||||
|
else {
|
||||||
nodes.push_back(node);
|
nodes.push_back(node);
|
||||||
|
}
|
||||||
|
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
auto current_token = this->current();
|
auto current_token = this->current();
|
||||||
if (current_token.type == UDQTokenType::binary_op_add || current_token.type == UDQTokenType::binary_op_sub) {
|
if ((current_token.type == UDQTokenType::binary_op_add) ||
|
||||||
current_node.reset( new UDQASTNode(current_token.type, current_token.value) );
|
(current_token.type == UDQTokenType::binary_op_sub))
|
||||||
|
{
|
||||||
|
current_node = std::make_unique<UDQASTNode>
|
||||||
|
(current_token.type, current_token.value);
|
||||||
|
|
||||||
this->next();
|
this->next();
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
return UDQASTNode( UDQTokenType::error );
|
return UDQASTNode(UDQTokenType::error);
|
||||||
} else if (current_token.type == UDQTokenType::close_paren || UDQ::cmpFunc(current_token.type) || UDQ::setFunc(current_token.type))
|
}
|
||||||
|
}
|
||||||
|
else if ((current_token.type == UDQTokenType::close_paren) ||
|
||||||
|
UDQ::cmpFunc(current_token.type) ||
|
||||||
|
UDQ::setFunc(current_token.type))
|
||||||
|
{
|
||||||
break;
|
break;
|
||||||
else
|
}
|
||||||
return UDQASTNode( UDQTokenType::error );
|
else {
|
||||||
|
return UDQASTNode(UDQTokenType::error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQASTNode top_node = nodes.back();
|
UDQASTNode top_node = nodes.back();
|
||||||
if (nodes.size() > 1) {
|
if (nodes.size() > 1) {
|
||||||
UDQASTNode * current = &top_node;
|
UDQASTNode* current = &top_node;
|
||||||
for (std::size_t index = nodes.size() - 1; index > 0; index--) {
|
for (std::size_t index = nodes.size() - 1; index > 0; index--) {
|
||||||
current->set_left(nodes[index - 1]);
|
current->set_left(nodes[index - 1]);
|
||||||
current = current->get_left();
|
current = current->get_left();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return top_node;
|
return top_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A bit uncertain on the presedence of the comparison operators. In normal
|
||||||
|
// C the comparion operators bind weaker than addition, i.e. for the
|
||||||
|
// assignment:
|
||||||
|
//
|
||||||
|
// auto cmp = a + b < c;
|
||||||
|
//
|
||||||
|
// The sum (a+b) is evaluated and then compared with c, that is the order of
|
||||||
|
// presedence implemented here. But reading the eclipse UDQ manual one can
|
||||||
|
// get the imporession that the relation operators should bind "very
|
||||||
|
// strong", i.e. that (b < c) should be evaluated first, and then the
|
||||||
|
// result of the comparison added to a.
|
||||||
|
|
||||||
/*
|
UDQASTNode UDQParser::parse_cmp()
|
||||||
A bit uncertain on the presedence of the comparison operators. In normal C the
|
{
|
||||||
comparion operators bind weaker than addition, i.e. for the assignment:
|
|
||||||
|
|
||||||
auto cmp = a + b < c;
|
|
||||||
|
|
||||||
The sum (a+b) is evaluated and then compared with c, that is the order of
|
|
||||||
presedence implemented here. But reading the eclipse UDQ manual one can get
|
|
||||||
the imporession that the relation operators should bind "very strong", i.e.
|
|
||||||
that (b < c) should be evaluated first, and then the result of the comparison
|
|
||||||
added to a.
|
|
||||||
*/
|
|
||||||
|
|
||||||
UDQASTNode UDQParser::parse_cmp() {
|
|
||||||
auto left = this->parse_add();
|
auto left = this->parse_add();
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
return left;
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
auto current = this->current();
|
auto current = this->current();
|
||||||
if (UDQ::cmpFunc(current.type)) {
|
if (UDQ::cmpFunc(current.type)) {
|
||||||
auto func_node = current;
|
auto func_node = current;
|
||||||
|
|
||||||
this->next();
|
this->next();
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
return UDQASTNode(UDQTokenType::error);
|
return UDQASTNode(UDQTokenType::error);
|
||||||
|
}
|
||||||
|
|
||||||
auto right = this->parse_cmp();
|
auto right = this->parse_cmp();
|
||||||
return UDQASTNode(current.type, current.value, left, right);
|
return UDQASTNode(current.type, current.value, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQASTNode UDQParser::parse_set()
|
||||||
UDQASTNode UDQParser::parse_set() {
|
{
|
||||||
auto left = this->parse_cmp();
|
auto left = this->parse_cmp();
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
return left;
|
return left;
|
||||||
|
}
|
||||||
|
|
||||||
auto current = this->current();
|
auto current = this->current();
|
||||||
if (UDQ::setFunc(current.type)) {
|
if (UDQ::setFunc(current.type)) {
|
||||||
auto func_node = current;
|
auto func_node = current;
|
||||||
|
|
||||||
this->next();
|
this->next();
|
||||||
if (this->empty())
|
if (this->empty()) {
|
||||||
return UDQASTNode(UDQTokenType::error);
|
return UDQASTNode(UDQTokenType::error);
|
||||||
|
}
|
||||||
|
|
||||||
auto right = this->parse_set();
|
auto right = this->parse_set();
|
||||||
return UDQASTNode(current.type, current.value, left, right);
|
return UDQASTNode(current.type, current.value, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQASTNode
|
||||||
namespace {
|
UDQParser::parse(const UDQParams& udq_params,
|
||||||
void dump_tokens(const std::string& target_var, const std::vector<UDQToken>& tokens) {
|
const UDQVarType target_type,
|
||||||
std::cout << target_var << " = ";
|
const std::string& target_var,
|
||||||
for (const auto& token : tokens)
|
const KeywordLocation& location,
|
||||||
std::cout << token.str();
|
const std::vector<UDQToken>& tokens,
|
||||||
std::cout << std::endl;
|
const ParseContext& parseContext,
|
||||||
}
|
ErrorGuard& errors)
|
||||||
|
|
||||||
/*
|
|
||||||
This function is extremely weak - hopefully it can be improved in the future.
|
|
||||||
See the comment in UDQEnums.hpp about 'UDQ type system'.
|
|
||||||
*/
|
|
||||||
bool static_type_check(UDQVarType lhs, UDQVarType rhs) {
|
|
||||||
if (lhs == rhs)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if (rhs == UDQVarType::SCALAR)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/*
|
|
||||||
This does not check if the rhs evaluates to a scalar.
|
|
||||||
*/
|
|
||||||
if (rhs == UDQVarType::WELL_VAR)
|
|
||||||
return (lhs == UDQVarType::WELL_VAR);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type, const std::string& target_var, const KeywordLocation& location, const std::vector<UDQToken>& tokens, const ParseContext& parseContext, ErrorGuard& errors)
|
|
||||||
{
|
{
|
||||||
UDQParser parser(udq_params, tokens);
|
UDQParser parser(udq_params, tokens);
|
||||||
parser.next();
|
parser.next();
|
||||||
@ -315,20 +386,26 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type,
|
|||||||
auto current = parser.current();
|
auto current = parser.current();
|
||||||
std::string msg_fmt = fmt::format("Problem parsing UDQ {}\n"
|
std::string msg_fmt = fmt::format("Problem parsing UDQ {}\n"
|
||||||
"In {{file}} line {{line}}.\n"
|
"In {{file}} line {{line}}.\n"
|
||||||
"Extra unhandled data starting with item {}.", target_var, current.string());
|
"Extra unhandled data starting with item {}.",
|
||||||
|
target_var, current.string());
|
||||||
|
|
||||||
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
|
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
|
||||||
return UDQASTNode( udq_params.undefinedValue() );
|
return UDQASTNode( udq_params.undefinedValue() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tree.valid()) {
|
if (!tree.valid()) {
|
||||||
std::string token_string;
|
std::string token_string;
|
||||||
for (const auto& token : tokens)
|
for (const auto& token : tokens) {
|
||||||
token_string += token.str() + " ";
|
token_string += token.str() + " ";
|
||||||
|
}
|
||||||
|
|
||||||
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
|
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
|
||||||
"In {{file}} line {{line}}.\n"
|
"In {{file}} line {{line}}.\n"
|
||||||
"This can be a bug in flow or a bug in the UDQ input string.\n"
|
"This can be a bug in flow or a "
|
||||||
"UDQ input: '{}'", target_var, token_string);
|
"bug in the UDQ input string.\n"
|
||||||
|
"UDQ input: '{}'",
|
||||||
|
target_var, token_string);
|
||||||
|
|
||||||
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
|
parseContext.handleError(ParseContext::UDQ_PARSE_ERROR, msg_fmt, location, errors);
|
||||||
return UDQASTNode( udq_params.undefinedValue() );
|
return UDQASTNode( udq_params.undefinedValue() );
|
||||||
}
|
}
|
||||||
@ -336,27 +413,35 @@ UDQASTNode UDQParser::parse(const UDQParams& udq_params, UDQVarType target_type,
|
|||||||
if (!static_type_check(target_type, tree.var_type)) {
|
if (!static_type_check(target_type, tree.var_type)) {
|
||||||
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
|
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
|
||||||
"In {{file}} line {{line}}.\n"
|
"In {{file}} line {{line}}.\n"
|
||||||
"Invalid type conversion detected in UDQ expression expected: {} got: {}", target_var, UDQ::typeName(target_type), UDQ::typeName(tree.var_type));
|
"Invalid type conversion detected "
|
||||||
|
"in UDQ expression expected: {}, got: {}",
|
||||||
|
target_var,
|
||||||
|
UDQ::typeName(target_type),
|
||||||
|
UDQ::typeName(tree.var_type));
|
||||||
|
|
||||||
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
|
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
|
||||||
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE)
|
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE) {
|
||||||
dump_tokens(target_var, tokens);
|
dump_tokens(target_var, tokens);
|
||||||
|
}
|
||||||
|
|
||||||
return UDQASTNode( udq_params.undefinedValue() );
|
return UDQASTNode(udq_params.undefinedValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tree.var_type == UDQVarType::NONE) {
|
if (tree.var_type == UDQVarType::NONE) {
|
||||||
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
|
std::string msg_fmt = fmt::format("Failed to parse UDQ {}\n"
|
||||||
"In {{file}} line {{line}}.\n"
|
"In {{file}} line {{line}}.\n"
|
||||||
"Could not determine expression type.", target_var);
|
"Could not determine "
|
||||||
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
|
"expression type.", target_var);
|
||||||
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE)
|
|
||||||
dump_tokens(target_var, tokens);
|
|
||||||
|
|
||||||
return UDQASTNode( udq_params.undefinedValue() );
|
parseContext.handleError(ParseContext::UDQ_TYPE_ERROR, msg_fmt, location, errors);
|
||||||
|
if (parseContext.get(ParseContext::UDQ_TYPE_ERROR) != InputError::IGNORE) {
|
||||||
|
dump_tokens(target_var, tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UDQASTNode(udq_params.undefinedValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
return tree;
|
return tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Opm
|
||||||
|
@ -16,70 +16,85 @@
|
|||||||
OPM. If not, see <http://www.gnu.org/licenses/>.
|
OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef UDQPARSER_HPP
|
#ifndef UDQPARSER_HPP
|
||||||
#define UDQPARSER_HPP
|
#define UDQPARSER_HPP
|
||||||
|
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
|
||||||
|
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQASTNode.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQFunctionTable.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQParams.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQEnums.hpp>
|
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQToken.hpp>
|
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
class ParseContext;
|
class ParseContext;
|
||||||
class ErrorGuard;
|
class ErrorGuard;
|
||||||
class KeywordLocation;
|
class KeywordLocation;
|
||||||
|
|
||||||
struct UDQParseNode {
|
} // namespace Opm
|
||||||
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg, const std::vector<std::string>& selector_arg) :
|
|
||||||
type(type_arg),
|
namespace Opm {
|
||||||
value(value_arg),
|
|
||||||
selector(selector_arg)
|
struct UDQParseNode
|
||||||
|
{
|
||||||
|
UDQParseNode(const UDQTokenType type_arg,
|
||||||
|
const std::variant<std::string, double>& value_arg,
|
||||||
|
const std::vector<std::string>& selector_arg)
|
||||||
|
: type(type_arg)
|
||||||
|
, value(value_arg)
|
||||||
|
, selector(selector_arg)
|
||||||
{
|
{
|
||||||
if (type_arg == UDQTokenType::ecl_expr)
|
if (type_arg == UDQTokenType::ecl_expr) {
|
||||||
this->var_type = UDQ::targetType(std::get<std::string>(value_arg), selector_arg);
|
this->var_type = UDQ::targetType(std::get<std::string>(value_arg), selector_arg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg)
|
||||||
UDQParseNode(UDQTokenType type_arg, const std::variant<std::string, double>& value_arg) :
|
: UDQParseNode(type_arg, value_arg, {})
|
||||||
UDQParseNode(type_arg, value_arg, {})
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
// Implicit converting constructor.
|
// Implicit converting constructor.
|
||||||
UDQParseNode(UDQTokenType type_arg) : UDQParseNode(type_arg, "")
|
UDQParseNode(UDQTokenType type_arg) : UDQParseNode(type_arg, "")
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string string() const {
|
std::string string() const
|
||||||
if (std::holds_alternative<std::string>(this->value))
|
{
|
||||||
|
if (std::holds_alternative<std::string>(this->value)) {
|
||||||
return std::get<std::string>(this->value);
|
return std::get<std::string>(this->value);
|
||||||
else
|
}
|
||||||
return std::to_string( std::get<double>(this->value));
|
else {
|
||||||
|
return std::to_string(std::get<double>(this->value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UDQTokenType type;
|
UDQTokenType type;
|
||||||
std::variant<std::string, double> value;
|
std::variant<std::string, double> value;
|
||||||
std::vector<std::string> selector;
|
std::vector<std::string> selector;
|
||||||
UDQVarType var_type = UDQVarType::NONE;
|
UDQVarType var_type = UDQVarType::NONE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UDQParser
|
||||||
class UDQParser {
|
{
|
||||||
public:
|
public:
|
||||||
static UDQASTNode parse(const UDQParams& udq_params, UDQVarType target_type, const std::string& target_var, const KeywordLocation& location, const std::vector<UDQToken>& tokens_, const ParseContext& parseContext, ErrorGuard& errors);
|
static UDQASTNode
|
||||||
|
parse(const UDQParams& udq_params,
|
||||||
|
UDQVarType target_type,
|
||||||
|
const std::string& target_var,
|
||||||
|
const KeywordLocation& location,
|
||||||
|
const std::vector<UDQToken>& tokens_,
|
||||||
|
const ParseContext& parseContext,
|
||||||
|
ErrorGuard& errors);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UDQParser(const UDQParams& udq_params1, const std::vector<UDQToken>& tokens_) :
|
UDQParser(const UDQParams& udq_params1,
|
||||||
udq_params(udq_params1),
|
const std::vector<UDQToken>& tokens_)
|
||||||
udqft(UDQFunctionTable(udq_params)),
|
: udq_params(udq_params1)
|
||||||
tokens(tokens_)
|
, udqft(UDQFunctionTable(udq_params))
|
||||||
|
, tokens(tokens_)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
UDQASTNode parse_set();
|
UDQASTNode parse_set();
|
||||||
@ -101,7 +116,6 @@ private:
|
|||||||
ssize_t current_pos = -1;
|
ssize_t current_pos = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Opm
|
||||||
|
|
||||||
}
|
#endif // UDQPARSER_HPP
|
||||||
|
|
||||||
#endif
|
|
||||||
|
@ -16,12 +16,21 @@
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
#include <opm/common/utility/shmatch.hpp>
|
#include <opm/common/utility/shmatch.hpp>
|
||||||
#include <opm/input/eclipse/Schedule/UDQ/UDQSet.hpp>
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <optional>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
@ -216,12 +225,13 @@ UDQSet UDQSet::groups(const std::string& name, const std::vector<std::string>& g
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool UDQSet::has(const std::string& name) const {
|
bool UDQSet::has(const std::string& name) const
|
||||||
for (const auto& res : this->values) {
|
{
|
||||||
if (res.wgname() == name)
|
return std::any_of(this->values.begin(), this->values.end(),
|
||||||
return true;
|
[&name](const UDQScalar& value)
|
||||||
}
|
{
|
||||||
return false;
|
return value.wgname() == name;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t UDQSet::size() const {
|
std::size_t UDQSet::size() const {
|
||||||
@ -342,25 +352,36 @@ std::vector<double> UDQSet::defined_values() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::size_t UDQSet::defined_size() const {
|
std::size_t UDQSet::defined_size() const
|
||||||
std::size_t dsize = 0;
|
{
|
||||||
for (const auto& v : this->values) {
|
return std::count_if(this->values.begin(), this->values.end(),
|
||||||
if (v)
|
[](const UDQScalar& value)
|
||||||
dsize += 1;
|
{
|
||||||
}
|
return value.defined();
|
||||||
return dsize;
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const UDQScalar& UDQSet::operator[](std::size_t index) const {
|
const UDQScalar& UDQSet::operator[](std::size_t index) const
|
||||||
if (index >= this->size())
|
{
|
||||||
|
if (index >= this->size()) {
|
||||||
throw std::out_of_range("Index out of range in UDQset::operator[]");
|
throw std::out_of_range("Index out of range in UDQset::operator[]");
|
||||||
|
}
|
||||||
|
|
||||||
return this->values[index];
|
return this->values[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const UDQScalar& UDQSet::operator[](const std::string& wgname) const {
|
const UDQScalar& UDQSet::operator[](const std::string& wgname) const
|
||||||
auto value_iter = std::find_if( this->values.begin(), this->values.end(), [&wgname](const UDQScalar& value) { return (value.wgname() == wgname );});
|
{
|
||||||
if (value_iter == this->values.end())
|
auto value_iter = std::find_if(this->values.begin(), this->values.end(),
|
||||||
|
[&wgname](const UDQScalar& value)
|
||||||
|
{
|
||||||
|
return value.wgname() == wgname;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (value_iter == this->values.end()) {
|
||||||
throw std::out_of_range("No such well/group: " + wgname);
|
throw std::out_of_range("No such well/group: " + wgname);
|
||||||
|
}
|
||||||
|
|
||||||
return *value_iter;
|
return *value_iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -453,54 +474,58 @@ UDQScalar operator/(double lhs, const UDQScalar& rhs) {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool is_scalar(const UDQSet& udq_set) {
|
bool is_scalar(const UDQSet& udq_set)
|
||||||
if (udq_set.var_type() == UDQVarType::SCALAR)
|
{
|
||||||
return true;
|
const auto vtype = udq_set.var_type();
|
||||||
|
|
||||||
if (udq_set.var_type() == UDQVarType::FIELD_VAR)
|
return (vtype == UDQVarType::SCALAR)
|
||||||
return true;
|
|| (vtype == UDQVarType::FIELD_VAR);
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If one result set is scalar and the other represents a set of
|
||||||
/*
|
// wells/groups, the scalar result is promoted to a set of the right type.
|
||||||
If one result set is scalar and the other represents a set of wells/groups,
|
//
|
||||||
the scalar result is promoted to a set of the right type.
|
// This function is quite subconscious about FIELD / SCALAR.
|
||||||
|
|
||||||
This function is quite subconcious about FIELD / SCALAR.
|
|
||||||
*/
|
|
||||||
std::pair<UDQSet, UDQSet> udq_cast(const UDQSet& lhs, const UDQSet& rhs)
|
std::pair<UDQSet, UDQSet> udq_cast(const UDQSet& lhs, const UDQSet& rhs)
|
||||||
{
|
{
|
||||||
if (lhs.var_type() == rhs.var_type())
|
if (lhs.var_type() == rhs.var_type()) {
|
||||||
return std::make_pair(lhs,rhs);
|
return { lhs, rhs };
|
||||||
|
}
|
||||||
|
|
||||||
if (lhs.size() == rhs.size())
|
if (is_scalar(lhs) && is_scalar(rhs)) {
|
||||||
return std::make_pair(lhs,rhs);
|
return { lhs, rhs };
|
||||||
|
}
|
||||||
|
|
||||||
if (is_scalar(lhs)) {
|
if (is_scalar(lhs)) {
|
||||||
if (rhs.var_type() == UDQVarType::WELL_VAR)
|
if (rhs.var_type() == UDQVarType::WELL_VAR) {
|
||||||
return std::make_pair(UDQSet::wells(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs);
|
return { UDQSet::wells(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs };
|
||||||
|
}
|
||||||
|
|
||||||
if (rhs.var_type() == UDQVarType::GROUP_VAR)
|
if (rhs.var_type() == UDQVarType::GROUP_VAR) {
|
||||||
return std::make_pair(UDQSet::groups(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs);
|
return { UDQSet::groups(lhs.name(), rhs.wgnames(), lhs[0].get()), rhs };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_scalar(rhs)) {
|
if (is_scalar(rhs)) {
|
||||||
if (lhs.var_type() == UDQVarType::WELL_VAR)
|
if (lhs.var_type() == UDQVarType::WELL_VAR) {
|
||||||
return std::make_pair(lhs, UDQSet::wells(rhs.name(), lhs.wgnames(), rhs[0].get()));
|
return { lhs, UDQSet::wells(rhs.name(), lhs.wgnames(), rhs[0].get()) };
|
||||||
|
}
|
||||||
|
|
||||||
if (lhs.var_type() == UDQVarType::GROUP_VAR)
|
if (lhs.var_type() == UDQVarType::GROUP_VAR) {
|
||||||
return std::make_pair(lhs, UDQSet::groups(rhs.name(), lhs.wgnames(), rhs[0].get()));
|
return { lhs, UDQSet::groups(rhs.name(), lhs.wgnames(), rhs[0].get()) };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto msg = fmt::format("Type/size mismatch when combining UDQs {}(size={}, type={}) and {}(size={}, type={})",
|
throw std::logic_error {
|
||||||
lhs.name(), lhs.size(), static_cast<int>(lhs.var_type()),
|
fmt::format("Type/size mismatch when combining UDQs "
|
||||||
rhs.name(), rhs.size(), static_cast<int>(rhs.var_type()));
|
"{}(size={}, type={}) and "
|
||||||
throw std::logic_error(msg);
|
"{}(size={}, type={})",
|
||||||
|
lhs.name(), lhs.size(), UDQ::typeName(lhs.var_type()),
|
||||||
|
rhs.name(), rhs.size(), UDQ::typeName(rhs.var_type()))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // Anonymous namespace
|
||||||
|
|
||||||
UDQSet operator+(const UDQSet&lhs, const UDQSet& rhs) {
|
UDQSet operator+(const UDQSet&lhs, const UDQSet& rhs) {
|
||||||
auto [left,right] = udq_cast(lhs, rhs);
|
auto [left,right] = udq_cast(lhs, rhs);
|
||||||
@ -584,4 +609,4 @@ bool UDQSet::operator==(const UDQSet& other) const {
|
|||||||
this->values == other.values;
|
this->values == other.values;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace Opm
|
||||||
|
@ -36,47 +36,57 @@ namespace {
|
|||||||
|
|
||||||
namespace Opm {
|
namespace Opm {
|
||||||
|
|
||||||
UDQToken::UDQToken(const std::string& string_token, UDQTokenType token_type_) :
|
UDQToken::UDQToken(const std::string& string_token,
|
||||||
token_type(token_type_)
|
const UDQTokenType token_type_)
|
||||||
|
: token_type(token_type_)
|
||||||
{
|
{
|
||||||
if (this->token_type == UDQTokenType::number)
|
if (this->token_type == UDQTokenType::number) {
|
||||||
this->m_value = stod(string_token);
|
this->m_value = stod(string_token);
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
this->m_value = string_token;
|
this->m_value = string_token;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQToken::UDQToken(const std::string& string_token, const std::vector<std::string>& selector_):
|
UDQToken::UDQToken(const std::string& string_token,
|
||||||
token_type(UDQTokenType::ecl_expr),
|
const std::vector<std::string>& selector_)
|
||||||
m_value(string_token),
|
: token_type(UDQTokenType::ecl_expr)
|
||||||
m_selector(selector_)
|
, m_value (string_token)
|
||||||
|
, m_selector(selector_)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const std::variant<std::string, double>& UDQToken::value() const
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
const std::variant<std::string, double>& UDQToken::value() const {
|
|
||||||
return this->m_value;
|
return this->m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string>& UDQToken::selector() const {
|
const std::vector<std::string>& UDQToken::selector() const
|
||||||
|
{
|
||||||
return this->m_selector;
|
return this->m_selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
UDQTokenType UDQToken::type() const {
|
UDQTokenType UDQToken::type() const
|
||||||
|
{
|
||||||
return this->token_type;
|
return this->token_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string UDQToken::str() const {
|
std::string UDQToken::str() const
|
||||||
|
{
|
||||||
if (std::holds_alternative<std::string>(this->m_value)) {
|
if (std::holds_alternative<std::string>(this->m_value)) {
|
||||||
if (this->m_selector.empty())
|
if (this->m_selector.empty()) {
|
||||||
return std::get<std::string>(this->m_value);
|
return std::get<std::string>(this->m_value);
|
||||||
|
}
|
||||||
|
|
||||||
std::string quoted_selector;
|
std::string quoted_selector;
|
||||||
for (const auto& s : this->m_selector)
|
for (const auto& s : this->m_selector) {
|
||||||
quoted_selector += " '" + s + "'";
|
quoted_selector += " '" + s + "'";
|
||||||
|
}
|
||||||
|
|
||||||
return std::get<std::string>(this->m_value) + quoted_selector;
|
return std::get<std::string>(this->m_value) + quoted_selector;
|
||||||
} else
|
}
|
||||||
|
else {
|
||||||
return format_double(std::get<double>(this->m_value));
|
return format_double(std::get<double>(this->m_value));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Opm
|
} // namespace Opm
|
||||||
|
Loading…
Reference in New Issue
Block a user