can parse keywords of type double-record.

...

ParserKeyword: bool double_records set.

added keywords CECONT.

ParserKeywords: double_records set by keyword generator.

Parsertests: added test for parsing double_records.

ParserKeywords.parse: if double_records returns empty.

double_records keywords set to SLASH_TERMINATED.

...

ParserKeyword: for double records size_type = DOUBLE_SLASH_TERMINATED.

double_records: RawKeyword is Raw::DOUBLE_SLASH_TERMINATED.

RawKeyword uses m_isTempFinished.

Parser: can parse files with double-record keywords.

Parser.cpp/RawRecord.cpp: removed comments.

DeckKeyword has param m_isDoubleRecordKeyword.

test ParseDoubleRecords: double records to have linear structure.

DeckKeyword: Can create records of type double_record.

double-records parser test transferred to ParserTests.cpp.

...

...
This commit is contained in:
Steinar Foss
2019-12-11 14:36:18 +01:00
parent a62d9df61f
commit 87bbc46bbb
13 changed files with 224 additions and 13 deletions

View File

@@ -58,7 +58,9 @@ namespace Opm {
DeckRecord& getRecord(size_t index);
const DeckRecord& getDataRecord() const;
void setDataKeyword(bool isDataKeyword = true);
void setDoubleRecordKeyword(bool isDoubleRecordKeyword = true);
bool isDataKeyword() const;
bool isDoubleRecordKeyword() const;
const std::vector<int>& getIntData() const;
const std::vector<double>& getRawDoubleData() const;
@@ -93,6 +95,7 @@ namespace Opm {
std::vector< DeckRecord > m_recordList;
bool m_isDataKeyword;
bool m_slashTerminated;
bool m_isDoubleRecordKeyword = false;
};
}

View File

@@ -29,7 +29,8 @@ namespace Opm {
FIXED = 1,
OTHER_KEYWORD_IN_DECK = 2,
UNKNOWN = 3,
FIXED_CODE = 4
FIXED_CODE = 4,
DOUBLE_SLASH_TERMINATED = 5
};

View File

