Internalize UDA values in the deck

This commit is contained in:
Joakim Hove 2019-04-13 09:10:24 +02:00
parent 656878d649
commit b148769cc6
12 changed files with 198 additions and 45 deletions

View File

@ -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

View File

@ -27,6 +27,7 @@
#include <opm/parser/eclipse/Units/Dimension.hpp>
#include <opm/parser/eclipse/Utility/Typetools.hpp>
#include <opm/parser/eclipse/Deck/UDAValue.hpp>
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;

View File

@ -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;

View File

@ -1,16 +1,15 @@
#ifndef OPM_TYPETOOLS_HPP
#define OPM_TYPETOOLS_HPP
#include <opm/parser/eclipse/Deck/UDAValue.hpp>
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<UDAValue>() {
return type_tag::uda;
}
}
#endif //OPM_TYPETOOLS_HPP

View File

@ -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<int> 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<double>())
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<double>());
return this->dval;
}
throw std::invalid_argument( "DeckItem::value_ref<double> 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<std::string> 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<UDAValue> 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() )
@ -239,11 +290,25 @@ const std::vector< double >& DeckItem::getSIDoubleData() const {
void DeckItem::push_backDimension( const Dimension& active,
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 );
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;
}

View File

@ -20,6 +20,7 @@
#include <ostream>
#include <opm/parser/eclipse/Deck/DeckOutput.hpp>
#include <opm/parser/eclipse/Deck/UDAValue.hpp>
namespace Opm {
@ -82,6 +83,14 @@ namespace Opm {
this->os << value;
}
template <>
void DeckOutput::write_value( const UDAValue& value ) {
if (value.is<double>())
this->write_value(value.get<double>());
else
this->write_value(value.get<std::string>());
}
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);
}

View File

@ -49,6 +49,7 @@ const std::string testHeader =
"auto unitSystem = UnitSystem::newMETRIC();\n";
const std::string sourceHeader =
"#include <opm/parser/eclipse/Deck/UDAValue.hpp>\n"
"#include <opm/parser/eclipse/Parser/ParserKeyword.hpp>\n"
"#include <opm/parser/eclipse/Parser/ParserItem.hpp>\n"
"#include <opm/parser/eclipse/Parser/ParserRecord.hpp>\n"

View File

@ -30,7 +30,7 @@
#include <opm/parser/eclipse/Parser/ParserEnums.hpp>
#include <opm/parser/eclipse/RawDeck/RawRecord.hpp>
#include <opm/parser/eclipse/RawDeck/StarToken.hpp>
#include <opm/parser/eclipse/Deck/UDAValue.hpp>
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<double>::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<UDAValue> 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.");
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<double>()) << ")";
break;
case type_tag::uda:
{
double double_value =this->getDefault<UDAValue>().get<double>();
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<UDAValue>(*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<UDAValue>().get<double>();
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;
}

View File

@ -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())

View File

@ -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<UDAValue>(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)));
}
}
}

View File

@ -28,6 +28,7 @@
#include <opm/parser/eclipse/RawDeck/StarToken.hpp>
#include <opm/parser/eclipse/Utility/Stringview.hpp>
#include <opm/parser/eclipse/Deck/UDAValue.hpp>
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<std::string>(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"...

View File

@ -978,8 +978,4 @@ BOOST_AUTO_TEST_CASE(UDA_VALUE) {
BOOST_CHECK(value2.is<std::string>());
BOOST_CHECK_EQUAL( value2.get<std::string>(), std::string("FUBHP"));
BOOST_CHECK_THROW( value2.get<double>(), std::invalid_argument);
std::vector<UDAValue> values;
values.resize(100, UDAValue(1000));
}