#2066 Observed Data : Major rewrite of varying column width parsing

Add TableInfo to hold a table with several ColumnInfo objects
Improved detection of RifEclipseSummaryAddress from all variants
This commit is contained in:
Magne Sjaastad
2017-11-02 19:00:27 +01:00
parent 02cd42aa54
commit fee00918e9
14 changed files with 1146 additions and 495 deletions

View File

@@ -36,6 +36,7 @@ ${CEE_CURRENT_LIST_DIR}RifColumnBasedUserData.h
${CEE_CURRENT_LIST_DIR}RifKeywordVectorUserData.h
${CEE_CURRENT_LIST_DIR}RifWellRftAddress.h
${CEE_CURRENT_LIST_DIR}RifWellRftAddressQMetaType.h
${CEE_CURRENT_LIST_DIR}RifEclipseUserDataKeywordTools.h
# HDF5 file reader is directly included in ResInsight main CmakeList.txt
#${CEE_CURRENT_LIST_DIR}RifHdf5Reader.h
@@ -77,6 +78,7 @@ ${CEE_CURRENT_LIST_DIR}RifHdf5ReaderInterface.cpp
${CEE_CURRENT_LIST_DIR}RifColumnBasedUserData.cpp
${CEE_CURRENT_LIST_DIR}RifKeywordVectorUserData.cpp
${CEE_CURRENT_LIST_DIR}RifWellRftAddress.cpp
${CEE_CURRENT_LIST_DIR}RifEclipseUserDataKeywordTools.cpp
# HDF5 file reader is directly included in ResInsight main CmakeList.txt

View File

