From b148769cc63d2f3cd04947f8066a1a12365ddecb Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Sat, 13 Apr 2019 09:10:24 +0200 Subject: [PATCH] Internalize UDA values in the deck --- GenerateKeywords.cmake | 1 + opm/parser/eclipse/Deck/DeckItem.hpp | 9 +- opm/parser/eclipse/Parser/ParserItem.hpp | 2 + opm/parser/eclipse/Utility/Typetools.hpp | 14 ++- src/opm/parser/eclipse/Deck/DeckItem.cpp | 96 ++++++++++++++++--- src/opm/parser/eclipse/Deck/DeckOutput.cpp | 10 ++ .../eclipse/Generator/KeywordGenerator.cpp | 1 + src/opm/parser/eclipse/Parser/ParserItem.cpp | 75 +++++++++++---- .../parser/eclipse/Parser/ParserKeyword.cpp | 2 - .../parser/eclipse/Parser/ParserRecord.cpp | 16 +++- src/opm/parser/eclipse/RawDeck/StarToken.cpp | 13 +++ tests/parser/UDQTests.cpp | 4 - 12 files changed, 198 insertions(+), 45 deletions(-) diff --git a/GenerateKeywords.cmake b/GenerateKeywords.cmake index b53b29a85..1d3262bad 100644 --- a/GenerateKeywords.cmake +++ b/GenerateKeywords.cmake @@ -1,5 +1,6 @@ set(genkw_SOURCES src/opm/json/JsonObject.cpp src/opm/parser/eclipse/Parser/createDefaultKeywordList.cpp + src/opm/parser/eclipse/Deck/UDAValue.cpp src/opm/parser/eclipse/Deck/Deck.cpp src/opm/parser/eclipse/Deck/DeckItem.cpp src/opm/parser/eclipse/Deck/DeckKeyword.cpp diff --git a/opm/parser/eclipse/Deck/DeckItem.hpp b/opm/parser/eclipse/Deck/DeckItem.hpp index f9e7650dd..f125f6e31 100644 --- a/opm/parser/eclipse/Deck/DeckItem.hpp +++ b/opm/parser/eclipse/Deck/DeckItem.hpp @@ -27,6 +27,7 @@ #include #include +#include namespace Opm { class DeckOutput; @@ -39,6 +40,7 @@ namespace Opm { DeckItem( const std::string&, int, size_t size_hint = 8 ); DeckItem( const std::string&, double, size_t size_hint = 8 ); DeckItem( const std::string&, std::string, size_t size_hint = 8 ); + DeckItem( const std::string&, UDAValue, size_t size_hint = 8 ); const std::string& name() const; @@ -58,6 +60,7 @@ namespace Opm { size_t size() const; size_t out_size() const; + //template< typename T > T& get( size_t ) ; template< typename T > const T& get( size_t ) const; double getSIDouble( size_t ) const; std::string getTrimmedString( size_t ) const; @@ -65,12 +68,15 @@ namespace Opm { template< typename T > const std::vector< T >& getData() const; const std::vector< double >& getSIDoubleData() const; + void push_back( UDAValue ); void push_back( int ); void push_back( double ); void push_back( std::string ); + void push_back( UDAValue, size_t ); void push_back( int, size_t ); void push_back( double, size_t ); void push_back( std::string, size_t ); + void push_backDefault( UDAValue ); void push_backDefault( int ); void push_backDefault( double ); void push_backDefault( std::string ); @@ -107,9 +113,10 @@ namespace Opm { bool operator!=(const DeckItem& other) const; static bool to_bool(std::string string_value); private: - std::vector< double > dval; + mutable std::vector< double > dval; std::vector< int > ival; std::vector< std::string > sval; + std::vector< UDAValue > uval; type_tag type = type_tag::unknown; diff --git a/opm/parser/eclipse/Parser/ParserItem.hpp b/opm/parser/eclipse/Parser/ParserItem.hpp index 2dec702a5..4145e11e9 100644 --- a/opm/parser/eclipse/Parser/ParserItem.hpp +++ b/opm/parser/eclipse/Parser/ParserItem.hpp @@ -80,6 +80,7 @@ namespace Opm { size_t numDimensions() const; const std::string& name() const; item_size sizeType() const; + type_tag dataType() const; void setSizeType(item_size size_type); std::string getDescription() const; bool scalar() const; @@ -108,6 +109,7 @@ namespace Opm { double dval; int ival; std::string sval; + UDAValue uval; std::vector< std::string > dimensions; std::string m_name; diff --git a/opm/parser/eclipse/Utility/Typetools.hpp b/opm/parser/eclipse/Utility/Typetools.hpp index 6ef4e5ea0..75f284c19 100644 --- a/opm/parser/eclipse/Utility/Typetools.hpp +++ b/opm/parser/eclipse/Utility/Typetools.hpp @@ -1,16 +1,15 @@ #ifndef OPM_TYPETOOLS_HPP #define OPM_TYPETOOLS_HPP +#include namespace Opm { enum class type_tag { - /* for python interop as well as queries, must be manually synchronised - * with cdeck_item.cc and opm/deck/item_type_enum.py - */ unknown = 0, integer = 1, string = 2, fdouble = 3, + uda = 4, }; inline std::string tag_name( type_tag x ) { @@ -18,23 +17,30 @@ inline std::string tag_name( type_tag x ) { case type_tag::integer: return "int"; case type_tag::string: return "std::string"; case type_tag::fdouble: return "double"; + case type_tag::uda: return "UDAValue"; case type_tag::unknown: return "unknown"; - } return "unknown"; } template< typename T > type_tag get_type(); + template<> inline type_tag get_type< int >() { return type_tag::integer; } + template<> inline type_tag get_type< double >() { return type_tag::fdouble; } + template<> inline type_tag get_type< std::string >() { return type_tag::string; } +template<> inline type_tag get_type() { + return type_tag::uda; +} + } #endif //OPM_TYPETOOLS_HPP diff --git a/src/opm/parser/eclipse/Deck/DeckItem.cpp b/src/opm/parser/eclipse/Deck/DeckItem.cpp index 6f4187830..935a845d0 100644 --- a/src/opm/parser/eclipse/Deck/DeckItem.cpp +++ b/src/opm/parser/eclipse/Deck/DeckItem.cpp @@ -41,27 +41,46 @@ std::vector< T >& DeckItem::value_ref() { template<> const std::vector< int >& DeckItem::value_ref< int >() const { if( this->type != get_type< int >() ) - throw std::invalid_argument( "Item of wrong type." ); + throw std::invalid_argument( "DekcItem::velut_ref Item of wrong type." ); return this->ival; } template<> const std::vector< double >& DeckItem::value_ref< double >() const { - if( this->type != get_type< double >() ) - throw std::invalid_argument( "Item of wrong type." ); + if (this->type == get_type()) + return this->dval; - return this->dval; + /* Temporary return double values when user code asks for double on + something which is really a UDAValue. + */ + if( this->type == get_type< UDAValue >() ) { + this->dval.clear(); + for (const auto& uv : this->uval) + this->dval.push_back(uv.get()); + + return this->dval; + } + throw std::invalid_argument( "DeckItem::value_ref Item of wrong type." ); } template<> const std::vector< std::string >& DeckItem::value_ref< std::string >() const { if( this->type != get_type< std::string >() ) - throw std::invalid_argument( "Item of wrong type." ); + throw std::invalid_argument( "DeckItem::value_ref Item of wrong type." ); return this->sval; } +template<> +const std::vector< UDAValue >& DeckItem::value_ref< UDAValue >() const { + if( this->type != get_type< UDAValue >() ) + throw std::invalid_argument( "DeckItem::value_ref Item of wrong type." ); + + return this->uval; +} + + DeckItem::DeckItem( const std::string& nm ) : item_name( nm ) {} DeckItem::DeckItem( const std::string& nm, int, size_t hint ) : @@ -80,6 +99,14 @@ DeckItem::DeckItem( const std::string& nm, double, size_t hint ) : this->defaulted.reserve( hint ); } +DeckItem::DeckItem( const std::string& nm, UDAValue , size_t hint ) : + type( get_type< UDAValue >() ), + item_name( nm ) +{ + this->uval.reserve( hint ); + this->defaulted.reserve( hint ); +} + DeckItem::DeckItem( const std::string& nm, std::string, size_t hint ) : type( get_type< std::string >() ), item_name( nm ) @@ -101,7 +128,8 @@ bool DeckItem::hasValue( size_t index ) const { case type_tag::integer: return this->ival.size() > index; case type_tag::fdouble: return this->dval.size() > index; case type_tag::string: return this->sval.size() > index; - default: throw std::logic_error( "Type not set." ); + case type_tag::uda: return this->uval.size() > index; + default: throw std::logic_error( "DeckItem::hasValue: Type not set." ); } } @@ -110,7 +138,8 @@ size_t DeckItem::size() const { case type_tag::integer: return this->ival.size(); case type_tag::fdouble: return this->dval.size(); case type_tag::string: return this->sval.size(); - default: throw std::logic_error( "Type not set." ); + case type_tag::uda: return this->uval.size(); + default: throw std::logic_error( "DeckItem::size: Type not set." ); } } @@ -119,6 +148,16 @@ size_t DeckItem::out_size() const { return std::max( data_size , this->defaulted.size() ); } +/* + The non const overload is only used for the UDAValue type because we need to + mutate the UDAValue object and add dimension to it retroactively. +*/ +/*template<> +UDAValue& DeckItem::get( size_t index ) { + return this->uval[index]; +} +*/ + template< typename T > const T& DeckItem::get( size_t index ) const { return this->value_ref< T >().at( index ); @@ -149,6 +188,10 @@ void DeckItem::push_back( std::string x ) { this->push( std::move( x ) ); } +void DeckItem::push_back( UDAValue x ) { + this->push( std::move( x ) ); +} + template< typename T > void DeckItem::push( T x, size_t n ) { auto& val = this->value_ref< T >(); @@ -169,6 +212,10 @@ void DeckItem::push_back( std::string x, size_t n ) { this->push( std::move( x ), n ); } +void DeckItem::push_back( UDAValue x, size_t n ) { + this->push( std::move( x ), n ); +} + template< typename T > void DeckItem::push_default( T x ) { auto& val = this->value_ref< T >(); @@ -192,6 +239,10 @@ void DeckItem::push_backDefault( std::string x ) { this->push_default( std::move( x ) ); } +void DeckItem::push_backDefault( UDAValue x ) { + this->push_default( std::move( x ) ); +} + void DeckItem::push_backDummyDefault() { if( !this->defaulted.empty() ) @@ -238,12 +289,26 @@ const std::vector< double >& DeckItem::getSIDoubleData() const { } void DeckItem::push_backDimension( const Dimension& active, - const Dimension& def ) { - const auto& ds = this->value_ref< double >(); - const bool dim_inactive = ds.empty() - || this->defaultApplied( ds.size() - 1 ); + const Dimension& def ) { + if (this->type == type_tag::fdouble) { + const auto& ds = this->value_ref< double >(); + const bool dim_inactive = ds.empty() + || this->defaultApplied( ds.size() - 1 ); - this->dimensions.push_back( dim_inactive ? def : active ); + this->dimensions.push_back( dim_inactive ? def : active ); + return; + } + + if (this->type == type_tag::uda) { + auto& du = this->value_ref< UDAValue >(); + const bool dim_inactive = du.empty() + || this->defaultApplied( du.size() - 1 ); + + this->dimensions.push_back( dim_inactive ? def : active ); + return; + } + + throw std::logic_error("Tried to push dimensions to an item which can not hold dimension. "); } type_tag DeckItem::getType() const { @@ -274,8 +339,11 @@ void DeckItem::write(DeckOutput& stream) const { case type_tag::string: this->write_vector( stream, this->sval ); break; + case type_tag::uda: + this->write_vector( stream, this->uval ); + break; default: - throw std::logic_error( "Type not set." ); + throw std::logic_error( "DeckItem::write: Type not set." ); } } @@ -405,8 +473,10 @@ bool DeckItem::to_bool(std::string string_value) { template const int& DeckItem::get< int >( size_t ) const; template const double& DeckItem::get< double >( size_t ) const; template const std::string& DeckItem::get< std::string >( size_t ) const; +template const UDAValue& DeckItem::get< UDAValue >( size_t ) const; template const std::vector< int >& DeckItem::getData< int >() const; template const std::vector< double >& DeckItem::getData< double >() const; +template const std::vector< UDAValue >& DeckItem::getData< UDAValue >() const; template const std::vector< std::string >& DeckItem::getData< std::string >() const; } diff --git a/src/opm/parser/eclipse/Deck/DeckOutput.cpp b/src/opm/parser/eclipse/Deck/DeckOutput.cpp index 81a5c4274..1adca84ba 100644 --- a/src/opm/parser/eclipse/Deck/DeckOutput.cpp +++ b/src/opm/parser/eclipse/Deck/DeckOutput.cpp @@ -20,6 +20,7 @@ #include #include +#include namespace Opm { @@ -82,6 +83,14 @@ namespace Opm { this->os << value; } + template <> + void DeckOutput::write_value( const UDAValue& value ) { + if (value.is()) + this->write_value(value.get()); + else + this->write_value(value.get()); + } + void DeckOutput::stash_default( ) { this->default_count++; } @@ -132,4 +141,5 @@ namespace Opm { template void DeckOutput::write( const int& value); template void DeckOutput::write( const double& value); template void DeckOutput::write( const std::string& value); + template void DeckOutput::write( const UDAValue& value); } diff --git a/src/opm/parser/eclipse/Generator/KeywordGenerator.cpp b/src/opm/parser/eclipse/Generator/KeywordGenerator.cpp index 36037ef27..999e13b63 100644 --- a/src/opm/parser/eclipse/Generator/KeywordGenerator.cpp +++ b/src/opm/parser/eclipse/Generator/KeywordGenerator.cpp @@ -49,6 +49,7 @@ const std::string testHeader = "auto unitSystem = UnitSystem::newMETRIC();\n"; const std::string sourceHeader = + "#include \n" "#include \n" "#include \n" "#include \n" diff --git a/src/opm/parser/eclipse/Parser/ParserItem.cpp b/src/opm/parser/eclipse/Parser/ParserItem.cpp index d1d898e62..ec03b21ba 100644 --- a/src/opm/parser/eclipse/Parser/ParserItem.cpp +++ b/src/opm/parser/eclipse/Parser/ParserItem.cpp @@ -30,7 +30,7 @@ #include #include #include - +#include namespace Opm { @@ -47,6 +47,11 @@ template<> const double& default_value< double >() { return value; } +template<> const UDAValue& default_value< UDAValue >() { + static const UDAValue value = UDAValue(std::numeric_limits::quiet_NaN()); + return value; +} + template<> const std::string& default_value< std::string >() { static const std::string value = ""; return value; @@ -57,7 +62,7 @@ type_tag get_data_type_json( const std::string& str ) { if( str == "DOUBLE" ) return type_tag::fdouble; if( str == "STRING" ) return type_tag::string; if( str == "RAW_STRING") return type_tag::string; - if( str == "UDA") return type_tag::fdouble; + if( str == "UDA") return type_tag::uda; throw std::invalid_argument( str + " cannot be converted to enum 'tag'" ); } @@ -88,7 +93,14 @@ std::string ParserItem::string_from_size( ParserItem::item_size sz ) { case item_size::SINGLE: return "SINGLE"; } - throw std::logic_error( "Fatal error; should not be reachable" ); + throw std::logic_error( "ParserItem::string_from_size: Fatal error; should not be reachable" ); +} + +template<> const UDAValue& ParserItem::value_ref< UDAValue >() const { + if( this->data_type != get_type< UDAValue >() ) + throw std::invalid_argument("ValueRef Wrong type." ); + + return this->uval; } template<> const int& ParserItem::value_ref< int >() const { @@ -164,17 +176,17 @@ ParserItem::ParserItem( const Json::JsonObject& json ) : this->setDefault( json.get_double( "default" ) ); break; + case itype::UDA: + this->setDefault( UDAValue(json.get_double( "default" )) ); + break; + case itype::STRING: case itype::RAW_STRING: this->setDefault( json.get_string( "default" ) ); break; - case itype::UDA: - this->setDefault( json.get_double( "default" ) ); - break; - default: - throw std::logic_error( "Item of unknown type." ); + throw std::logic_error( "Item of unknown type: <" + json.get_string("value_type") + ">" ); } } @@ -205,7 +217,7 @@ void ParserItem::setInputType(ParserItem::itype input_type) { this->setDataType( std::string() ); else if (input_type == itype::UDA) - this->setDataType( double() ); + this->setDataType( UDAValue(0) ); else throw std::invalid_argument("BUG: input type not recognized in setInputType()"); @@ -238,22 +250,17 @@ const T& ParserItem::getDefault() const { } bool ParserItem::hasDimension() const { - if( this->data_type != type_tag::fdouble ) - return false; - return !this->dimensions.empty(); } size_t ParserItem::numDimensions() const { - if( this->data_type != type_tag::fdouble ) return 0; return this->dimensions.size(); } const std::string& ParserItem::getDimension( size_t index ) const { - if( this->data_type != type_tag::fdouble ) - throw std::invalid_argument("Item is not double."); - - return this->dimensions.at( index ); + if( this->data_type == type_tag::fdouble || this->data_type == type_tag::uda) + return this->dimensions.at( index ); + throw std::invalid_argument("Item is not double / UDA ."); } void ParserItem::push_backDimension( const std::string& dim ) { @@ -278,6 +285,10 @@ void ParserItem::push_backDimension( const std::string& dim ) { } +type_tag ParserItem::dataType() const { + return this->data_type; +} + ParserItem::item_size ParserItem::sizeType() const { return m_sizeType; @@ -341,8 +352,12 @@ bool ParserItem::operator==( const ParserItem& rhs ) const { if( this->sval != rhs.sval ) return false; break; + case type_tag::uda: + if( this->uval != rhs.uval ) return false; + break; + default: - throw std::logic_error( "Item of unknown type." ); + throw std::logic_error( "Item of unknown type data_type:" + tag_name(this->data_type)); } } if( this->data_type != type_tag::fdouble ) return true; @@ -427,6 +442,13 @@ std::string ParserItem::createCode(const std::string& indent) const { stream << "double(" << as_string(this->getDefault()) << ")"; break; + case type_tag::uda: + { + double double_value =this->getDefault().get(); + stream << "UDAValue(" << as_string(double_value) << ")"; + } + break; + case type_tag::string: stream << "std::string(\"" << this->getDefault< std::string >() << "\")"; break; @@ -437,6 +459,9 @@ std::string ParserItem::createCode(const std::string& indent) const { stream << " );" << '\n'; } + for (size_t idim=0; idim < this->numDimensions(); idim++) + stream << indent <<"item.push_backDimension(\"" << this->getDimension( idim ) << "\");" << '\n'; + if (this->m_description.size() > 0) stream << indent << "item.setDescription(\"" << this->m_description << "\");" << '\n'; @@ -552,8 +577,10 @@ DeckItem ParserItem::scan( RawRecord& record ) const { return scan_item< double >( *this, record ); case type_tag::string: return scan_item< std::string >( *this, record ); + case type_tag::uda: + return scan_item(*this, record); default: - throw std::logic_error( "Fatal error; should not be reachable" ); + throw std::logic_error( "ParserItem::scan: Fatal error; should not be reachable" ); } } @@ -592,11 +619,16 @@ std::string ParserItem::inlineClassInit(const std::string& parentClass, return std::to_string( this->getDefault< int >() ); case type_tag::fdouble: return std::to_string( this->getDefault< double >() ); + case type_tag::uda: + { + double value = this->getDefault().get(); + return "UDAValue(" + std::to_string(value) + ")"; + } case type_tag::string: return "\"" + this->getDefault< std::string >() + "\""; default: - throw std::logic_error( "Fatal error; should not be reachable" ); + throw std::logic_error( "ParserItem::inlineClassInit: Fatal error; should not be reachable" ); } }; @@ -661,13 +693,16 @@ bool ParserItem::parseRaw( ) const { template void ParserItem::setDefault( int ); template void ParserItem::setDefault( double ); template void ParserItem::setDefault( std::string ); +template void ParserItem::setDefault( UDAValue ); template void ParserItem::setDataType( int ); template void ParserItem::setDataType( double ); template void ParserItem::setDataType( std::string ); +template void ParserItem::setDataType( UDAValue ); template const int& ParserItem::getDefault() const; template const double& ParserItem::getDefault() const; template const std::string& ParserItem::getDefault() const; +template const UDAValue& ParserItem::getDefault() const; } diff --git a/src/opm/parser/eclipse/Parser/ParserKeyword.cpp b/src/opm/parser/eclipse/Parser/ParserKeyword.cpp index a961f50dd..bfefb72c0 100644 --- a/src/opm/parser/eclipse/Parser/ParserKeyword.cpp +++ b/src/opm/parser/eclipse/Parser/ParserKeyword.cpp @@ -648,8 +648,6 @@ void set_dimensions( ParserItem& item, { std::string indent3 = local_indent + " "; ss << item.createCode(indent3); - for (size_t idim=0; idim < item.numDimensions(); idim++) - ss << indent3 <<"item.push_backDimension(\"" << item.getDimension( idim ) << "\");" << '\n'; { std::string addItemMethod = "addItem"; if (isDataKeyword()) diff --git a/src/opm/parser/eclipse/Parser/ParserRecord.cpp b/src/opm/parser/eclipse/Parser/ParserRecord.cpp index 38f0cc126..ada7354b9 100644 --- a/src/opm/parser/eclipse/Parser/ParserRecord.cpp +++ b/src/opm/parser/eclipse/Parser/ParserRecord.cpp @@ -99,12 +99,26 @@ namespace { if( !parser_item.hasDimension() ) continue; auto& deckItem = deckRecord.getItem( parser_item.name() ); - for (size_t idim = 0; idim < parser_item.numDimensions(); idim++) { auto activeDimension = deck.getActiveUnitSystem().getNewDimension( parser_item.getDimension(idim) ); auto defaultDimension = deck.getDefaultUnitSystem().getNewDimension( parser_item.getDimension(idim) ); deckItem.push_backDimension( activeDimension , defaultDimension ); } + + /* + A little special casing ... the UDAValue elements in the deck must + carry their own dimension. Observe that the + ParserItem::setSizeType() method guarantees that UDA data is + scalar, i.e. this special case loop can be simpler than the + general code in the block above. + */ + if (parser_item.dataType() == type_tag::uda && deckItem.size() > 0) { + auto uda = deckItem.get(0); + if (deckItem.defaultApplied(0)) + uda.set_dim( deck.getDefaultUnitSystem().getNewDimension( parser_item.getDimension(0))); + else + uda.set_dim( deck.getActiveUnitSystem().getNewDimension( parser_item.getDimension(0))); + } } } diff --git a/src/opm/parser/eclipse/RawDeck/StarToken.cpp b/src/opm/parser/eclipse/RawDeck/StarToken.cpp index e9edd2d33..becd965d1 100644 --- a/src/opm/parser/eclipse/RawDeck/StarToken.cpp +++ b/src/opm/parser/eclipse/RawDeck/StarToken.cpp @@ -28,6 +28,7 @@ #include #include +#include namespace qi = boost::spirit::qi; @@ -105,6 +106,7 @@ namespace Opm { throw std::invalid_argument( "Malformed floating point number '" + view + "'" ); } + template <> std::string readValueToken< std::string >( string_view view ) { if( view.size() == 0 || view[ 0 ] != '\'' ) @@ -116,6 +118,17 @@ namespace Opm { return view.substr( 1, view.size() - 1 ); } + template<> + UDAValue readValueToken< UDAValue >( string_view view ) { + double n = 0; + qi::real_parser< double, fortran_double< double > > double_; + auto cursor = view.begin(); + const auto ok = qi::parse( cursor, view.end(), double_, n ); + + if( ok && cursor == view.end() ) return UDAValue(n); + return UDAValue( readValueToken(view) ); + } + void StarToken::init_( const string_view& token ) { // special-case the interpretation of a lone star as "1*" but do not // allow constructs like "*123"... diff --git a/tests/parser/UDQTests.cpp b/tests/parser/UDQTests.cpp index 16a47f2a2..148b86526 100644 --- a/tests/parser/UDQTests.cpp +++ b/tests/parser/UDQTests.cpp @@ -978,8 +978,4 @@ BOOST_AUTO_TEST_CASE(UDA_VALUE) { BOOST_CHECK(value2.is()); BOOST_CHECK_EQUAL( value2.get(), std::string("FUBHP")); BOOST_CHECK_THROW( value2.get(), std::invalid_argument); - - - std::vector values; - values.resize(100, UDAValue(1000)); }