2017-05-10 05:19:46 -05:00
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 2011- Statoil ASA
|
|
|
|
|
// Copyright (C) 2013- Ceetron Solutions AS
|
|
|
|
|
// Copyright (C) 2011-2012 Ceetron AS
|
|
|
|
|
//
|
|
|
|
|
// 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 "RifWellPathImporter.h"
|
|
|
|
|
|
|
|
|
|
#include "RifJsonEncodeDecode.h"
|
|
|
|
|
|
|
|
|
|
#include <fstream>
|
|
|
|
|
|
2017-05-15 06:40:13 -05:00
|
|
|
|
#include "cafUtils.h"
|
|
|
|
|
|
2017-05-10 05:19:46 -05:00
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
|
2017-05-15 07:06:40 -05:00
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
2017-05-10 05:19:46 -05:00
|
|
|
|
#define ASCII_FILE_DEFAULT_START_INDEX 0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RifWellPathImporter::WellData RifWellPathImporter::readWellData(const QString& filePath, size_t indexInFile)
|
|
|
|
|
{
|
2017-05-15 06:40:13 -05:00
|
|
|
|
CVF_ASSERT(caf::Utils::fileExists(filePath));
|
2017-05-10 05:19:46 -05:00
|
|
|
|
|
|
|
|
|
if (isJsonFile(filePath))
|
|
|
|
|
{
|
|
|
|
|
return readJsonWellData(filePath);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return readAsciiWellData(filePath, indexInFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RifWellPathImporter::WellData RifWellPathImporter::readWellData(const QString& filePath)
|
|
|
|
|
{
|
|
|
|
|
return readWellData(filePath, ASCII_FILE_DEFAULT_START_INDEX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RifWellPathImporter::WellMetaData RifWellPathImporter::readWellMetaData(const QString& filePath, size_t indexInFile)
|
|
|
|
|
{
|
2017-05-15 06:40:13 -05:00
|
|
|
|
CVF_ASSERT(caf::Utils::fileExists(filePath));
|
2017-05-10 05:19:46 -05:00
|
|
|
|
|
|
|
|
|
if (isJsonFile(filePath))
|
|
|
|
|
{
|
|
|
|
|
return readJsonWellMetaData(filePath);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return readAsciiWellMetaData(filePath, indexInFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RifWellPathImporter::WellMetaData RifWellPathImporter::readWellMetaData(const QString& filePath)
|
|
|
|
|
{
|
|
|
|
|
return readWellMetaData(filePath, ASCII_FILE_DEFAULT_START_INDEX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
size_t RifWellPathImporter::wellDataCount(const QString& filePath)
|
|
|
|
|
{
|
|
|
|
|
if (isJsonFile(filePath))
|
|
|
|
|
{
|
|
|
|
|
// Only support JSON files with single well data currently
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::map<QString, std::vector<RifWellPathImporter::WellData> >::iterator it = m_fileNameToWellDataGroupMap.find(filePath);
|
|
|
|
|
|
|
|
|
|
// If we have the file in the map, assume it is already read.
|
|
|
|
|
if (it != m_fileNameToWellDataGroupMap.end())
|
|
|
|
|
{
|
|
|
|
|
return it->second.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
readAllAsciiWellData(filePath);
|
|
|
|
|
it = m_fileNameToWellDataGroupMap.find(filePath);
|
|
|
|
|
CVF_ASSERT(it != m_fileNameToWellDataGroupMap.end());
|
|
|
|
|
|
|
|
|
|
return it->second.size();;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
bool RifWellPathImporter::isJsonFile(const QString & filePath)
|
|
|
|
|
{
|
|
|
|
|
QFileInfo fileInfo(filePath);
|
|
|
|
|
|
|
|
|
|
if (fileInfo.suffix().compare("json") == 0)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RifWellPathImporter::WellMetaData RifWellPathImporter::readJsonWellMetaData(const QString & filePath)
|
|
|
|
|
{
|
|
|
|
|
ResInsightInternalJson::JsonReader jsonReader;
|
|
|
|
|
QMap<QString, QVariant> jsonMap = jsonReader.decodeFile(filePath);
|
|
|
|
|
WellMetaData metadata;
|
|
|
|
|
|
|
|
|
|
metadata.m_id = jsonMap["id"].toString();
|
|
|
|
|
metadata.m_name = jsonMap["name"].toString();
|
|
|
|
|
metadata.m_sourceSystem = jsonMap["sourceSystem"].toString();
|
|
|
|
|
metadata.m_utmZone = jsonMap["utmZone"].toString();
|
|
|
|
|
metadata.m_updateUser = jsonMap["updateUser"].toString();
|
|
|
|
|
metadata.m_surveyType = jsonMap["surveyType"].toString();
|
|
|
|
|
|
|
|
|
|
// Convert updateDate from the following format:
|
|
|
|
|
// "Number of milliseconds elapsed since midnight Coordinated Universal Time (UTC)
|
|
|
|
|
// of January 1, 1970, not counting leap seconds"
|
|
|
|
|
QString updateDateStr = jsonMap["updateDate"].toString().trimmed();
|
|
|
|
|
uint updateDateUint = updateDateStr.toULongLong() / 1000; // Should be within 32 bit, maximum number is 4294967295 which corresponds to year 2106
|
|
|
|
|
metadata.m_updateDate.setTime_t(updateDateUint);
|
|
|
|
|
|
|
|
|
|
return metadata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RifWellPathImporter::WellData RifWellPathImporter::readJsonWellData(const QString& filePath)
|
|
|
|
|
{
|
|
|
|
|
ResInsightInternalJson::JsonReader jsonReader;
|
|
|
|
|
QMap<QString, QVariant> jsonMap = jsonReader.decodeFile(filePath);
|
|
|
|
|
|
|
|
|
|
double datumElevation = jsonMap["datumElevation"].toDouble();
|
|
|
|
|
QList<QVariant> pathList = jsonMap["path"].toList();
|
|
|
|
|
WellData wellData;
|
2017-08-15 08:16:29 -05:00
|
|
|
|
wellData.m_wellPathGeometry = new RigWellPath;
|
2017-05-10 05:19:46 -05:00
|
|
|
|
wellData.m_wellPathGeometry->setDatumElevation(datumElevation);
|
|
|
|
|
wellData.m_name = jsonMap["name"].toString();
|
|
|
|
|
|
|
|
|
|
foreach(QVariant point, pathList)
|
|
|
|
|
{
|
|
|
|
|
QMap<QString, QVariant> coordinateMap = point.toMap();
|
|
|
|
|
cvf::Vec3d vec3d(coordinateMap["east"].toDouble(), coordinateMap["north"].toDouble(), -(coordinateMap["tvd"].toDouble() - datumElevation));
|
|
|
|
|
wellData.m_wellPathGeometry->m_wellPathPoints.push_back(vec3d);
|
|
|
|
|
double measuredDepth = coordinateMap["md"].toDouble();
|
|
|
|
|
wellData.m_wellPathGeometry->m_measuredDepths.push_back(measuredDepth);
|
|
|
|
|
}
|
|
|
|
|
return wellData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RifWellPathImporter::readAllAsciiWellData(const QString& filePath)
|
|
|
|
|
{
|
|
|
|
|
std::map<QString, std::vector<RifWellPathImporter::WellData> >::iterator it = m_fileNameToWellDataGroupMap.find(filePath);
|
|
|
|
|
|
|
|
|
|
// If we have the file in the map, assume it is already read.
|
|
|
|
|
if (it != m_fileNameToWellDataGroupMap.end())
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create the data container
|
|
|
|
|
std::vector<RifWellPathImporter::WellData>& fileWellDataArray = m_fileNameToWellDataGroupMap[filePath];
|
|
|
|
|
|
|
|
|
|
std::ifstream stream(filePath.toLatin1().data());
|
|
|
|
|
double x(HUGE_VAL), y(HUGE_VAL), tvd(HUGE_VAL), md(HUGE_VAL);
|
|
|
|
|
|
|
|
|
|
bool hasReadWellPointInCurrentWell = false;
|
|
|
|
|
|
|
|
|
|
while (stream.good())
|
|
|
|
|
{
|
|
|
|
|
// First check if we can read a number
|
|
|
|
|
stream >> x;
|
|
|
|
|
if (stream.good()) // If we can, assume this line is a well point entry
|
|
|
|
|
{
|
|
|
|
|
stream >> y >> tvd >> md;
|
|
|
|
|
if (!stream.good())
|
|
|
|
|
{
|
|
|
|
|
// -999 or otherwise to few numbers before some word
|
|
|
|
|
if (x != -999)
|
|
|
|
|
{
|
|
|
|
|
// Error in file: missing numbers at this line
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
stream.clear();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!fileWellDataArray.size())
|
|
|
|
|
{
|
|
|
|
|
fileWellDataArray.push_back(RifWellPathImporter::WellData());
|
|
|
|
|
fileWellDataArray.back().m_wellPathGeometry = new RigWellPath();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cvf::Vec3d wellPoint(x, y, -tvd);
|
|
|
|
|
fileWellDataArray.back().m_wellPathGeometry->m_wellPathPoints.push_back(wellPoint);
|
|
|
|
|
fileWellDataArray.back().m_wellPathGeometry->m_measuredDepths.push_back(md);
|
|
|
|
|
|
|
|
|
|
x = HUGE_VAL;
|
|
|
|
|
y = HUGE_VAL;
|
|
|
|
|
tvd = HUGE_VAL;
|
|
|
|
|
md = HUGE_VAL;
|
|
|
|
|
|
|
|
|
|
hasReadWellPointInCurrentWell = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Could not read one double.
|
|
|
|
|
// we assume there is a comment line or a well path description
|
|
|
|
|
stream.clear();
|
|
|
|
|
|
|
|
|
|
std::string line;
|
|
|
|
|
std::getline(stream, line, '\n');
|
|
|
|
|
// Skip possible comment lines (-- is used in eclipse, so Haakon H<>gst<73>l considered it smart to skip these here as well)
|
|
|
|
|
// The first "-" is eaten by the stream >> x above
|
|
|
|
|
if (line.find("-") == 0 || line.find("#") == 0)
|
|
|
|
|
{
|
|
|
|
|
// Comment line, just ignore
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Find the first and the last position of any quotes (and do not care to match quotes)
|
|
|
|
|
size_t quoteStartIdx = line.find_first_of("'`<60><><EFBFBD>");
|
|
|
|
|
size_t quoteEndIdx = line.find_last_of("'`<60><><EFBFBD>");
|
|
|
|
|
|
|
|
|
|
std::string wellName;
|
|
|
|
|
bool haveAPossibleWellStart = false;
|
|
|
|
|
|
|
|
|
|
if (quoteStartIdx < line.size() -1)
|
|
|
|
|
{
|
|
|
|
|
// Extract the text between the quotes
|
|
|
|
|
wellName = line.substr(quoteStartIdx + 1, quoteEndIdx - 1 - quoteStartIdx);
|
|
|
|
|
haveAPossibleWellStart = true;
|
|
|
|
|
}
|
|
|
|
|
else if (quoteStartIdx > line.length())
|
|
|
|
|
{
|
|
|
|
|
// We did not find any quotes
|
|
|
|
|
|
|
|
|
|
// Supported alternatives are
|
|
|
|
|
// name <WellNameA>
|
|
|
|
|
// wellname: <WellNameA>
|
|
|
|
|
std::string lineLowerCase = line;
|
|
|
|
|
transform(lineLowerCase.begin(), lineLowerCase.end(), lineLowerCase.begin(), ::tolower);
|
|
|
|
|
|
|
|
|
|
std::string tokenName = "name";
|
|
|
|
|
std::size_t foundNameIdx = lineLowerCase.find(tokenName);
|
|
|
|
|
if (foundNameIdx != std::string::npos)
|
|
|
|
|
{
|
|
|
|
|
std::string tokenColon = ":";
|
|
|
|
|
std::size_t foundColonIdx = lineLowerCase.find(tokenColon, foundNameIdx);
|
|
|
|
|
if (foundColonIdx != std::string::npos)
|
|
|
|
|
{
|
|
|
|
|
wellName = line.substr(foundColonIdx + tokenColon.length());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
wellName = line.substr(foundNameIdx + tokenName.length());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
haveAPossibleWellStart = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Interpret the whole line as the well name.
|
|
|
|
|
|
|
|
|
|
QString name = line.c_str();
|
|
|
|
|
if (!name.trimmed().isEmpty())
|
|
|
|
|
{
|
|
|
|
|
wellName = name.trimmed().toStdString();
|
|
|
|
|
haveAPossibleWellStart = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (haveAPossibleWellStart)
|
|
|
|
|
{
|
|
|
|
|
// Create a new Well data if we have read some data into the previous one.
|
|
|
|
|
// if not, just overwrite the name
|
|
|
|
|
if (hasReadWellPointInCurrentWell || fileWellDataArray.size() == 0)
|
|
|
|
|
{
|
|
|
|
|
fileWellDataArray.push_back(RifWellPathImporter::WellData());
|
|
|
|
|
fileWellDataArray.back().m_wellPathGeometry = new RigWellPath();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString name = wellName.c_str();
|
|
|
|
|
if (!name.trimmed().isEmpty())
|
|
|
|
|
{
|
|
|
|
|
// Do not overwrite the name aquired from a line above, if this line is empty
|
|
|
|
|
fileWellDataArray.back().m_name = name.trimmed();
|
|
|
|
|
}
|
|
|
|
|
hasReadWellPointInCurrentWell = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RifWellPathImporter::WellData RifWellPathImporter::readAsciiWellData(const QString& filePath, size_t indexInFile)
|
|
|
|
|
{
|
|
|
|
|
readAllAsciiWellData(filePath);
|
|
|
|
|
|
|
|
|
|
std::map<QString, std::vector<RifWellPathImporter::WellData> >::iterator it = m_fileNameToWellDataGroupMap.find(filePath);
|
|
|
|
|
|
|
|
|
|
CVF_ASSERT(it != m_fileNameToWellDataGroupMap.end());
|
|
|
|
|
|
|
|
|
|
if (indexInFile < it->second.size())
|
|
|
|
|
{
|
|
|
|
|
return it->second[indexInFile];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Error : The ascii well path file does not contain that many well paths
|
|
|
|
|
return RifWellPathImporter::WellData();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
RifWellPathImporter::WellMetaData RifWellPathImporter::readAsciiWellMetaData(const QString & filePath, size_t indexInFile)
|
|
|
|
|
{
|
|
|
|
|
// No metadata in ASCII files
|
|
|
|
|
return WellMetaData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RifWellPathImporter::clear()
|
|
|
|
|
{
|
|
|
|
|
m_fileNameToWellDataGroupMap.clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
///
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
|
|
|
void RifWellPathImporter::removeFilePath(const QString& filePath)
|
|
|
|
|
{
|
|
|
|
|
m_fileNameToWellDataGroupMap.erase(filePath);
|
|
|
|
|
}
|