@@ -18,10 +18,12 @@
#include "RifColumnBasedUserData.h"
#include "RiaQDateTimeTools.h"
#include "RiaDateStringParser.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "RifColumnBasedUserDataParser.h"
#include "RifEclipseUserDataKeywordTools.h"
#include "RifEclipseUserDataParserTools.h"
#include "cafUtils.h"
@@ -64,130 +66,7 @@ bool RifColumnBasedUserData::parse(const QString& data, const QString& customWel
return false;
}
for (size_t tableIndex = 0; tableIndex < m_parser->tables().size(); tableIndex++)
{
// Find time index
size_t dateColumnIndex = m_parser->tables()[tableIndex].size();
size_t dayOrYearColumnIndex = m_parser->tables()[tableIndex].size();
for (size_t columIndex = 0; columIndex < m_parser->tables()[tableIndex].size(); columIndex++)
{
const ColumnInfo& ci = m_parser->tables()[tableIndex][columIndex];
if (!ci.isAVector)
{
QString unit = QString::fromStdString(ci.unitName).trimmed().toUpper();
if (unit == "DATE" ||
unit == "DATES")
{
dateColumnIndex = columIndex;
}
else if (unit == "DAY" ||
unit == "DAYS" ||
unit == "YEAR" ||
unit == "YEARS")
{
dayOrYearColumnIndex = columIndex;
break;
}
}
}
size_t timeColumnIndex = m_parser->tables()[tableIndex].size();
if (dayOrYearColumnIndex < m_parser->tables()[tableIndex].size())
{
timeColumnIndex = dayOrYearColumnIndex;
}
else if (dateColumnIndex < m_parser->tables()[tableIndex].size())
{
timeColumnIndex = dateColumnIndex;
}
if (timeColumnIndex == m_parser->tables()[tableIndex].size())
{
RiaLogging::warning(QString("Failed to find time data for table %1 in file %2").arg(tableIndex));
RiaLogging::warning(QString("No data for this table is imported"));
}
else
{
m_timeSteps.resize(m_timeSteps.size() + 1);
std::vector<time_t>& timeSteps = m_timeSteps.back();
const ColumnInfo& ci = m_parser->tables()[tableIndex][timeColumnIndex];
if (timeColumnIndex == dateColumnIndex)
{
for (const auto& timeStepValue : ci.observationDateTimes)
{
timeSteps.push_back(timeStepValue.toTime_t());
}
}
else
{
QDateTime startDate;
if (ci.startQDateTime.isValid())
{
startDate = ci.startQDateTime;
}
else
{
QString startDateString = QString::fromStdString(ci.startDateString);
if (!startDateString.isEmpty())
{
QString dateFormatString = "ddMMyyyy";
startDate = RiaQDateTimeTools::fromString(startDateString, dateFormatString);
}
else
{
startDate = RiaQDateTimeTools::epoch();
}
}
QString unit = QString::fromStdString(ci.unitName).trimmed().toUpper();
if (unit == "DAY" || unit == "DAYS")
{
for (const auto& timeStepValue : ci.values)
{
QDateTime dateTime = RiaQDateTimeTools::addDays(startDate, timeStepValue);
timeSteps.push_back(dateTime.toTime_t());
}
}
else if (unit == "YEAR" || unit == "YEARS")
{
for (const auto& timeStepValue : ci.values)
{
QDateTime dateTime = RiaQDateTimeTools::addYears(startDate, timeStepValue);
timeSteps.push_back(dateTime.toTime_t());
}
}
}
for (size_t columIndex = 0; columIndex < m_parser->tables()[tableIndex].size(); columIndex++)
{
const ColumnInfo& ci = m_parser->tables()[tableIndex][columIndex];
if (ci.isAVector)
{
RifEclipseSummaryAddress sumAddress = ci.summaryAddress;
if (customWellName.size() > 0)
{
sumAddress.setWellName(customWellName.toStdString());
}
if (customWellGroupName.size() > 0)
{
sumAddress.setWellGroupName(customWellGroupName.toStdString());
}
m_allResultAddresses.push_back(sumAddress);
m_mapFromAddressToTimeStepIndex[sumAddress] = m_timeSteps.size() - 1;
m_mapFromAddressToResultIndex[sumAddress] = std::make_pair(tableIndex, columIndex);
}
}
}
}
buildTimeStepsFromTables();
return true;
@@ -203,8 +82,10 @@ bool RifColumnBasedUserData::values(const RifEclipseSummaryAddress& resultAddres
{
std::pair<size_t, size_t> tableColIndices = search->second;
const ColumnInfo& ci = m_parser->tables()[tableColIndices.first][tableColIndices.second];
for (const auto& v : ci.values)
const ColumnInfo* ci = m_parser->columnInfo(tableColIndices.first, tableColIndices.second);
if (!ci) return false;
for (const auto& v : ci->values)
{
values->push_back(v);
}
@@ -239,10 +120,119 @@ std::string RifColumnBasedUserData::unitName(const RifEclipseSummaryAddress& res
{
std::pair<size_t, size_t> tableColIndices = search->second;
const ColumnInfo& ci = m_parser->tables()[tableColIndices.first][tableColIndices.second];
return ci.unitName;
const ColumnInfo* ci = m_parser->columnInfo(tableColIndices.first, tableColIndices.second);
if (ci)
{
return ci->unitName;
}
}
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifColumnBasedUserData::buildTimeStepsFromTables()
{
for (size_t tableIndex = 0; tableIndex < m_parser->tableData().size(); tableIndex++)
{
auto tableData = m_parser->tableData()[tableIndex];
// Find time index
size_t dateColumnIndex = tableData.columnInfos().size();
size_t dayOrYearColumnIndex = tableData.columnInfos().size();
for (size_t columIndex = 0; columIndex < tableData.columnInfos().size(); columIndex++)
{
const ColumnInfo& ci = tableData.columnInfos()[columIndex];
if (dateColumnIndex == tableData.columnInfos().size() &&
RifEclipseUserDataKeywordTools::isDate(ci.summaryAddress.quantityName()))
{
dateColumnIndex = columIndex;
}
else if (dayOrYearColumnIndex == tableData.columnInfos().size() &&
RifEclipseUserDataParserTools::hasTimeUnit(ci.unitName))
{
dayOrYearColumnIndex = columIndex;
}
}
if (dateColumnIndex == tableData.columnInfos().size() &&
dayOrYearColumnIndex == tableData.columnInfos().size())
{
RiaLogging::warning(QString("Failed to find time data for table %1 in file %2").arg(tableIndex));
RiaLogging::warning(QString("No data for this table is imported"));
}
else
{
m_timeSteps.resize(m_timeSteps.size() + 1);
std::vector<time_t>& timeSteps = m_timeSteps.back();
if (dateColumnIndex != tableData.columnInfos().size())
{
const ColumnInfo& ci = tableData.columnInfos()[dateColumnIndex];
QString dateFormat;
for (auto s : ci.stringValues)
{
QDateTime dt = RiaDateStringParser::parseDateString(s);
timeSteps.push_back(dt.toTime_t());
}
}
else
{
QDateTime startDate = RiaQDateTimeTools::epoch();
if (!tableData.startDate().empty())
{
QDateTime candidate = RiaDateStringParser::parseDateString(tableData.startDate());
if (candidate.isValid())
{
startDate = candidate;
}
}
if (dayOrYearColumnIndex != tableData.columnInfos().size())
{
const ColumnInfo& ci = tableData.columnInfos()[dayOrYearColumnIndex];
QString unit = QString::fromStdString(ci.unitName).trimmed().toUpper();
if (unit == "DAY" || unit == "DAYS")
{
for (const auto& timeStepValue : ci.values)
{
QDateTime dateTime = RiaQDateTimeTools::addDays(startDate, timeStepValue);
timeSteps.push_back(dateTime.toTime_t());
}
}
else if (unit == "YEAR" || unit == "YEARS")
{
for (const auto& timeStepValue : ci.values)
{
QDateTime dateTime = RiaQDateTimeTools::addYears(startDate, timeStepValue);
timeSteps.push_back(dateTime.toTime_t());
}
}
}
}
for (size_t columIndex = 0; columIndex < tableData.columnInfos().size(); columIndex++)
{
const ColumnInfo& ci = tableData.columnInfos()[columIndex];
if (!ci.isStringData)
{
RifEclipseSummaryAddress sumAddress = ci.summaryAddress;
m_allResultAddresses.push_back(sumAddress);
m_mapFromAddressToTimeStepIndex[sumAddress] = m_timeSteps.size() - 1;
m_mapFromAddressToResultIndex[sumAddress] = std::make_pair(tableIndex, columIndex);
}
}
}
}
}

View File

@@ -49,6 +49,9 @@ public:
std::string unitName(const RifEclipseSummaryAddress& resultAddress) const override;
private:
void buildTimeStepsFromTables();
private:
std::unique_ptr<RifColumnBasedUserDataParser> m_parser;
std::vector< std::vector<time_t> > m_timeSteps;

View File

@@ -35,85 +35,71 @@
//--------------------------------------------------------------------------------------------------
RifColumnBasedUserDataParser::RifColumnBasedUserDataParser(const QString& data)
{
parseData(data);
parseTableData(data);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector< std::vector<ColumnInfo> >& RifColumnBasedUserDataParser::tables() const
const std::vector<TableData>& RifColumnBasedUserDataParser::tableData() const
{
return m_tables;
return m_tableDatas;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const ColumnInfo* RifColumnBasedUserDataParser::columnInfo(size_t tableIndex, size_t columnIndex) const
{
if (tableIndex >= m_tableDatas.size()) return nullptr;
if (columnIndex >= m_tableDatas[tableIndex].columnInfos().size()) return nullptr;
return &(m_tableDatas[tableIndex].columnInfos()[columnIndex]);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifColumnBasedUserDataParser::parseData(const QString& data)
void RifColumnBasedUserDataParser::parseTableData(const QString& data)
{
std::stringstream streamData;
streamData.str(data.toStdString());
do
do
{
std::vector<ColumnInfo> table = RifEclipseUserDataParserTools::columnInfoForTable(streamData);
size_t columnCount = table.size();
auto table = RifEclipseUserDataParserTools::tableDataFromText(streamData);
std::vector<ColumnInfo>& columnInfos = table.columnInfos();
int columnCount = static_cast<int>(columnInfos.size());
if (columnCount == 0) break;
std::string line;
std::getline(streamData, line);
size_t dateColumnIndex = table.size();
for (size_t i = 0; i < columnCount; i++)
{
if (table[i].summaryAddress.quantityName() == "DATE" ||
table[i].summaryAddress.quantityName() == "DATES")
{
dateColumnIndex = i;
}
}
// If a DATE column is present, use the first date as the start date of the samples
// This date is then used as basis for times defined by days or years given as double values
QDateTime startDate;
std::vector<double> values;
QString qLine;
do
{
qLine = QString::fromStdString(line);
QString qLine = QString::fromStdString(line);
QStringList entries = qLine.split(" ", QString::SkipEmptyParts);
if (entries.size() < static_cast<int>(columnCount)) break;
if (entries.size() < columnCount) break;
for (size_t i = 0; i < columnCount; i++)
for (int i = 0; i < columnCount; i++)
{
if (dateColumnIndex < columnCount)
if (columnInfos[i].isStringData)
{
QDateTime observationDate = RiaDateStringParser::parseDateString(entries[static_cast<int>(dateColumnIndex)]);
if (observationDate.isValid() && !startDate.isValid())
{
startDate = observationDate;
}
table[i].observationDateTimes.push_back(observationDate);
columnInfos[i].stringValues.push_back(entries[i].toStdString());
}
else
{
double entry = entries[i].toDouble();
columnInfos[i].values.push_back(entry);
}
double entry = entries.at(static_cast<int>(i)).toDouble();
table[i].values.push_back(entry);
}
} while (std::getline(streamData, line));
if (startDate.isValid())
{
for (auto& ci : table)
{
ci.startQDateTime = startDate;
}
}
m_tables.push_back(table);
m_tableDatas.push_back(table);
} while (streamData.good());
}

View File

@@ -24,7 +24,8 @@
#include <vector>
struct ColumnInfo;
class ColumnInfo;
class TableData;
//==================================================================================================
///
@@ -33,11 +34,13 @@ class RifColumnBasedUserDataParser
{
public:
RifColumnBasedUserDataParser(const QString& data);
const std::vector< std::vector<ColumnInfo> >& tables() const;
const std::vector<TableData>& tableData() const;
const ColumnInfo* columnInfo(size_t tableIndex, size_t columnIndex) const;
private:
void parseData(const QString& data);
void parseTableData(const QString& data);
private:
std::vector< std::vector<ColumnInfo> > m_tables;
std::vector<TableData> m_tableDatas;
};

View File

@@ -115,6 +115,18 @@ RifEclipseSummaryAddress RifEclipseSummaryAddress::calculatedCurveAddress(const
return fieldAddr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress RifEclipseSummaryAddress::miscAddress(const std::string& quantityName)
{
RifEclipseSummaryAddress fieldAddr;
fieldAddr.m_variableCategory = SUMMARY_MISC;
fieldAddr.m_quantityName = quantityName;
return fieldAddr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@@ -106,6 +106,7 @@ public:
static RifEclipseSummaryAddress fieldVarAddress(const std::string& fieldVarName);
static RifEclipseSummaryAddress calculatedCurveAddress(const std::string& curveName);
static RifEclipseSummaryAddress miscAddress(const std::string& quantityName);
// Access methods

View File

@@ -0,0 +1,248 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RifEclipseUserDataKeywordTools.h"
#include "RiaLogging.h"
#include "RifEclipseUserDataParserTools.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<size_t> RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(const std::string& identifier)
{
if (identifier.size() < 2) return {};
char firstLetter = identifier[0];
switch (firstLetter)
{
case 'B': return { 3 }; // Block triplet
case 'C': return { 1, 3 }; // Well Name and completion triplet
case 'G': return { 1 }; // Group
case 'R': return { 1 }; // Region number
case 'S': return { 1, 1 }; // Well name and segment number
case 'W': return { 1 }; // Well Name
}
std::string firstTwoLetters = identifier.substr(0, 2);
if (firstTwoLetters == "LB") return { 1, 3 }; // LGR name and block triplet
else if (firstTwoLetters == "LC") return { 1, 1, 3 }; // LGR name, well name and block triplet
else if (firstTwoLetters == "LW") return { 1, 1 }; // LGR name and well name
return { };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<std::string>> RifEclipseUserDataKeywordTools::buildColumnHeaderText(const std::vector<std::string>& quantityNames,
const std::vector<std::vector<std::string>>& restOfHeaderRows,
std::vector<std::string>* errorText)
{
std::vector<std::vector<std::string>> tableHeaderText;
std::vector<size_t> headerLineWordIndices(restOfHeaderRows.size(), 0);
for (size_t i = 0; i < quantityNames.size(); i++)
{
std::vector<std::string> columnHeaderText;
auto quantityName = quantityNames[i];
columnHeaderText.push_back(quantityName);
auto itemCountPerLine = RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(quantityName);
if (itemCountPerLine.size() > restOfHeaderRows.size())
{
std::string text = "Detected too few header lines";
if (errorText) errorText->push_back(text);
return std::vector<std::vector<std::string>>();
}
for (size_t lineIdx = 0; lineIdx < itemCountPerLine.size(); lineIdx++)
{
auto line = restOfHeaderRows[lineIdx];
for (size_t itemIndex = 0; itemIndex < itemCountPerLine[lineIdx]; itemIndex++)
{
size_t wordIndex = headerLineWordIndices[lineIdx];
if (wordIndex >= line.size())
{
std::string text = "Detected too few items for header line";
if (errorText) errorText->push_back(text);
return std::vector<std::vector<std::string>>();
}
auto word = line[wordIndex];
columnHeaderText.push_back(word);
headerLineWordIndices[lineIdx]++;
}
}
tableHeaderText.push_back(columnHeaderText);
}
return tableHeaderText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataKeywordTools::isDate(const std::string& identifier)
{
if (identifier.find("DATE") != std::string::npos) return true;
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress RifEclipseUserDataKeywordTools::makeAndFillAddress(const std::string quantityName, const std::vector<std::string>& columnHeaderText)
{
RifEclipseSummaryAddress::SummaryVarCategory category = RifEclipseUserDataParserTools::identifyCategory(quantityName);
if (category == RifEclipseSummaryAddress::SUMMARY_INVALID)
{
return RifEclipseSummaryAddress::miscAddress(quantityName);
}
int regionNumber = -1;
int regionNumber2 = -1;
std::string wellGroupName = "";
std::string wellName = "";
int wellSegmentNumber = -1;
std::string lgrName = "";
int cellI = -1;
int cellJ = -1;
int cellK = -1;
switch (category)
{
case RifEclipseSummaryAddress::SUMMARY_FIELD:
break;
case RifEclipseSummaryAddress::SUMMARY_AQUIFER:
break;
case RifEclipseSummaryAddress::SUMMARY_NETWORK:
break;
case RifEclipseSummaryAddress::SUMMARY_MISC:
break;
case RifEclipseSummaryAddress::SUMMARY_REGION:
{
if (columnHeaderText.size() > 0)
{
regionNumber = std::stoi(columnHeaderText[0]);
}
break;
}
case RifEclipseSummaryAddress::SUMMARY_REGION_2_REGION:
break;
case RifEclipseSummaryAddress::SUMMARY_WELL_GROUP:
{
if (columnHeaderText.size() > 0)
{
wellGroupName = columnHeaderText[0];
}
break;
}
case RifEclipseSummaryAddress::SUMMARY_WELL:
{
if (columnHeaderText.size() > 0)
{
wellName = columnHeaderText[0];
}
break;
}
case RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION:
{
if (columnHeaderText.size() > 3)
{
wellName = columnHeaderText[0];
cellI = std::stoi(columnHeaderText[1]);
cellJ = std::stoi(columnHeaderText[2]);
cellK = std::stoi(columnHeaderText[3]);
}
break;
}
break;
case RifEclipseSummaryAddress::SUMMARY_WELL_LGR:
if (columnHeaderText.size() > 1)
{
wellName = columnHeaderText[0];
lgrName = columnHeaderText[1];
}
break;
case RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION_LGR:
if (columnHeaderText.size() > 4)
{
wellName = columnHeaderText[0];
lgrName = columnHeaderText[1];
cellI = std::stoi(columnHeaderText[2]);
cellJ = std::stoi(columnHeaderText[3]);
cellK = std::stoi(columnHeaderText[4]);
}
break;
case RifEclipseSummaryAddress::SUMMARY_WELL_SEGMENT:
if (columnHeaderText.size() > 1)
{
wellName = columnHeaderText[0];
wellSegmentNumber = std::stoi(columnHeaderText[1]);
}
break;
case RifEclipseSummaryAddress::SUMMARY_BLOCK:
if (columnHeaderText.size() > 2)
{
cellI = std::stoi(columnHeaderText[0]);
cellJ = std::stoi(columnHeaderText[1]);
cellK = std::stoi(columnHeaderText[2]);
}
break;
case RifEclipseSummaryAddress::SUMMARY_BLOCK_LGR:
if (columnHeaderText.size() > 3)
{
lgrName = columnHeaderText[0];
cellI = std::stoi(columnHeaderText[1]);
cellJ = std::stoi(columnHeaderText[2]);
cellK = std::stoi(columnHeaderText[3]);
}
break;
case RifEclipseSummaryAddress::SUMMARY_CALCULATED:
break;
default:
break;
}
return RifEclipseSummaryAddress(category,
quantityName,
regionNumber,
regionNumber2,
wellGroupName,
wellName,
wellSegmentNumber,
lgrName,
cellI,
cellJ,
cellK);
}

View File

@@ -0,0 +1,42 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2017- Statoil ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RifEclipseUserDataParserTools.h"
#include <vector>
#include <string>
//==================================================================================================
///
//==================================================================================================
class RifEclipseUserDataKeywordTools
{
public:
static std::vector<size_t> requiredItemsPerLineForKeyword(const std::string& identifier);
static std::vector<std::vector<std::string>> buildColumnHeaderText(const std::vector<std::string>& quantityNames,
const std::vector<std::vector<std::string>>& restOfHeaderRows,
std::vector<std::string>* errorText = nullptr);
static bool isDate(const std::string& identifier);
static RifEclipseSummaryAddress makeAndFillAddress(const std::string quantityName, const std::vector<std::string>& columnHeaderText);
};

View File

@@ -18,8 +18,11 @@
#include "RifEclipseUserDataParserTools.h"
#include "RiaDateStringParser.h"
#include "RiaLogging.h"
#include "RifEclipseUserDataKeywordTools.h"
#include "cvfAssert.h"
#include <QString>
@@ -80,7 +83,7 @@ bool RifEclipseUserDataParserTools::isLineSkippable(const std::string& line)
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::isAComment(const std::string& word)
{
if (word.size() > 1 && word.substr(0, 2) == "--")
if (word.find("--") != std::string::npos)
{
return true;
}
@@ -161,77 +164,6 @@ size_t RifEclipseUserDataParserTools::findFirstNonEmptyEntryIndex(std::vector<st
return list.size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseSummaryAddress RifEclipseUserDataParserTools::makeAndFillAddress(std::string quantityName, std::vector< std::string > headerColumn)
{
int regionNumber = -1;
int regionNumber2 = -1;
std::string wellGroupName = "";
std::string wellName = "";
int wellSegmentNumber = -1;
std::string lgrName = "";
int cellI = -1;
int cellJ = -1;
int cellK = -1;
RifEclipseSummaryAddress::SummaryVarCategory category = identifyCategory(quantityName);
switch (category) //TODO: More categories
{
case (RifEclipseSummaryAddress::SUMMARY_INVALID):
{
break;
}
case (RifEclipseSummaryAddress::SUMMARY_WELL):
{
size_t index = findFirstNonEmptyEntryIndex(headerColumn);
if (index < headerColumn.size())
{
wellName = headerColumn[index];
}
break;
}
case (RifEclipseSummaryAddress::SUMMARY_WELL_GROUP):
{
size_t index = findFirstNonEmptyEntryIndex(headerColumn);
if (index < headerColumn.size())
{
wellGroupName = headerColumn[index];
}
break;
}
case (RifEclipseSummaryAddress::SUMMARY_REGION):
{
size_t index = findFirstNonEmptyEntryIndex(headerColumn);
if (index < headerColumn.size())
{
try
{
regionNumber = std::stoi(headerColumn[index]);
}
catch (...){}
}
break;
}
default:
break;
}
return RifEclipseSummaryAddress(category,
quantityName,
regionNumber,
regionNumber2,
wellGroupName,
wellName,
wellSegmentNumber,
lgrName,
cellI,
cellJ,
cellK);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -248,7 +180,19 @@ bool RifEclipseUserDataParserTools::keywordParser(const std::string& line, std::
else if (words[0] == "STARTDATE")
{
words.erase(words.begin());
startDate = std::accumulate(words.begin(), words.end(), std::string(""));
for (size_t i = 0; i < words.size(); i++)
{
std::string s = words[i];
startDate += s;
if (i < words.size() - 1)
{
startDate += " ";
}
}
return true;
}
else if (words[0] == "DATEFORMAT")
@@ -259,162 +203,6 @@ bool RifEclipseUserDataParserTools::keywordParser(const std::string& line, std::
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<ColumnInfo> RifEclipseUserDataParserTools::columnInfoForTable(std::stringstream& streamData)
{
std::vector<ColumnInfo> table;
std::string origin = "";
std::string dateFormat = "";
std::string startDate = "";
std::string line;
std::getline(streamData, line);
while (isLineSkippable(line) || keywordParser(line, origin, dateFormat, startDate))
{
if (!streamData.good()) return table;
std::getline(streamData, line);
}
std::vector<std::string> quantityNames = splitLineAndRemoveComments(line);
size_t columnCount = quantityNames.size();
std::vector< std::vector< std::string > > allHeaderRows;
{
std::stringstream::pos_type posAtStartOfLine = streamData.tellg();
std::string secondLine;
std::getline(streamData, line);
std::stringstream::pos_type posAtStartOfSecondLine = streamData.tellg();
std::getline(streamData, secondLine);
bool header = true;
while (header)
{
std::vector<std::string> words = splitLineAndRemoveComments(line);
std::vector<std::string> wordsSecondLine = splitLineAndRemoveComments(secondLine);
if (words.size() == columnCount &&
wordsSecondLine.size() == columnCount &&
hasOnlyValidDoubleValues(words) &&
hasOnlyValidDoubleValues(wordsSecondLine))
{
header = false;
break;
}
else
{
if (words.size() > columnCount) break;
size_t diff = columnCount - words.size();
if (diff == columnCount)
{
std::vector< std::string > vectorOfEmptyStrings(columnCount, "");
allHeaderRows.push_back(vectorOfEmptyStrings);
}
else
{
words.insert(words.begin(), diff, "");
allHeaderRows.push_back(words);
}
}
posAtStartOfLine = posAtStartOfSecondLine;
line = secondLine;
posAtStartOfSecondLine = streamData.tellg();
std::getline(streamData, secondLine);
}
streamData.seekg(posAtStartOfLine);
}
std::vector<std::string> unitNames;
std::vector<double> scaleFactors;
std::vector< std::vector< std::string > > restOfHeaderRows;
for (const auto& wordsForRow : allHeaderRows)
{
bool excludeFromHeader = false;
if (unitNames.size() == 0)
{
for (const std::string& word : wordsForRow)
{
if (hasTimeUnit(word))
{
unitNames = wordsForRow;
excludeFromHeader = true;
}
}
}
if (scaleFactors.size() == 0)
{
std::vector<double> values;
if (hasOnlyValidDoubleValues(wordsForRow, &values))
{
scaleFactors = values;
excludeFromHeader = true;
}
}
if (!excludeFromHeader)
{
restOfHeaderRows.push_back(wordsForRow);
}
}
for (const std::string& unit : unitNames)
{
ColumnInfo columnInfo;
columnInfo.unitName = unit;
columnInfo.origin = origin;
columnInfo.dateFormatString = dateFormat;
columnInfo.startDateString = startDate;
table.push_back(columnInfo);
}
for (size_t i = 0; i < table.size(); i++)
{
if (scaleFactors.size() == table.size())
{
table[i].scaleFactor = scaleFactors[i];
}
else
{
table[i].scaleFactor = 1.0;
}
}
for (size_t i = 0; i < table.size(); i++)
{
std::vector< std::string > restOfHeaderColumn;
for (std::vector< std::string > restOfHeaderRow : restOfHeaderRows)
{
restOfHeaderColumn.push_back(restOfHeaderRow.at(i));
}
table[i].summaryAddress = makeAndFillAddress(quantityNames.at(i), restOfHeaderColumn);
}
for (ColumnInfo& column : table)
{
if (column.summaryAddress.category() != RifEclipseSummaryAddress::SUMMARY_INVALID)
{
column.isAVector = true;
}
}
return table;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -486,19 +274,234 @@ bool RifEclipseUserDataParserTools::hasOnlyValidDoubleValues(const std::vector<s
{
char* end;
bool onlyValidValues = true;
for (const auto& word : words)
{
double doubleVal = strtod(word.data(), &end);
if (end == word.data())
if (word.find_first_not_of("0123456789.eE-") != std::string::npos)
{
return false;
onlyValidValues = false;
}
if (doubleValues)
else
{
double doubleVal = strtod(word.data(), &end);
doubleValues->push_back(doubleVal);
}
}
return true;
return onlyValidValues;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::hasDateUnit(const std::string& word)
{
if (word.find("DATE") != std::string::npos) return true;
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseUserDataParserTools::isValidTableData(size_t columnCount, const std::string& line)
{
std::vector<std::string> words = splitLineAndRemoveComments(line);
if (words.size() != columnCount) return false;
std::vector<double> doubleValues;
RifEclipseUserDataParserTools::hasOnlyValidDoubleValues(words, &doubleValues);
if (doubleValues.size() == columnCount) return true;
size_t columnsWithDate = 0;
for (auto w : words)
{
if (RiaDateStringParser::parseDateString(w).isValid())
{
columnsWithDate++;
}
}
if (columnsWithDate == 1 && doubleValues.size() == columnCount - 1)
{
return true;
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TableData RifEclipseUserDataParserTools::tableDataFromText(std::stringstream& streamData, std::vector<std::string>* errorText)
{
TableData emptyTable;
std::string origin = "";
std::string dateFormat = "";
std::string startDate = "";
std::string firstLine;
std::getline(streamData, firstLine);
while (isLineSkippable(firstLine) || keywordParser(firstLine, origin, dateFormat, startDate))
{
if (!streamData.good())
{
if (errorText) errorText->push_back("Failed to detect start of table header");
return emptyTable;
}
std::getline(streamData, firstLine);
}
std::vector<std::string> quantityNames = splitLineAndRemoveComments(firstLine);
size_t columnCount = quantityNames.size();
if (columnCount == 0)
{
if (errorText) errorText->push_back("No quantities detected in table");
return emptyTable;
}
std::vector< std::vector< std::string > > allHeaderRows;
{
std::stringstream::pos_type posAtStartOfFirstLine = streamData.tellg();
std::string secondLine;
std::getline(streamData, firstLine);
std::stringstream::pos_type posAtStartOfSecondLine = streamData.tellg();
std::getline(streamData, secondLine);
bool header = true;
while (header)
{
if (isValidTableData(columnCount, firstLine) &&
isValidTableData(columnCount, secondLine))
{
header = false;
break;
}
else
{
std::vector<std::string> words = splitLineAndRemoveComments(firstLine);
if (words.size() > 0)
{
allHeaderRows.push_back(words);
}
}
posAtStartOfFirstLine = posAtStartOfSecondLine;
firstLine = secondLine;
posAtStartOfSecondLine = streamData.tellg();
std::getline(streamData, secondLine);
if (!streamData.good())
{
header = false;
}
}
streamData.seekg(posAtStartOfFirstLine);
}
std::vector<std::string> unitNames;
std::vector<double> scaleFactors;
std::vector< std::vector< std::string > > headerRows;
for (const auto& rowWords : allHeaderRows)
{
bool excludeFromHeader = false;
if (rowWords.size() == columnCount)
{
if (unitNames.size() == 0)
{
for (const std::string& word : rowWords)
{
if (hasTimeUnit(word))
{
unitNames = rowWords;
excludeFromHeader = true;
}
}
}
if (scaleFactors.size() == 0)
{
std::vector<double> values;
if (hasOnlyValidDoubleValues(rowWords, &values))
{
scaleFactors = values;
excludeFromHeader = true;
}
}
}
if (!excludeFromHeader)
{
headerRows.push_back(rowWords);
}
}
if (columnCount != unitNames.size())
{
if (errorText) errorText->push_back("Number of quantities is different from number of units");
return emptyTable;
}
std::vector<ColumnInfo> columnInfos;
// Create string vectors for each column
{
std::vector<std::string> parserErrors;
std::vector<std::vector<std::string>> tableHeaderText = RifEclipseUserDataKeywordTools::buildColumnHeaderText(quantityNames, headerRows, &parserErrors);
if (parserErrors.size() > 0)
{
if (errorText) errorText->insert(errorText->end(), parserErrors.begin(), parserErrors.end());
return emptyTable;
}
// For each column header, create rif adress and date time
for (size_t i = 0; i < tableHeaderText.size(); i++)
{
auto columnText = tableHeaderText[i];
if (columnText.size() == 0)
{
if (errorText) errorText->push_back("Detected column with no content");
continue;
}
std::string quantity = columnText[0];
std::string unit = unitNames[i];
std::vector<std::string> columnHeader;
if (columnText.size() > 1) columnHeader.insert(columnHeader.begin(), columnText.begin() + 1, columnText.end());
RifEclipseSummaryAddress adr = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnHeader);
ColumnInfo ci(adr, unit);
if (quantity == "DATE")
{
ci.isStringData = true;
}
columnInfos.push_back(ci);
}
}
return TableData(origin, dateFormat, startDate, columnInfos);
}

View File

@@ -28,18 +28,86 @@
#include <string>
#include <vector>
struct ColumnInfo
//==================================================================================================
///
//==================================================================================================
class ColumnInfo
{
bool isAVector = false;
public:
ColumnInfo()
: scaleFactor(1.0),
isStringData(false)
{
}
ColumnInfo(const RifEclipseSummaryAddress& adr, const std::string& unit)
: summaryAddress(adr),
scaleFactor(1.0),
unitName(unit),
isStringData(false)
{
}
public:
RifEclipseSummaryAddress summaryAddress;
std::string unitName;
double scaleFactor;
std::vector<double> values;
std::string origin;
std::string dateFormatString;
std::string startDateString;
QDateTime startQDateTime;
std::vector<QDateTime> observationDateTimes;
bool isStringData;
std::vector<std::string> stringValues;
};
//==================================================================================================
///
//==================================================================================================
class TableData
{
public:
TableData()
{}
TableData(const std::string& origin,
const std::string& dateFormat,
const std::string& startDate,
const std::vector<ColumnInfo>& columnInfos)
: m_origin(origin),
m_dateFormat(dateFormat),
m_startDate(startDate),
m_columnInfos(columnInfos)
{
}
std::string origin() const
{
return m_origin;
}
std::string startDate() const
{
return m_startDate;
}
std::string dateFormat() const
{
return m_dateFormat;
}
std::vector<ColumnInfo>& columnInfos()
{
return m_columnInfos;
}
const std::vector<ColumnInfo>& columnInfos() const
{
return m_columnInfos;
}
private:
std::string m_origin;
std::string m_dateFormat;
std::string m_startDate;
std::vector<ColumnInfo> m_columnInfos;
};
//==================================================================================================
@@ -54,12 +122,15 @@ public:
static RifEclipseSummaryAddress::SummaryVarCategory identifyCategory(const std::string& word);
static void splitLineToDoubles(const std::string& line, std::vector<double>& values);
static size_t findFirstNonEmptyEntryIndex(std::vector<std::string>& list);
static RifEclipseSummaryAddress makeAndFillAddress(std::string quantityName, std::vector< std::string > headerColumn);
static bool keywordParser(const std::string& line, std::string& origin, std::string& dateFormat, std::string& startDate);
static std::vector<ColumnInfo> columnInfoForTable(std::stringstream& data);
static bool isANumber(const std::string& line);
static std::vector<std::string> headerReader(std::stringstream& streamData, std::string& line);
static bool hasTimeUnit(const std::string& line);
static bool hasOnlyValidDoubleValues(const std::vector<std::string>& words, std::vector<double>* doubleValues = nullptr);
static bool hasDateUnit(const std::string& word);
static bool isValidTableData(size_t columnCount, const std::string& line);
static TableData tableDataFromText(std::stringstream& data, std::vector<std::string>* errorText = nullptr);
};

View File

@@ -31,7 +31,8 @@ ${CEE_CURRENT_LIST_DIR}RigHexIntersectionTools-Test.cpp
${CEE_CURRENT_LIST_DIR}ObservedDataParser-Test.cpp
${CEE_CURRENT_LIST_DIR}EclipseRftReader-Test.cpp
${CEE_CURRENT_LIST_DIR}RicExpressionParser-Test.cpp
${CEE_CURRENT_LIST_DIR}RiuSummaryVectorDescriptionMap-Test
${CEE_CURRENT_LIST_DIR}RiuSummaryVectorDescriptionMap-Test.cpp
${CEE_CURRENT_LIST_DIR}RifEclipseUserDataKeywordTools-Test.cpp
)
if (RESINSIGHT_ENABLE_PROTOTYPE_FEATURE_FRACTURES)

View File

@@ -8,6 +8,8 @@
#include <vector>
#include <QTextStream>
#include <QDebug>
#include "RifEclipseUserDataKeywordTools.h"
//--------------------------------------------------------------------------------------------------
///
@@ -246,7 +248,7 @@ TEST(RifRsmspecParserToolsTest, TestSplitLineToDoubles)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RifColumnBasedRsmspecParserTest, TestKeywordsAndMissingUnitName)
TEST(RifColumnBasedRsmspecParserTest, TestTwoPages)
{
QString data;
@@ -258,7 +260,7 @@ TEST(RifColumnBasedRsmspecParserTest, TestKeywordsAndMissingUnitName)
out << "DATEFORMAT DD/MM/YY\n";
out << "\n";
out << "TIME YEARX WGT1 WGT2 WGT4 WR12 WR22 WR42 \n";
out << "DAYS YEARS kg/Sm3 kg/Sm3 kg/Sm3 kg/Sm3 kg/Sm3 \n";
out << "DAYS YEARS kg/Sm3 kg/Sm3 kg/Sm3 kg/Sm3 kg/Sm3 kg/Sm3 \n";
out << "1 1 1.00E+03 1.00E+03 1.00E+03 1.00E+03 1.00E+03 1.00E+03 \n";
out << " OP-1 OP-1 OP-1 OP-1 OP-1 OP-1 \n";
out << "\n";
@@ -289,21 +291,18 @@ TEST(RifColumnBasedRsmspecParserTest, TestKeywordsAndMissingUnitName)
RifColumnBasedUserDataParser parser = RifColumnBasedUserDataParser(data);
std::vector< std::vector<ColumnInfo> > tables = parser.tables();
auto tables = parser.tableData();
ASSERT_EQ(2, tables.size());
EXPECT_EQ("112000", tables[0].at(0).startDateString);
EXPECT_EQ("OP-1_TR", tables[0].at(0).origin);
EXPECT_EQ("DD/MM/YY", tables[0].at(0).dateFormatString);
EXPECT_EQ("1 1 2000", tables[0].startDate());
EXPECT_EQ("OP-1_TR", tables[0].origin());
EXPECT_EQ("DD/MM/YY", tables[0].dateFormat());
EXPECT_EQ("112000", tables[1].at(0).startDateString);
EXPECT_EQ("OP-2_TR", tables[1].at(0).origin);
EXPECT_EQ("DD/MM/YY", tables[1].at(0).dateFormatString);
EXPECT_EQ("1 1 2000", tables[1].startDate());
EXPECT_EQ("OP-2_TR", tables[1].origin());
EXPECT_EQ("DD/MM/YY", tables[1].dateFormat());
// Assume missing units at start of row
EXPECT_EQ("", tables[0].at(0).unitName);
ASSERT_EQ(8, tables.at(0).size());
EXPECT_EQ(1.0E-12, tables.at(0).at(4).values[0]);
ASSERT_EQ(8, tables.at(0).columnInfos().size());
EXPECT_EQ(1.0E-12, tables.at(0).columnInfos().at(4).values[0]);
}
@@ -358,28 +357,28 @@ TEST(RifColumnBasedRsmspecParserTest, TestTableValues)
RifColumnBasedUserDataParser parser = RifColumnBasedUserDataParser(data);
std::vector< std::vector<ColumnInfo> > tables = parser.tables();
auto tables = parser.tableData();
ASSERT_EQ(tables.size(), 2);
ASSERT_EQ(tables.at(0).size(), 6);
ASSERT_EQ(tables.at(1).size(), 6);
ASSERT_EQ(tables.at(0).columnInfos().size(), 6);
ASSERT_EQ(tables.at(1).columnInfos().size(), 6);
ASSERT_EQ(18, tables.at(0).at(0).values.size());
ASSERT_EQ(4, tables.at(1).at(0).values.size());
ASSERT_EQ(18, tables.at(0).columnInfos().at(0).values.size());
ASSERT_EQ(4, tables.at(1).columnInfos().at(0).values.size());
EXPECT_TRUE(tables.at(0).at(2).isAVector);
EXPECT_FALSE(tables.at(1).at(0).isAVector);
// EXPECT_TRUE(tables.at(0).columnInfos().at(2).isAVector);
// EXPECT_FALSE(tables.at(1).columnInfos().at(0).isAVector);
EXPECT_EQ(0.0, tables.at(0).at(1).values.at(6));
EXPECT_EQ(282, tables.at(0).at(3).values.at(6));
EXPECT_EQ(0.0, tables.at(0).columnInfos().at(1).values.at(6));
EXPECT_EQ(282, tables.at(0).columnInfos().at(3).values.at(6));
EXPECT_EQ(3, tables.at(1).at(0).values.at(2));
EXPECT_EQ(370, tables.at(1).at(3).values.at(3));
EXPECT_EQ(3, tables.at(1).columnInfos().at(0).values.at(2));
EXPECT_EQ(370, tables.at(1).columnInfos().at(3).values.at(3));
EXPECT_EQ("WLVP", tables.at(0).at(1).summaryAddress.quantityName());
EXPECT_EQ("P-15P", tables.at(0).at(5).summaryAddress.wellName());
EXPECT_EQ("P-9P", tables.at(1).at(1).summaryAddress.wellName());
EXPECT_NE("P-9P", tables.at(1).at(0).summaryAddress.wellName());
EXPECT_EQ("WLVP", tables.at(0).columnInfos().at(1).summaryAddress.quantityName());
EXPECT_EQ("P-15P", tables.at(0).columnInfos().at(5).summaryAddress.wellName());
EXPECT_EQ("P-9P", tables.at(1).columnInfos().at(1).summaryAddress.wellName());
EXPECT_NE("P-9P", tables.at(1).columnInfos().at(0).summaryAddress.wellName());
}
//--------------------------------------------------------------------------------------------------
@@ -419,9 +418,10 @@ TEST(RifColumnBasedRsmspecParserTest, TestTableMissingWellNames)
RifColumnBasedUserDataParser parser = RifColumnBasedUserDataParser(data);
std::vector< std::vector<ColumnInfo> > tables = parser.tables();
ASSERT_EQ(tables.size(), 1);
ASSERT_EQ(tables.at(0).size(), 6);
auto tables = parser.tableData();
// Missing header line with well name, returning empty table
ASSERT_EQ(tables.size(), 0);
}
//--------------------------------------------------------------------------------------------------
@@ -437,7 +437,7 @@ TEST(RifColumnBasedRsmspecParserTest, TestTableValuesHeaderWithSpaces)
out << " SUMMARY OF RUN NORNE_ATW2013_RFTPLT_V3 EC\n";
out << " -----------------------------------------\n";
out << " DATE YEARS WBHP \n";
out << " YEARS BARSA \n";
out << " DATE YEARS BARSA \n";
out << " B-1H \n";
out << " \n";
out << " -----------------------------------------\n";
@@ -470,7 +470,7 @@ TEST(RifColumnBasedRsmspecParserTest, TestTableValuesHeaderWithSpaces)
RifColumnBasedUserDataParser parser = RifColumnBasedUserDataParser(data);
std::vector< std::vector<ColumnInfo> > tables = parser.tables();
auto tables = parser.tableData();
ASSERT_EQ(tables.size(), 1);
}
@@ -521,7 +521,7 @@ TEST(RifColumnBasedRsmspecParserTest, TestTableDateOnly)
RifColumnBasedUserDataParser parser = RifColumnBasedUserDataParser(data);
std::vector< std::vector<ColumnInfo> > tables = parser.tables();
auto tables = parser.tableData();
ASSERT_EQ(tables.size(), 1);
}
@@ -673,17 +673,17 @@ TEST(RifKeywordBasedRsmspecParserTest, TestShutins)
RifColumnBasedUserDataParser parser = RifColumnBasedUserDataParser(data);
std::vector< std::vector<ColumnInfo> > tables = parser.tables();
auto tables = parser.tableData();
ASSERT_EQ(1, tables.size());
ASSERT_EQ(3, tables.at(0).size());
ASSERT_EQ(18, tables.at(0).at(2).values.size());
ASSERT_EQ(3, tables[0].columnInfos().size());
ASSERT_EQ(18, tables.at(0).columnInfos().at(2).values.size());
EXPECT_EQ(2014.39, tables.at(0).at(1).values[2]);
EXPECT_EQ(2014.39, tables.at(0).columnInfos().at(1).values[2]);
EXPECT_EQ("WBP9L", tables.at(0).at(2).summaryAddress.quantityName());
EXPECT_EQ("WBP9L", tables.at(0).columnInfos().at(2).summaryAddress.quantityName());
EXPECT_EQ("OP-1", tables.at(0).at(2).summaryAddress.wellName());
EXPECT_NE("OP-1", tables.at(0).at(1).summaryAddress.wellName());
EXPECT_EQ("OP-1", tables.at(0).columnInfos().at(2).summaryAddress.wellName());
EXPECT_NE("OP-1", tables.at(0).columnInfos().at(1).summaryAddress.wellName());
}
@@ -732,13 +732,20 @@ TEST(RifKeywordBasedRsmspecParserTest, TestTimeSteps)
std::vector< std::string > headerColumn;
headerColumn.push_back("OP-1");
RifEclipseSummaryAddress address = RifEclipseUserDataParserTools::makeAndFillAddress(quantityName, headerColumn);
RifEclipseSummaryAddress address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantityName, headerColumn);
RifColumnBasedUserData columnBasedUserdata;
columnBasedUserdata.parse(data, "", "");
std::vector<time_t> timeSteps = columnBasedUserdata.timeSteps(address);
for (auto t : timeSteps)
{
QDateTime dt = QDateTime::fromTime_t(t);
qDebug() << dt;
}
QDateTime startDate = QDateTime::fromString("01012004", "ddMMyyyy");
startDate.setTimeSpec(Qt::UTC);
@@ -756,33 +763,35 @@ TEST(RifKeywordBasedRsmspecParserTest, TestTimeSteps)
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RifColumnBasedRsmspecParserTest, TestTooManyColumnsInFile)
TEST(RifColumnBasedRsmspecParserTest, IsTableData)
{
QString data;
QTextStream out(&data);
{
std::string line(" 6-NOV-1997 0 ");
EXPECT_TRUE(RifEclipseUserDataParserTools::isValidTableData(2, line));
}
out << "1 \n";
out << "--------------------------------------- \n";
out << "SUMMARY OF RUN BHP_THP USER FILE DATA VECTORS \n";
out << "--------------------------------------- \n";
out << "TIME WTHPH WBHPH \n";
out << "DAYS BARSA BARSA \n";
out << " \n";
out << " K-6HWG K-6HWG \n";
out << " 1 0.0 0.0 0.0 \n";
out << " 2 0.0 0.0 0.0 \n";
out << " 3 0.0 0.0 0.0 \n";
out << " 4 0.0 0.0 0.0 \n";
out << " 5 0.0 0.0 0.0 \n";
out << " 6 0.0 0.0 0.0 \n";
out << " 7 0.0 0.0 0.0 \n";
out << " 8 0.0 0.0 0.0 \n";
out << " 9 0.0 0.0 0.0 \n";
out << " 10 0.0 0.0 0.0 \n";
out << " \n";
{
std::string line(" DATE BARSA ");
EXPECT_FALSE(RifEclipseUserDataParserTools::isValidTableData(2, line));
}
RifColumnBasedUserDataParser parser = RifColumnBasedUserDataParser(data);
{
std::string line(" 1.2 0 ");
EXPECT_TRUE(RifEclipseUserDataParserTools::isValidTableData(2, line));
}
std::vector< std::vector<ColumnInfo> > tables = parser.tables();
ASSERT_EQ(tables.size(), 1);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RifColumnBasedRsmspecParserTest, HasOnlyValidDoubleValues)
{
{
std::vector<double> doubleValues;
std::string line(" 6-NOV-1997 0 ");
std::vector<std::string> words = RifEclipseUserDataParserTools::splitLineAndRemoveComments(line);
EXPECT_FALSE(RifEclipseUserDataParserTools::hasOnlyValidDoubleValues(words, &doubleValues));
}
}

View File

@@ -0,0 +1,280 @@
#include "gtest/gtest.h"
#include "RifEclipseUserDataKeywordTools.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RifEclipseUserDataKeywordToolsTest, TestIdentifierItemsPerLine)
{
{
std::string s = "AA";
EXPECT_EQ(0, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s).size());
}
{
std::string s = "BB";
EXPECT_EQ(3, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[0]);
}
{
std::string s = "CC";
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[0]);
EXPECT_EQ(3, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[1]);
}
{
std::string s = "FF";
EXPECT_EQ(0, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s).size());
}
{
std::string s = "GG";
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[0]);
}
{
std::string s = "NN";
EXPECT_EQ(0, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s).size());
}
{
std::string s = "RR";
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[0]);
}
{
std::string s = "SS";
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[0]);
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[1]);
}
{
std::string s = "WW";
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[0]);
}
{
std::string s = "LB";
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[0]);
EXPECT_EQ(3, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[1]);
}
{
std::string s = "LC";
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[0]);
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[1]);
EXPECT_EQ(3, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[2]);
}
{
std::string s = "LW";
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[0]);
EXPECT_EQ(1, RifEclipseUserDataKeywordTools::requiredItemsPerLineForKeyword(s)[1]);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RifEclipseUserDataKeywordToolsTest, BuildTableHeaderText)
{
std::vector<std::string> keywordNames = { "TIME", "YEARX", "WGT1", "WR42" };
std::vector<std::string> firstheader = { "OP-1", "OP-1" };
std::vector<std::vector<std::string>> headerLines = { firstheader };
auto tableHeaderData = RifEclipseUserDataKeywordTools::buildColumnHeaderText(keywordNames, headerLines);
EXPECT_EQ(4, tableHeaderData.size());
EXPECT_EQ(1, tableHeaderData[0].size());
EXPECT_EQ(1, tableHeaderData[1].size());
EXPECT_EQ(2, tableHeaderData[2].size());
EXPECT_EQ(2, tableHeaderData[3].size());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RifEclipseUserDataKeywordToolsTest, BuildTableHeaderTextComplex)
{
std::vector<std::string> keywordNames = { "TIME", "WGT1", "FVIR", "RPR", "GOPR", "CWIR", "FTPTS36", "CWIR" };
std::vector<std::string> firstheader = { "OP-1", "8", "MANI-D2", "F-2H", "2H" };
std::vector<std::string> secondHeader = { "18", "83","3", "9", "8","7" };
std::vector<std::vector<std::string>> headerLines = { firstheader, secondHeader };
auto tableHeaderData = RifEclipseUserDataKeywordTools::buildColumnHeaderText(keywordNames, headerLines);
EXPECT_EQ(8, tableHeaderData.size());
EXPECT_EQ(1, tableHeaderData[0].size());
EXPECT_EQ(2, tableHeaderData[1].size());
EXPECT_EQ(1, tableHeaderData[2].size());
EXPECT_EQ(2, tableHeaderData[3].size());
EXPECT_EQ(2, tableHeaderData[4].size());
EXPECT_EQ(5, tableHeaderData[5].size());
EXPECT_EQ(1, tableHeaderData[6].size());
EXPECT_EQ(5, tableHeaderData[7].size());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RifEclipseUserDataKeywordToolsTest, MissingHeaderData)
{
{
std::vector<std::string> keywordNames = { "TIME", "WGT1" };
std::vector<std::string> firstheader = { }; // Missing well name
std::vector<std::vector<std::string>> headerLines = { firstheader };
auto tableHeaderData = RifEclipseUserDataKeywordTools::buildColumnHeaderText(keywordNames, headerLines);
EXPECT_EQ(0, tableHeaderData.size());
}
{
std::vector<std::string> keywordNames = { "TIME", "WGT1", "FVIR", "RPR", "GOPR", "CWIR", "FTPTS36", "CWIR" };
std::vector<std::string> firstheader = { "OP-1", "8", "MANI-D2", "F-2H", "2H" };
std::vector<std::string> secondHeader = { "18", "83","3", "9", "8" }; // Missing value from last triplet
std::vector<std::vector<std::string>> headerLines = { firstheader, secondHeader };
auto tableHeaderData = RifEclipseUserDataKeywordTools::buildColumnHeaderText(keywordNames, headerLines);
EXPECT_EQ(0, tableHeaderData.size());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RifEclipseUserDataKeywordToolsTest, CreationOfSummaryAddresses)
{
// Region
{
std::string quantity = "RGT1";
std::vector<std::string> columnData = {"1"};
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_REGION);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
EXPECT_EQ(1, address.regionNumber());
}
// Well group
{
std::string quantity = "GT1";
std::vector<std::string> columnData = { "OP-1" };
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_WELL_GROUP);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
EXPECT_STREQ(columnData[0].data(), address.wellGroupName().data());
}
// Well
{
std::string quantity = "WGT1";
std::vector<std::string> columnData = { "OP-1" };
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_WELL);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
EXPECT_STREQ(columnData[0].data(), address.wellName().data());
}
// Well completion
{
std::string quantity = "CWIT";
std::vector<std::string> columnData = { "F-3H", "1", "2", "3" };
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
EXPECT_STREQ(columnData[0].data(), address.wellName().data());
EXPECT_EQ(1, address.cellI());
EXPECT_EQ(2, address.cellJ());
EXPECT_EQ(3, address.cellK());
}
// Well LGR
{
std::string quantity = "LWGT1";
std::vector<std::string> columnData = { "OP-1", "LGR-NAME" };
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_WELL_LGR);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
EXPECT_STREQ(columnData[0].data(), address.wellName().data());
EXPECT_STREQ(columnData[1].data(), address.lgrName().data());
}
// Well completion LGR
{
std::string quantity = "LC";
std::vector<std::string> columnData = { "F-3H", "LGR-NAME", "1", "2", "3" };
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_WELL_COMPLETION_LGR);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
EXPECT_STREQ(columnData[0].data(), address.wellName().data());
EXPECT_STREQ(columnData[1].data(), address.lgrName().data());
EXPECT_EQ(1, address.cellI());
EXPECT_EQ(2, address.cellJ());
EXPECT_EQ(3, address.cellK());
}
// Well segment
{
std::string quantity = "SCWIT";
std::vector<std::string> columnData = { "F-3H", "1" };
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_WELL_SEGMENT);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
EXPECT_STREQ(columnData[0].data(), address.wellName().data());
EXPECT_EQ(1, address.wellSegmentNumber());
}
// Block
{
std::string quantity = "BWIT";
std::vector<std::string> columnData = { "1", "2", "3" };
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_BLOCK);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
EXPECT_EQ(1, address.cellI());
EXPECT_EQ(2, address.cellJ());
EXPECT_EQ(3, address.cellK());
}
// Block LGR
{
std::string quantity = "LBWIT";
std::vector<std::string> columnData = { "LGR-name", "1", "2", "3" };
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_BLOCK_LGR);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
EXPECT_STREQ(columnData[0].data(), address.lgrName().data());
EXPECT_EQ(1, address.cellI());
EXPECT_EQ(2, address.cellJ());
EXPECT_EQ(3, address.cellK());
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST(RifEclipseUserDataKeywordToolsTest, CreationOfMisc)
{
// Misc
{
std::string quantity = "JI-NOT-REQOGNIZED";
std::vector<std::string> columnData = { };
auto address = RifEclipseUserDataKeywordTools::makeAndFillAddress(quantity, columnData);
EXPECT_EQ(address.category(), RifEclipseSummaryAddress::SUMMARY_MISC);
EXPECT_STREQ(quantity.data(), address.quantityName().data());
}
}