@@ -131,7 +131,9 @@ namespace Opm {
bool rawStringKeyword() const;
bool isCodeKeyword() const;
bool isAlternatingKeyword() const;
bool isDoubleRecordKeyword() const;
void setAlternatingKeyword(bool alternating);
void setDoubleRecordsKeyword(bool double_rec);
std::string createDeclaration(const std::string& indent) const;
std::string createDecl() const;
@@ -154,6 +156,7 @@ namespace Opm {
std::string m_Description;
bool raw_string_keyword = false;
bool alternating_keyword = false;
bool double_records = false;
std::string code_end;
static bool validNameStart(const string_view& name);

View File

@@ -189,10 +189,18 @@ namespace Opm {
m_isDataKeyword = isDataKeyword_;
}
void DeckKeyword::setDoubleRecordKeyword(bool isDoubleRecordKeyword) {
m_isDoubleRecordKeyword = isDoubleRecordKeyword;
}
bool DeckKeyword::isDataKeyword() const {
return m_isDataKeyword;
}
bool DeckKeyword::isDoubleRecordKeyword() const {
return m_isDoubleRecordKeyword;
}
const std::string& DeckKeyword::name() const {
return m_keywordName;
}

View File

@@ -560,11 +560,16 @@ void ParserState::addPathAlias( const std::string& alias, const std::string& pat
RawKeyword * newRawKeyword(const ParserKeyword& parserKeyword, const std::string& keywordString, ParserState& parserState, const Parser& parser) {
bool raw_string_keyword = parserKeyword.rawStringKeyword();
if( parserKeyword.getSizeType() == SLASH_TERMINATED || parserKeyword.getSizeType() == UNKNOWN) {
if( parserKeyword.getSizeType() == SLASH_TERMINATED || parserKeyword.getSizeType() == UNKNOWN || parserKeyword.getSizeType() == DOUBLE_SLASH_TERMINATED) {
const auto rawSizeType = parserKeyword.getSizeType() == SLASH_TERMINATED
? Raw::SLASH_TERMINATED
: Raw::UNKNOWN;
const auto size_type = parserKeyword.getSizeType();
Raw::KeywordSizeEnum rawSizeType;
switch(size_type) {
case SLASH_TERMINATED: rawSizeType = Raw::SLASH_TERMINATED; break;
case UNKNOWN: rawSizeType = Raw::UNKNOWN; break;
case DOUBLE_SLASH_TERMINATED: rawSizeType = Raw::DOUBLE_SLASH_TERMINATED; break;
}
return new RawKeyword( keywordString,
parserState.current_path().string(),

View File

@@ -42,6 +42,9 @@ namespace Opm {
case FIXED_CODE:
return "FIXED_CODE";
break;
case DOUBLE_SLASH_TERMINATED:
return "DOUBLE_SLASH_TERMINATED";
break;
default:
throw std::invalid_argument("Implementation error - should NOT be here");
}

View File

@@ -140,6 +140,11 @@ namespace Opm {
return;
}
if (jsonConfig.has_item("records_set")) {
m_keywordSizeType = DOUBLE_SLASH_TERMINATED;
return;
}
if (jsonConfig.has_item("items") || jsonConfig.has_item("records")) {
// The number of records is undetermined - the keyword will be '/'
// terminated.
@@ -184,7 +189,9 @@ namespace Opm {
initSectionNames(jsonConfig);
initMatchRegex(jsonConfig);
if (jsonConfig.has_item("items") && (jsonConfig.has_item("records") || jsonConfig.has_item("alternating_records")))
if (jsonConfig.has_item("items") && (jsonConfig.has_item("records") ||
jsonConfig.has_item("alternating_records") ||
jsonConfig.has_item("records_set") ))
throw std::invalid_argument("Fatal error in " + getName() + " configuration. Can NOT have both records: and items:");
if (jsonConfig.has_item("items")) {
@@ -205,6 +212,12 @@ namespace Opm {
parseRecords( recordsConfig );
}
if (jsonConfig.has_item("records_set")) {
double_records = true;
const Json::JsonObject recordsConfig = jsonConfig.get_item("records_set");
parseRecords( recordsConfig );
}
if (jsonConfig.has_item("data"))
initData(jsonConfig);
@@ -523,19 +536,40 @@ void set_dimensions( ParserItem& item,
UnitSystem& active_unitsystem,
UnitSystem& default_unitsystem,
const std::string& filename) const {
if( !rawKeyword.isFinished() )
throw std::invalid_argument("Tried to create a deck keyword from an incomplete raw keyword " + rawKeyword.getKeywordName());
DeckKeyword keyword( rawKeyword.location(), rawKeyword.getKeywordName() );
keyword.setDataKeyword( isDataKeyword() );
size_t record_nr = 0;
for( auto& rawRecord : rawKeyword ) {
if( m_records.size() == 0 && rawRecord.size() > 0 )
throw std::invalid_argument("Missing item information " + rawKeyword.getKeywordName());
if (double_records)
keyword.setDoubleRecordKeyword();
keyword.addRecord( this->getRecord( record_nr ).parse( parseContext, errors, rawRecord, active_unitsystem, default_unitsystem, rawKeyword.getKeywordName(), filename ) );
record_nr++;
if (double_records) {
/* Note: this merely dumps all records sequentially into m_recordList.
In order to actually use double-record keywords, DeckKeyword needs to have a
2-dimensional DeckRecord structure, e.g.
std::vector< std::vector<DeckRecord >> m_recordList; */
size_t record_nr = 0;
for (auto& rawRecord : rawKeyword) {
if (rawRecord.size() == 0)
record_nr = 0;
else {
keyword.addRecord( this->getRecord( record_nr ).parse( parseContext, errors, rawRecord, active_unitsystem, default_unitsystem, rawKeyword.getKeywordName(), filename ) );
record_nr++;
}
}
}
else {
size_t record_nr = 0;
for( auto& rawRecord : rawKeyword ) {
if( m_records.size() == 0 && rawRecord.size() > 0 )
throw std::invalid_argument("Missing item information " + rawKeyword.getKeywordName());
keyword.addRecord( this->getRecord( record_nr ).parse( parseContext, errors, rawRecord, active_unitsystem, default_unitsystem, rawKeyword.getKeywordName(), filename ) );
record_nr++;
}
}
if (this->hasFixedSize( ))
@@ -588,10 +622,18 @@ void set_dimensions( ParserItem& item,
return alternating_keyword;
}
bool ParserKeyword::isDoubleRecordKeyword() const {
return double_records;
}
void ParserKeyword::setAlternatingKeyword(bool alternating) {
alternating_keyword = alternating;
}
void ParserKeyword::setDoubleRecordsKeyword(bool double_rec) {
double_records = double_rec;
}
bool ParserKeyword::hasMatchRegex() const {
return !m_matchRegexString.empty();
}
@@ -662,6 +704,7 @@ void set_dimensions( ParserItem& item,
switch (m_keywordSizeType) {
case SLASH_TERMINATED:
case FIXED_CODE:
case DOUBLE_SLASH_TERMINATED:
case UNKNOWN:
ss << "setSizeType(" << sizeString << ");" << '\n';
break;
@@ -698,6 +741,10 @@ void set_dimensions( ParserItem& item,
if (alternating_keyword)
ss << indent << "setAlternatingKeyword(true);" << '\n';
// set DoubleRecords
if (double_records)
ss << indent << "setDoubleRecordsKeyword(true);" << '\n';
// set the deck name match regex
if (hasMatchRegex())
ss << indent << "setMatchRegex(\"" << m_matchRegexString << "\");" << '\n';

View File

@@ -30,6 +30,7 @@ namespace Opm {
UNKNOWN = 3,
TABLE_COLLECTION = 4,
CODE = 5,
DOUBLE_SLASH_TERMINATED = 6
};
}
}

View File

@@ -96,6 +96,13 @@ namespace {
if (this->m_sizeType == Raw::SLASH_TERMINATED)
this->m_isFinished = true;
if (this->m_sizeType == Raw::DOUBLE_SLASH_TERMINATED) {
if (m_isTempFinished)
this->m_isFinished = true;
else
this->m_isTempFinished = true;
}
if (m_sizeType == Raw::TABLE_COLLECTION) {
m_currentNumTables += 1;
if (m_currentNumTables == m_numTables)
@@ -110,12 +117,15 @@ namespace {
bool RawKeyword::addRecord(RawRecord record) {
if (record.size() > 0)
m_isTempFinished = false;
this->m_records.push_back(std::move(record));
if (m_records.size() == this->m_fixedSize) {
if( this->m_sizeType == Raw::FIXED || this->m_sizeType == Raw::CODE)
this->m_isFinished = true;
}
return this->m_isFinished;
}

View File

@@ -71,6 +71,7 @@ namespace Opm {
size_t m_fixedSize = 0;
size_t m_numTables = 0;
size_t m_currentNumTables = 0;
bool m_isTempFinished = false;
bool m_isFinished = false;
std::vector< RawRecord > m_records;

View File

@@ -0,0 +1,22 @@
{
"name" : "CECONT", "sections" : ["SCHEDULE"], "records_set" : [
[
{"name" : "WELL", "value_type" : "STRING"},
{"name" : "I", "value_type" : "INT", "default" : 0},
{"name" : "J", "value_type" : "INT", "default" : 0},
{"name" : "K_UPPER", "value_type" : "INT", "default" : 0},
{"name" : "K_LOWER", "value_type" : "INT", "default" : 0},
{"name" : "PROCEDURE", "value_type" : "STRING", "default" : "CON"},
{"name" : "CHECK_STOPPED_WELLS", "value_type" : "STRING", "default" : "NO"}
],
[
{"name" : "TRACER", "value_type" : "STRING"},
{"name" : "MAX_TOTAL_TRACER_RATE", "value_type" : "DOUBLE", "default" : 1e200},
{"name" : "MAX_TOTAL_TRACER_CONC", "value_type" : "DOUBLE", "default" : 1e200},
{"name" : "MAX_FREE_TRACER_RATE", "value_type" : "DOUBLE", "default" : 1e200},
{"name" : "MAX_FREE_TRACER_CONC", "value_type" : "DOUBLE", "default" : 1e200},
{"name" : "MAX_SOL_TRACER_RATE", "value_type" : "DOUBLE", "default" : 1e200},
{"name" : "MAX_SOL_TRACER_CONC", "value_type" : "DOUBLE", "default" : 1e200}
]
]
}

View File

@@ -79,6 +79,7 @@ set( keywords
000_Eclipse100/C/CART
000_Eclipse100/C/CBMOPTS
000_Eclipse100/C/CECON
000_Eclipse100/C/CECONT
000_Eclipse100/C/COAL
000_Eclipse100/C/COALADS
000_Eclipse100/C/COALNUM

View File

@@ -1774,6 +1774,38 @@ BOOST_AUTO_TEST_CASE(GetAlternatingKeywordFromParser) {
BOOST_CHECK(kw.getRecord(13) == record1);
}
BOOST_AUTO_TEST_CASE(ConstructFromJson_withDoubleRecords) {
const std::string json_string = R"(
{"name" : "CECONT", "sections" : ["PROPS"] , "records_set" : [[
{"name" : "WELL", "value_type" : "STRING"},
{"name" : "I", "value_type" : "INT"},
{"name" : "J", "value_type" : "INT"},
{"name" : "K", "value_type" : "INT"}], [
{"name" : "TRACER" , "value_type" : "STRING"},
{"name" : "rate", "value_type" : "DOUBLE"}]]}
)";
Json::JsonObject jsonObject( json_string );
ParserKeyword kw( jsonObject );
BOOST_CHECK( kw.isDoubleRecordKeyword() );
BOOST_CHECK_EQUAL(kw.getRecord(0).size(), 4);
BOOST_CHECK_EQUAL(kw.getRecord(1).size(), 2);
}
BOOST_AUTO_TEST_CASE(GetDoubleRecordKeywordFromParser) {
Parser parser;
BOOST_CHECK(parser.hasKeyword("CECONT"));
ParserKeyword kw = parser.getKeyword("CECONT");
BOOST_CHECK(kw.isDoubleRecordKeyword());
BOOST_CHECK(kw.getSizeType() == DOUBLE_SLASH_TERMINATED);
auto record0 = kw.getRecord(0);
auto record1 = kw.getRecord(1);
BOOST_CHECK_EQUAL(record0.get(0).name(), "WELL");
BOOST_CHECK_EQUAL(record1.get(0).name(), "TRACER");
BOOST_CHECK(kw.getRecord(11) == record1);
BOOST_CHECK(kw.getRecord(13) == record1);
}
BOOST_AUTO_TEST_CASE(Create1Arg) {
ParserKeyword kw("GRID");
@@ -2136,4 +2168,78 @@ DENSITY
}
}
BOOST_AUTO_TEST_CASE(ParseDoubleRecords) {
const auto deck_string = std::string { R"(
RUNSPEC
FIELD
TABDIMS
1* 2
/
PROPS
DENSITY
50.91 62.4 /
51.90 64.2 /
SCHEDULE
CECONT
PROD1 4* CON NO /
TR1 1000.0 0.5 /
TR2 2* 1* 0.8 2* /
TR3 1500.0 0.1 /
/
PROD2 5 6 3 3 CON+ NO /
TR3 100.0 0.05 /
/
PROD3 6* /
TR4 200 5* /
PLY 1* 0.7 /
/
/
GCONSUMP
PLAT-A 20 50 /
PLAT-B 15 /
/
)" };
Parser parser;
auto deck = parser.parseString(deck_string);
BOOST_CHECK( deck.hasKeyword("CECONT") );
BOOST_CHECK( deck.hasKeyword("GCONSUMP") );
auto kw_density = deck.getKeyword("DENSITY");
auto kw = deck.getKeyword("CECONT");
BOOST_CHECK( kw.isDoubleRecordKeyword() );
auto record00 = kw.getRecord(0);
BOOST_CHECK_EQUAL(record00.getItem(0).name(), "WELL");
BOOST_CHECK_EQUAL(record00.getItem(0).get<std::string>(0), "PROD1");
BOOST_CHECK(record00.getItem(1).getType() == type_tag::integer);
BOOST_CHECK_EQUAL(record00.getItem(1).get<int>(0), 0);
auto record01 = kw.getRecord(1);
BOOST_CHECK_EQUAL(record01.getItem(0).name(), "TRACER");
BOOST_CHECK_EQUAL(record01.getItem(0).get<std::string>(0), "TR1");
BOOST_CHECK(record01.getItem(1).getType() == type_tag::fdouble);
BOOST_CHECK_EQUAL(record01.getItem(1).get<double>(0), 1000);
auto record04 = kw.getRecord(4);
BOOST_CHECK_EQUAL(record04.getItem(0).name(), "WELL");
BOOST_CHECK_EQUAL(record04.getItem(0).get<std::string>(0), "PROD2");
BOOST_CHECK(record04.getItem(1).getType() == type_tag::integer);
BOOST_CHECK_EQUAL(record04.getItem(1).get<int>(0), 5);
auto record08 = kw.getRecord(8);
BOOST_CHECK_EQUAL(record08.getItem(0).name(), "TRACER");
BOOST_CHECK_EQUAL(record08.getItem(0).get<std::string>(0), "PLY");
BOOST_CHECK(record08.getItem(2).getType() == type_tag::fdouble);
BOOST_CHECK_EQUAL(record08.getItem(2).get<double>(0), 0.7);
}