ResInsight/ApplicationCode/FileInterface/RifEclipseInputFileTools.cpp

1764 lines
65 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RifEclipseInputFileTools.h"
#include "RiaCellDividingTools.h"
#include "RiaLogging.h"
#include "RiaStringEncodingTools.h"
#include "RifReaderEclipseOutput.h"
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigFault.h"
#include "RigMainGrid.h"
#include "cafProgressInfo.h"
#include <cmath>
#include <fstream>
#include <iostream>
#include <vector>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include "ert/ecl/ecl_box.hpp"
#include "ert/ecl/ecl_kw.h"
#include "ert/ecl/ecl_grid.hpp"
QString includeKeyword("INCLUDE");
QString faultsKeyword("FAULTS");
QString editKeyword("EDIT");
QString gridKeyword("GRID");
QString pathsKeyword("PATHS");
//--------------------------------------------------------------------------------------------------
/// Constructor
//--------------------------------------------------------------------------------------------------
RifEclipseInputFileTools::RifEclipseInputFileTools() {}
//--------------------------------------------------------------------------------------------------
/// Destructor
//--------------------------------------------------------------------------------------------------
RifEclipseInputFileTools::~RifEclipseInputFileTools() {}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::openGridFile(const QString& fileName,
RigEclipseCaseData* eclipseCase,
bool readFaultData,
QString* errorMessages)
{
CVF_ASSERT(eclipseCase && errorMessages);
std::vector<RifKeywordAndFilePos> keywordsAndFilePos;
findKeywordsOnFile(fileName, &keywordsAndFilePos);
qint64 coordPos = -1;
qint64 zcornPos = -1;
qint64 specgridPos = -1;
qint64 actnumPos = -1;
qint64 mapaxesPos = -1;
qint64 gridunitPos = -1;
findGridKeywordPositions(keywordsAndFilePos, &coordPos, &zcornPos, &specgridPos, &actnumPos, &mapaxesPos, &gridunitPos);
if (coordPos < 0 || zcornPos < 0 || specgridPos < 0)
{
QString errorText = QString("Failed to import grid file '%1'\n").arg(fileName);
if (coordPos < 0)
{
errorText += " Missing required keyword COORD";
}
if (zcornPos < 0)
{
errorText += " Missing required keyword ZCORN";
}
if (specgridPos < 0)
{
errorText += " Missing required keyword SPECGRID";
}
*errorMessages += errorText;
return false;
}
if (gridunitPos >= 0)
{
QFile gridFile(fileName);
if (gridFile.open(QFile::ReadOnly))
{
RiaEclipseUnitTools::UnitSystem units = readUnitSystem(gridFile, gridunitPos);
if (units != RiaEclipseUnitTools::UNITS_UNKNOWN)
{
eclipseCase->setUnitsType(units);
}
}
}
FILE* gridFilePointer = util_fopen(fileName.toLatin1().data(), "r");
if (!gridFilePointer) return false;
// Main grid dimensions
// SPECGRID - This is whats normally available, but not really the input to Eclipse.
// DIMENS - Is what Eclipse expects and uses, but is not defined in the GRID section and is not (?) available normally
// ZCORN, COORD, ACTNUM, MAPAXES
// ecl_kw_type * ecl_kw_fscanf_alloc_grdecl_dynamic__( FILE * stream , const char * kw , bool strict , ecl_type_enum
// ecl_type); ecl_grid_type * ecl_grid_alloc_GRDECL_kw( int nx, int ny , int nz , const ecl_kw_type * zcorn_kw , const
// ecl_kw_type * coord_kw , const ecl_kw_type * actnum_kw , const ecl_kw_type * mapaxes_kw );
ecl_kw_type* specGridKw = nullptr;
ecl_kw_type* zCornKw = nullptr;
ecl_kw_type* coordKw = nullptr;
ecl_kw_type* actNumKw = nullptr;
ecl_kw_type* mapAxesKw = nullptr;
// Try to read all the needed keywords. Early exit if some are not found
caf::ProgressInfo progress(8, "Read Grid from Eclipse Input file");
bool allKwReadOk = true;
fseek(gridFilePointer, specgridPos, SEEK_SET);
allKwReadOk = allKwReadOk && nullptr != (specGridKw = ecl_kw_fscanf_alloc_current_grdecl__(
gridFilePointer, false, ecl_type_create_from_type(ECL_INT_TYPE)));
progress.setProgress(1);
fseek(gridFilePointer, zcornPos, SEEK_SET);
allKwReadOk = allKwReadOk && nullptr != (zCornKw = ecl_kw_fscanf_alloc_current_grdecl__(
gridFilePointer, false, ecl_type_create_from_type(ECL_FLOAT_TYPE)));
progress.setProgress(2);
fseek(gridFilePointer, coordPos, SEEK_SET);
allKwReadOk = allKwReadOk && nullptr != (coordKw = ecl_kw_fscanf_alloc_current_grdecl__(
gridFilePointer, false, ecl_type_create_from_type(ECL_FLOAT_TYPE)));
progress.setProgress(3);
// If ACTNUM is not defined, this pointer will be nullptr, which is a valid condition
if (actnumPos >= 0)
{
fseek(gridFilePointer, actnumPos, SEEK_SET);
allKwReadOk = allKwReadOk && nullptr != (actNumKw = ecl_kw_fscanf_alloc_current_grdecl__(
gridFilePointer, false, ecl_type_create_from_type(ECL_INT_TYPE)));
progress.setProgress(4);
}
// If MAPAXES is not defined, this pointer will be nullptr, which is a valid condition
if (mapaxesPos >= 0)
{
fseek(gridFilePointer, mapaxesPos, SEEK_SET);
mapAxesKw = ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false, ecl_type_create_from_type(ECL_FLOAT_TYPE));
}
if (!allKwReadOk)
{
if (specGridKw) ecl_kw_free(specGridKw);
if (zCornKw) ecl_kw_free(zCornKw);
if (coordKw) ecl_kw_free(coordKw);
if (actNumKw) ecl_kw_free(actNumKw);
if (mapAxesKw) ecl_kw_free(mapAxesKw);
return false;
}
progress.setProgress(5);
int nx = ecl_kw_iget_int(specGridKw, 0);
int ny = ecl_kw_iget_int(specGridKw, 1);
int nz = ecl_kw_iget_int(specGridKw, 2);
ecl_grid_type* inputGrid = ecl_grid_alloc_GRDECL_kw(nx, ny, nz, zCornKw, coordKw, actNumKw, mapAxesKw);
progress.setProgress(6);
RifReaderEclipseOutput::transferGeometry(inputGrid, eclipseCase);
progress.setProgress(7);
progress.setProgressDescription("Read faults ...");
if (readFaultData)
{
cvf::Collection<RigFault> faults;
RifEclipseInputFileTools::readFaults(fileName, keywordsAndFilePos, &faults);
RigMainGrid* mainGrid = eclipseCase->mainGrid();
mainGrid->setFaults(faults);
}
bool useMapAxes = ecl_grid_use_mapaxes(inputGrid);
eclipseCase->mainGrid()->setUseMapAxes(useMapAxes);
if (useMapAxes)
{
std::array<double, 6> mapAxesValues;
ecl_grid_init_mapaxes_data_double(inputGrid, mapAxesValues.data());
eclipseCase->mainGrid()->setMapAxes(mapAxesValues);
}
progress.setProgress(8);
progress.setProgressDescription("Cleaning up ...");
ecl_kw_free(specGridKw);
ecl_kw_free(zCornKw);
ecl_kw_free(coordKw);
if (actNumKw) ecl_kw_free(actNumKw);
if (mapAxesKw) ecl_kw_free(mapAxesKw);
ecl_grid_free(inputGrid);
fclose(gridFilePointer);
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::exportGrid(const QString& fileName,
RigEclipseCaseData* eclipseCase,
bool exportInLocalCoordinates,
const cvf::UByteArray* cellVisibilityOverrideForActnum,
const cvf::Vec3st& min,
const cvf::Vec3st& maxIn,
const cvf::Vec3st& refinement)
{
if (!eclipseCase)
{
return false;
}
const RigActiveCellInfo* activeCellInfo = eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL);
CVF_ASSERT(activeCellInfo);
const RigMainGrid* mainGrid = eclipseCase->mainGrid();
cvf::Vec3st max = maxIn;
if (max == cvf::Vec3st::UNDEFINED)
{
max = cvf::Vec3st(mainGrid->cellCountI() - 1, mainGrid->cellCountJ() - 1, mainGrid->cellCountK() - 1);
}
int ecl_nx = static_cast<int>((max.x() - min.x()) * refinement.x() + 1);
int ecl_ny = static_cast<int>((max.y() - min.y()) * refinement.y() + 1);
int ecl_nz = static_cast<int>((max.z() - min.z()) * refinement.z() + 1);
CVF_ASSERT(ecl_nx > 0 && ecl_ny > 0 && ecl_nz > 0);
size_t cellsPerOriginal = refinement.x() * refinement.y() * refinement.z();
caf::ProgressInfo progress(mainGrid->cellCount() * 2, "Save Eclipse Grid");
int cellProgressInterval = 1000;
std::vector<float*> ecl_corners;
ecl_corners.reserve(mainGrid->cellCount() * cellsPerOriginal);
std::vector<int*> ecl_coords;
ecl_coords.reserve(mainGrid->cellCount() * cellsPerOriginal);
std::array<float, 6> mapAxes = mainGrid->mapAxesF();
cvf::Mat4d mapAxisTrans = mainGrid->mapAxisTransform();
if (exportInLocalCoordinates)
{
cvf::Vec3d minPoint3d(mainGrid->boundingBox().min());
cvf::Vec2f minPoint2f(minPoint3d.x(), minPoint3d.y());
cvf::Vec2f origin(mapAxes[2] - minPoint2f.x(), mapAxes[3] - minPoint2f.y());
cvf::Vec2f xPoint = cvf::Vec2f(mapAxes[4], mapAxes[5]) - minPoint2f;
cvf::Vec2f yPoint = cvf::Vec2f(mapAxes[0], mapAxes[1]) - minPoint2f;
mapAxes = { yPoint.x(), yPoint.y(), origin.x(), origin.y(), xPoint.x(), xPoint.y() };
mapAxisTrans.setTranslation(mapAxisTrans.translation() - minPoint3d);
}
const size_t* cellMappingECLRi = RifReaderEclipseOutput::eclipseCellIndexMapping();
int incrementalIndex = 0;
for (size_t k = min.z() * refinement.z(); k <= max.z() * refinement.z(); ++k)
{
size_t mainK = k / refinement.z();
size_t k0 = k - min.z() * refinement.z();
for (size_t j = min.y() * refinement.y(); j <= max.y() * refinement.y(); ++j)
{
size_t mainJ = j / refinement.y();
size_t j0 = j - min.y() * refinement.y();
for (size_t i = min.x() * refinement.x(); i <= max.x() * refinement.x(); ++i)
{
size_t mainI = i / refinement.x();
size_t i0 = i - min.x() * refinement.x();
size_t mainIndex = mainGrid->cellIndexFromIJK(mainI, mainJ, mainK);
int active = activeCellInfo->isActive(mainIndex) ? 1 : 0;
if (active && cellVisibilityOverrideForActnum)
{
active = (*cellVisibilityOverrideForActnum)[mainIndex];
}
int* ecl_cell_coords = new int[5];
ecl_cell_coords[0] = (int)(i0 + 1);
ecl_cell_coords[1] = (int)(j0 + 1);
ecl_cell_coords[2] = (int)(k0 + 1);
ecl_cell_coords[3] = incrementalIndex++;
ecl_cell_coords[4] = active;
ecl_coords.push_back(ecl_cell_coords);
std::array<cvf::Vec3d, 8> cellCorners;
mainGrid->cellCornerVertices(mainIndex, cellCorners.data());
if (mainGrid->useMapAxes())
{
for (cvf::Vec3d& corner : cellCorners)
{
corner.transformPoint(mapAxisTrans);
}
}
auto refinedCoords =
RiaCellDividingTools::createHexCornerCoords(cellCorners, refinement.x(), refinement.y(), refinement.z());
size_t subI = i % refinement.x();
size_t subJ = j % refinement.y();
size_t subK = k % refinement.z();
size_t subIndex = subI + subJ * refinement.x() + subK * refinement.x() * refinement.y();
float* ecl_cell_corners = new float[24];
for (size_t cIdx = 0; cIdx < 8; ++cIdx)
{
cvf::Vec3d cellCorner = refinedCoords[subIndex * 8 + cIdx];
ecl_cell_corners[cellMappingECLRi[cIdx] * 3] = cellCorner[0];
ecl_cell_corners[cellMappingECLRi[cIdx] * 3 + 1] = cellCorner[1];
ecl_cell_corners[cellMappingECLRi[cIdx] * 3 + 2] = -cellCorner[2];
}
ecl_corners.push_back(ecl_cell_corners);
}
}
if (incrementalIndex % cellProgressInterval == 0)
{
progress.setProgress(incrementalIndex / cellsPerOriginal);
}
}
// Do not perform the transformation (applyMapaxes == false):
// The coordinates have been transformed to the mapaxes coordinate system already.
// However, send the mapaxes data in to libecl so that the coordinate system description is saved.
bool applyMapaxes = false;
ecl_grid_type* mainEclGrid =
ecl_grid_alloc_GRID_data((int)ecl_coords.size(), ecl_nx, ecl_ny, ecl_nz, 5, &ecl_coords[0], &ecl_corners[0], applyMapaxes, mapAxes.data());
progress.setProgress(mainGrid->cellCount());
for (float* floatArray : ecl_corners)
{
delete floatArray;
}
for (int* intArray : ecl_coords)
{
delete intArray;
}
FILE* filePtr = util_fopen(RiaStringEncodingTools::toNativeEncoded(fileName).data(), "w");
if (!filePtr)
{
return false;
}
ert_ecl_unit_enum ecl_units = ECL_METRIC_UNITS;
if (eclipseCase->unitsType() == RiaEclipseUnitTools::UNITS_FIELD)
ecl_units = ECL_FIELD_UNITS;
else if (eclipseCase->unitsType() == RiaEclipseUnitTools::UNITS_LAB)
ecl_units = ECL_LAB_UNITS;
ecl_grid_fprintf_grdecl2(mainEclGrid, filePtr, ecl_units);
ecl_grid_free(mainEclGrid);
fclose(filePtr);
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::exportKeywords(const QString& resultFileName,
RigEclipseCaseData* eclipseCase,
const std::vector<QString>& keywords,
const QString& fileWriteMode,
const cvf::Vec3st& min,
const cvf::Vec3st& maxIn,
const cvf::Vec3st& refinement)
{
FILE* filePtr = util_fopen(RiaStringEncodingTools::toNativeEncoded(resultFileName).data(),
RiaStringEncodingTools::toNativeEncoded(fileWriteMode).data());
if (!filePtr)
{
return false;
}
RigCaseCellResultsData* cellResultsData = eclipseCase->results(RiaDefines::MATRIX_MODEL);
RigActiveCellInfo* activeCells = cellResultsData->activeCellInfo();
RigMainGrid* mainGrid = eclipseCase->mainGrid();
cvf::Vec3st max = maxIn;
if (max == cvf::Vec3st::UNDEFINED)
{
max = cvf::Vec3st(mainGrid->cellCountI() - 1, mainGrid->cellCountJ() - 1, mainGrid->cellCountK() - 1);
}
caf::ProgressInfo progress(keywords.size(), "Saving Keywords");
for (const QString& keyword : keywords)
{
std::vector<double> resultValues;
RigEclipseResultAddress resAddr(RiaDefines::STATIC_NATIVE, keyword);
if (!cellResultsData->hasResultEntry(resAddr)) continue;
cellResultsData->ensureKnownResultLoaded(resAddr);
CVF_ASSERT(!cellResultsData->cellScalarResults(resAddr).empty());
resultValues = cellResultsData->cellScalarResults(resAddr)[0];
CVF_ASSERT(!resultValues.empty());
if (resultValues.empty()) continue;
std::vector<double> filteredResults;
filteredResults.reserve(resultValues.size());
for (size_t k = min.z() * refinement.z(); k <= max.z() * refinement.z(); ++k)
{
size_t mainK = k / refinement.z();
for (size_t j = min.y() * refinement.y(); j <= max.y() * refinement.y(); ++j)
{
size_t mainJ = j / refinement.y();
for (size_t i = min.x() * refinement.x(); i <= max.x() * refinement.x(); ++i)
{
size_t mainI = i / refinement.x();
size_t mainIndex = mainGrid->cellIndexFromIJK(mainI, mainJ, mainK);
size_t resIndex = activeCells->cellResultIndex(mainIndex);
if (resIndex != cvf::UNDEFINED_SIZE_T)
{
filteredResults.push_back(resultValues[resIndex]);
}
}
}
}
ecl_kw_type* ecl_kw = nullptr;
if (keyword.endsWith("NUM"))
{
std::vector<int> resultValuesInt;
resultValuesInt.reserve(filteredResults.size());
for (double val : filteredResults)
{
resultValuesInt.push_back(static_cast<int>(val));
}
ecl_kw = ecl_kw_alloc_new(keyword.toLatin1().data(), (int)resultValuesInt.size(), ECL_INT, resultValuesInt.data());
}
else
{
std::vector<float> resultValuesFloat;
resultValuesFloat.reserve(filteredResults.size());
for (double val : filteredResults)
{
resultValuesFloat.push_back(static_cast<float>(val));
}
ecl_kw =
ecl_kw_alloc_new(keyword.toLatin1().data(), (int)resultValuesFloat.size(), ECL_FLOAT, resultValuesFloat.data());
}
ecl_kw_fprintf_grdecl(ecl_kw, filePtr);
ecl_kw_free(ecl_kw);
progress.incrementProgress();
}
fclose(filePtr);
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::saveFault(QString completeFilename,
const RigMainGrid* mainGrid,
const std::vector<RigFault::FaultFace>& faultFaces,
QString faultName,
const cvf::Vec3st& min,
const cvf::Vec3st& maxIn,
const cvf::Vec3st& refinement)
{
QFile exportFile(completeFilename);
if (!exportFile.open(QIODevice::WriteOnly | QIODevice::Text))
{
RiaLogging::error("Could not open the file : " + completeFilename);
}
QTextStream stream(&exportFile);
stream << "FAULTS" << endl;
stream << "-- Name I1 I2 J1 J2 K1 K2 Face ( I/J/K )" << endl;
saveFault(stream, mainGrid, faultFaces, faultName, min, maxIn, refinement);
stream << "/" << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::saveFault(QTextStream& stream,
const RigMainGrid* mainGrid,
const std::vector<RigFault::FaultFace>& faultFaces,
QString faultName,
const cvf::Vec3st& min,
const cvf::Vec3st& maxIn,
const cvf::Vec3st& refinement)
{
// 'NAME' 1 1 1 1 1 2 J /
if (faultName.contains(' '))
{
RiaLogging::error(QString("Fault name '%1' contains spaces").arg(faultName));
return;
}
else if (faultName.length() > 8)
{
// Keep going anyway, eclipse files sometimes have longer than
// the specified 8 characters in the name without Eclipse complaining
RiaLogging::warning(QString("Fault name '%1' is longer than 8 characters").arg(faultName));
}
std::vector<RigFault::CellAndFace> faultCellAndFaces;
cvf::Vec3st max = maxIn;
if (max == cvf::Vec3st::UNDEFINED)
{
max = cvf::Vec3st(mainGrid->cellCountI() - 1, mainGrid->cellCountJ() - 1, mainGrid->cellCountK() - 1);
}
for (const RigFault::FaultFace& faultCellAndFace : faultFaces)
{
size_t i, j, k;
bool ok = mainGrid->ijkFromCellIndex(faultCellAndFace.m_nativeReservoirCellIndex, &i, &j, &k);
if (!ok) continue;
if (i < min.x() || i > max.x() || j < min.y() || j > max.y() || k < min.z() || k > max.z()) continue;
size_t shifted_i = (i - min.x()) * refinement.x();
size_t shifted_j = (j - min.y()) * refinement.y();
size_t shifted_k = (k - min.z()) * refinement.z();
// 2x2 Refinement of Original Cell 0, 0
// Y/J POS_J boundary
// ^ _______________
// | | | |
// | | 0,1 | 1,1 |
// | |_______|_______| POS_I boundary
// | | | |
// | | 0,0 | 1,0 |
// | |_______|_______|
// ---------------------> X/I
// NEG_J boundary
//
// POS_J gets shifted 1 index in J direction, NEG_J stays the same in J but spans two I.
// POS_I gets shifted 1 index in I direction, NEG_I stays the same in I but spans two J.
if (refinement != cvf::Vec3st(1, 1, 1))
{
if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_I ||
faultCellAndFace.m_nativeFace == cvf::StructGridInterface::NEG_I)
{
if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_I)
{
shifted_i += refinement.x() - 1;
}
for (size_t refineK = 0; refineK < refinement.z(); ++refineK)
{
for (size_t refineJ = 0; refineJ < refinement.y(); ++refineJ)
{
faultCellAndFaces.push_back(
std::make_tuple(shifted_i, shifted_j + refineJ, shifted_k + refineK, faultCellAndFace.m_nativeFace));
}
}
}
else if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_J ||
faultCellAndFace.m_nativeFace == cvf::StructGridInterface::NEG_J)
{
if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_J)
{
shifted_j += refinement.y() - 1;
}
for (size_t refineK = 0; refineK < refinement.z(); ++refineK)
{
for (size_t refineI = 0; refineI < refinement.x(); ++refineI)
{
faultCellAndFaces.push_back(
std::make_tuple(shifted_i + refineI, shifted_j, shifted_k + refineK, faultCellAndFace.m_nativeFace));
}
}
}
else if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_K ||
faultCellAndFace.m_nativeFace == cvf::StructGridInterface::NEG_K)
{
if (faultCellAndFace.m_nativeFace == cvf::StructGridInterface::POS_K)
{
shifted_k += refinement.z() - 1;
}
for (size_t refineJ = 0; refineJ < refinement.y(); ++refineJ)
{
for (size_t refineI = 0; refineI < refinement.x(); ++refineI)
{
faultCellAndFaces.push_back(
std::make_tuple(shifted_i + refineI, shifted_j + refineJ, shifted_k, faultCellAndFace.m_nativeFace));
}
}
}
}
else
{
faultCellAndFaces.push_back(std::make_tuple(shifted_i, shifted_j, shifted_k, faultCellAndFace.m_nativeFace));
}
}
// Sort order: i, j, face then k.
std::sort(faultCellAndFaces.begin(), faultCellAndFaces.end(), RigFault::ordering);
size_t lastI = std::numeric_limits<size_t>::max();
size_t lastJ = std::numeric_limits<size_t>::max();
size_t lastK = std::numeric_limits<size_t>::max();
size_t startK = std::numeric_limits<size_t>::max();
cvf::StructGridInterface::FaceType lastFaceType = cvf::StructGridInterface::FaceType::NO_FACE;
for (const RigFault::CellAndFace& faultCellAndFace : faultCellAndFaces)
{
size_t i, j, k;
cvf::StructGridInterface::FaceType faceType;
std::tie(i, j, k, faceType) = faultCellAndFace;
if (i != lastI || j != lastJ || lastFaceType != faceType || k != lastK + 1)
{
// No fault should have no face
if (lastFaceType != cvf::StructGridInterface::FaceType::NO_FACE)
{
writeFaultLine(stream, faultName, lastI, lastJ, startK, lastK, lastFaceType);
}
lastI = i;
lastJ = j;
lastK = k;
lastFaceType = faceType;
startK = k;
}
else
{
lastK = k;
}
}
// No fault should have no face
if (lastFaceType != cvf::StructGridInterface::FaceType::NO_FACE)
{
writeFaultLine(stream, faultName, lastI, lastJ, startK, lastK, lastFaceType);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::saveFaults(QTextStream& stream,
const RigMainGrid* mainGrid,
const cvf::Vec3st& min /*= cvf::Vec3st::ZERO*/,
const cvf::Vec3st& max /*= cvf::Vec3st::UNDEFINED*/,
const cvf::Vec3st& refinement /*= cvf::Vec3st(1, 1, 1)*/)
{
stream << "FAULTS" << endl;
stream << "-- Name I1 I2 J1 J2 K1 K2 Face ( I/J/K )" << endl;
const cvf::Collection<RigFault>& faults = mainGrid->faults();
for (const auto fault : faults)
{
if (fault->name() != RiaDefines::undefinedGridFaultName() &&
fault->name() != RiaDefines::undefinedGridFaultWithInactiveName())
{
saveFault(stream, mainGrid, fault->faultFaces(), fault->name(), min, max, refinement);
}
}
stream << "/" << endl;
}
//--------------------------------------------------------------------------------------------------
/// Read known properties from the input file
//--------------------------------------------------------------------------------------------------
std::map<QString, QString> RifEclipseInputFileTools::readProperties(const QString& fileName, RigEclipseCaseData* caseData)
{
CVF_ASSERT(caseData);
caf::ProgressInfo mainProgress(2, "Reading Eclipse Input properties");
std::vector<RifKeywordAndFilePos> fileKeywords;
RifEclipseInputFileTools::findKeywordsOnFile(fileName, &fileKeywords);
if (!fileKeywords.size())
{
RiaLogging::warning(QString("No keywords found in file: %1").arg(fileName));
}
mainProgress.setProgress(1);
caf::ProgressInfo progress(fileKeywords.size(), "Reading properties");
FILE* gridFilePointer = util_fopen(fileName.toLatin1().data(), "r");
if (!gridFilePointer)
{
RiaLogging::warning(QString("Could not open file: %1").arg(fileName));
return std::map<QString, QString>();
}
std::map<QString, QString> newResults;
for (size_t i = 0; i < fileKeywords.size(); ++i)
{
if (!isValidDataKeyword(fileKeywords[i].keyword))
{
continue;
}
fseek(gridFilePointer, fileKeywords[i].filePos, SEEK_SET);
ecl_kw_type* eclipseKeywordData =
ecl_kw_fscanf_alloc_current_grdecl__(gridFilePointer, false, ecl_type_create_from_type(ECL_FLOAT_TYPE));
if (eclipseKeywordData)
{
QString newResultName = caseData->results(RiaDefines::MATRIX_MODEL)->makeResultNameUnique(fileKeywords[i].keyword);
QString errMsg;
if (readDataFromKeyword(eclipseKeywordData, caseData, newResultName, &errMsg))
{
newResults[newResultName] = fileKeywords[i].keyword;
}
else
{
RiaLogging::error(QString("Failed to read keyword: %1").arg(errMsg));
}
ecl_kw_free(eclipseKeywordData);
}
else
{
RiaLogging::error(QString("Failed to allocate keyword: %1").arg(fileKeywords[i].keyword));
}
progress.setProgress(i);
}
fclose(gridFilePointer);
return newResults;
}
//--------------------------------------------------------------------------------------------------
/// Reads the property data requested into the \a reservoir, overwriting any previous
/// properties with the same name.
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::readProperty(const QString& fileName,
RigEclipseCaseData* caseData,
const QString& eclipseKeyWord,
const QString& resultName)
{
CVF_ASSERT(caseData);
if (!isValidDataKeyword(eclipseKeyWord)) return false;
FILE* filePointer = util_fopen(fileName.toLatin1().data(), "r");
if (!filePointer)
{
RiaLogging::error(QString("Could not open property file: %1").arg(fileName));
return false;
}
ecl_kw_type* eclipseKeywordData = ecl_kw_fscanf_alloc_grdecl_dynamic__(
filePointer, eclipseKeyWord.toLatin1().data(), false, ecl_type_create_from_type(ECL_FLOAT_TYPE));
bool isOk = false;
if (eclipseKeywordData)
{
QString errMsg;
isOk = readDataFromKeyword(eclipseKeywordData, caseData, resultName, &errMsg);
if (!isOk)
{
RiaLogging::error(QString("Failed to read property: %1").arg(errMsg));
}
ecl_kw_free(eclipseKeywordData);
}
else
{
RiaLogging::error(QString("Failed to load keyword %1 from file: %2").arg(eclipseKeyWord).arg(fileName));
}
fclose(filePointer);
return isOk;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::readDataFromKeyword(ecl_kw_type* eclipseKeywordData,
RigEclipseCaseData* caseData,
const QString& resultName,
QString* errMsg)
{
CVF_ASSERT(caseData);
CVF_ASSERT(eclipseKeywordData);
CVF_ASSERT(errMsg);
bool mathingItemCount = false;
size_t keywordItemCount = 0u;
{
keywordItemCount = static_cast<size_t>(ecl_kw_get_size(eclipseKeywordData));
if (keywordItemCount == caseData->mainGrid()->cellCount())
{
mathingItemCount = true;
}
if (keywordItemCount == caseData->activeCellInfo(RiaDefines::MATRIX_MODEL)->reservoirActiveCellCount())
{
mathingItemCount = true;
}
}
if (!mathingItemCount)
{
QString errFormat("Size mismatch: Main Grid has %1 cells, keyword %2 has %3 cells");
*errMsg = errFormat.arg(caseData->mainGrid()->cellCount()).arg(resultName).arg(keywordItemCount);
return false;
}
RigEclipseResultAddress resAddr(RiaDefines::INPUT_PROPERTY, resultName);
caseData->results(RiaDefines::MATRIX_MODEL)->createResultEntry(resAddr, false);
std::vector<std::vector<double>>& newPropertyData =
caseData->results(RiaDefines::MATRIX_MODEL)->modifiableCellScalarResultTimesteps(resAddr);
newPropertyData.push_back(std::vector<double>());
newPropertyData[0].resize(ecl_kw_get_size(eclipseKeywordData), HUGE_VAL);
ecl_kw_get_data_as_double(eclipseKeywordData, newPropertyData[0].data());
return true;
}
//--------------------------------------------------------------------------------------------------
/// Read all the keywords from a file
//
// This code was originally written using QTextStream, but due to a bug in Qt version up to 4.8.0
// we had to implement the reading using QFile and QFile::readLine
//
// See:
// https://bugreports.qt-project.org/browse/QTBUG-9814
//
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::findKeywordsOnFile(const QString& fileName, std::vector<RifKeywordAndFilePos>* keywords)
{
char buf[1024];
QFile data(fileName);
data.open(QFile::ReadOnly);
QString line;
qint64 filepos = -1;
qint64 lineLength = -1;
do
{
lineLength = data.readLine(buf, sizeof(buf));
if (lineLength > 0)
{
line = QString::fromLatin1(buf);
if (line.size() && line[0].isLetter())
{
RifKeywordAndFilePos keyPos;
filepos = data.pos() - lineLength;
keyPos.filePos = filepos;
QString keywordCandidate = line;
int commentStart = keywordCandidate.indexOf("--");
if (commentStart > 0)
{
keywordCandidate = keywordCandidate.left(commentStart);
}
keywordCandidate = keywordCandidate.trimmed();
keyPos.keyword = keywordCandidate;
keywords->push_back(keyPos);
// qDebug() << keyPos.keyword << " - " << keyPos.filePos;
}
}
} while (lineLength != -1);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::parseAndReadPathAliasKeyword(const QString& fileName,
std::vector<std::pair<QString, QString>>* pathAliasDefinitions)
{
char buf[1024];
QFile data(fileName);
data.open(QFile::ReadOnly);
QString line;
bool foundPathsKeyword = false;
do
{
qint64 lineLength = data.readLine(buf, sizeof(buf));
if (lineLength > 0)
{
line = QString::fromLatin1(buf);
if (line.size() && (line[0].isLetter() || foundPathsKeyword))
{
line = line.trimmed();
if (line == gridKeyword)
{
return;
}
else if (line == pathsKeyword)
{
foundPathsKeyword = true;
}
else if (foundPathsKeyword)
{
if (line.startsWith("/", Qt::CaseInsensitive))
{
// Detected end of keyword data section
return;
}
else if (line.startsWith("--", Qt::CaseInsensitive))
{
continue;
}
else
{
// Replace tab with space to be able to split the string using space as splitter
line.replace("\t", " ");
// Remove character ' used to mark start and end of fault name, possibly also around face definition; 'I+'
line.remove("'");
QStringList entries = line.split(" ", QString::SkipEmptyParts);
if (entries.size() < 2)
{
continue;
}
pathAliasDefinitions->push_back(std::make_pair(entries[0], entries[1]));
}
}
}
}
} while (!data.atEnd());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const std::vector<QString>& RifEclipseInputFileTools::invalidPropertyDataKeywords()
{
static std::vector<QString> keywords;
static bool isInitialized = false;
if (!isInitialized)
{
// Related to geometry
keywords.push_back("COORD");
keywords.push_back("ZCORN");
keywords.push_back("SPECGRID");
keywords.push_back("MAPAXES");
keywords.push_back("NOECHO");
keywords.push_back("MAPUNITS");
keywords.push_back("GRIDUNIT");
keywords.push_back(faultsKeyword);
isInitialized = true;
}
return keywords;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::findGridKeywordPositions(const std::vector<RifKeywordAndFilePos>& keywords,
qint64* coordPos,
qint64* zcornPos,
qint64* specgridPos,
qint64* actnumPos,
qint64* mapaxesPos,
qint64* gridunitPos)
{
CVF_ASSERT(coordPos && zcornPos && specgridPos && actnumPos && mapaxesPos && gridunitPos);
size_t i;
for (i = 0; i < keywords.size(); i++)
{
if (keywords[i].keyword == "COORD")
{
*coordPos = keywords[i].filePos;
}
else if (keywords[i].keyword == "ZCORN")
{
*zcornPos = keywords[i].filePos;
}
else if (keywords[i].keyword == "SPECGRID")
{
*specgridPos = keywords[i].filePos;
}
else if (keywords[i].keyword == "ACTNUM")
{
*actnumPos = keywords[i].filePos;
}
else if (keywords[i].keyword == "MAPAXES")
{
*mapaxesPos = keywords[i].filePos;
}
else if (keywords[i].keyword == "GRIDUNIT")
{
*gridunitPos = keywords[i].filePos;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::readFaults(const QString& fileName,
const std::vector<RifKeywordAndFilePos>& fileKeywords,
cvf::Collection<RigFault>* faults)
{
QFile data(fileName);
if (!data.open(QFile::ReadOnly))
{
return;
}
for (size_t i = 0; i < fileKeywords.size(); i++)
{
if (fileKeywords[i].keyword.compare(editKeyword, Qt::CaseInsensitive) == 0)
{
return;
}
else if (fileKeywords[i].keyword.compare(faultsKeyword, Qt::CaseInsensitive) != 0)
{
continue;
}
qint64 filePos = fileKeywords[i].filePos;
bool isEditKeywordDetected = false;
readFaults(data, filePos, faults, &isEditKeywordDetected);
if (isEditKeywordDetected)
{
return;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::parseAndReadFaults(const QString& fileName, cvf::Collection<RigFault>* faults)
{
QFile data(fileName);
if (!data.open(QFile::ReadOnly))
{
return;
}
qint64 filePos = findKeyword(faultsKeyword, data, 0);
while (filePos != -1)
{
readFaults(data, filePos, faults, nullptr);
filePos = findKeyword(faultsKeyword, data, filePos);
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::readFaultsInGridSection(const QString& fileName,
cvf::Collection<RigFault>* faults,
std::vector<QString>* filenamesWithFaults,
const QString& faultIncludeFileAbsolutePathPrefix)
{
QFile data(fileName);
if (!data.open(QFile::ReadOnly))
{
return;
}
// Search for keyword grid
qint64 gridPos = findKeyword(gridKeyword, data, 0);
if (gridPos < 0)
{
return;
}
bool isEditKeywordDetected = false;
std::vector<std::pair<QString, QString>> pathAliasDefinitions;
parseAndReadPathAliasKeyword(fileName, &pathAliasDefinitions);
readFaultsAndParseIncludeStatementsRecursively(data,
gridPos,
pathAliasDefinitions,
faults,
filenamesWithFaults,
&isEditKeywordDetected,
faultIncludeFileAbsolutePathPrefix);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RifEclipseInputFileTools::findFaultByName(const cvf::Collection<RigFault>& faults, const QString& name)
{
for (size_t i = 0; i < faults.size(); i++)
{
if (faults.at(i)->name() == name)
{
return i;
}
}
return cvf::UNDEFINED_SIZE_T;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
qint64 RifEclipseInputFileTools::findKeyword(const QString& keyword, QFile& file, qint64 startPos)
{
QString line;
file.seek(startPos);
do
{
line = file.readLine();
line = line.trimmed();
if (line.startsWith("--", Qt::CaseInsensitive))
{
continue;
}
if (line.startsWith(keyword, Qt::CaseInsensitive))
{
return file.pos();
}
} while (!file.atEnd());
return -1;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::isValidDataKeyword(const QString& keyword)
{
const std::vector<QString>& keywordsToSkip = RifEclipseInputFileTools::invalidPropertyDataKeywords();
for (const QString keywordToSkip : keywordsToSkip)
{
if (keywordToSkip == keyword.toUpper())
{
return false;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::writeFaultLine(QTextStream& stream,
QString faultName,
size_t i,
size_t j,
size_t startK,
size_t endK,
cvf::StructGridInterface::FaceType faceType)
{
// Convert indices to eclipse format
i++;
j++;
startK++;
endK++;
stream << "'" << faultName << "'"
<< " " << i << " " << i << " " << j << " " << j << " " << startK << " " << endK << " "
<< faultFaceText(faceType) << " / ";
stream << endl;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RifEclipseInputFileTools::faultFaceText(cvf::StructGridInterface::FaceType faceType)
{
switch (faceType)
{
case cvf::StructGridInterface::POS_I:
return QString(" I");
case cvf::StructGridInterface::NEG_I:
return QString("-I");
case cvf::StructGridInterface::POS_J:
return QString(" J");
case cvf::StructGridInterface::NEG_J:
return QString("-J");
case cvf::StructGridInterface::POS_K:
return QString(" K");
case cvf::StructGridInterface::NEG_K:
return QString("-K");
default:
CVF_ASSERT(false);
}
return "";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::readFaultsAndParseIncludeStatementsRecursively(
QFile& file,
qint64 startPos,
const std::vector<std::pair<QString, QString>>& pathAliasDefinitions,
cvf::Collection<RigFault>* faults,
std::vector<QString>* filenamesWithFaults,
bool* isEditKeywordDetected,
const QString& faultIncludeFileAbsolutePathPrefix)
{
QString line;
if (!file.seek(startPos))
{
return false;
}
bool continueParsing = true;
do
{
line = file.readLine();
line = line.trimmed();
if (line.startsWith("--", Qt::CaseInsensitive))
{
continue;
}
else if (line.startsWith(editKeyword, Qt::CaseInsensitive))
{
if (isEditKeywordDetected)
{
*isEditKeywordDetected = true;
}
return false;
}
if (line.startsWith(includeKeyword, Qt::CaseInsensitive))
{
line = file.readLine();
line = line.trimmed();
while (line.startsWith("--", Qt::CaseInsensitive))
{
line = file.readLine();
line = line.trimmed();
}
int firstQuote = line.indexOf("'");
int lastQuote = line.lastIndexOf("'");
if (!(firstQuote < 0 || lastQuote < 0 || firstQuote == lastQuote))
{
QDir currentFileFolder;
{
QFileInfo fi(file.fileName());
currentFileFolder = fi.absoluteDir();
}
// Read include file name, and both relative and absolute path is supported
QString includeFilename = line.mid(firstQuote + 1, lastQuote - firstQuote - 1);
for (auto entry : pathAliasDefinitions)
{
QString textToReplace = "$" + entry.first;
includeFilename.replace(textToReplace, entry.second);
}
#ifdef WIN32
if (includeFilename.startsWith('/'))
{
// Absolute UNIX path, prefix on Windows
includeFilename = faultIncludeFileAbsolutePathPrefix + includeFilename;
}
#endif
QFileInfo fi(currentFileFolder, includeFilename);
if (fi.exists())
{
QString absoluteFilename = fi.canonicalFilePath();
QFile includeFile(absoluteFilename);
if (includeFile.open(QFile::ReadOnly))
{
// qDebug() << "Found include statement, and start parsing of\n " << absoluteFilename;
if (!readFaultsAndParseIncludeStatementsRecursively(includeFile,
0,
pathAliasDefinitions,
faults,
filenamesWithFaults,
isEditKeywordDetected,
faultIncludeFileAbsolutePathPrefix))
{
qDebug() << "Error when parsing include file : " << absoluteFilename;
}
}
}
}
}
else if (line.startsWith(faultsKeyword, Qt::CaseInsensitive))
{
if (!line.contains("/"))
{
readFaults(file, file.pos(), faults, isEditKeywordDetected);
filenamesWithFaults->push_back(file.fileName());
}
}
if (isEditKeywordDetected && *isEditKeywordDetected)
{
continueParsing = false;
}
if (file.atEnd())
{
continueParsing = false;
}
} while (continueParsing);
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseInputFileTools::readKeywordAndParseIncludeStatementsRecursively(
const QString& keyword,
const QString& keywordToStopParsing,
QFile& file,
qint64 startPos,
const std::vector<std::pair<QString, QString>>& pathAliasDefinitions,
QStringList* keywordDataContent,
std::vector<QString>* filenamesContainingKeyword,
bool* isStopParsingKeywordDetected,
const QString& faultIncludeFileAbsolutePathPrefix /* rename to includeStatementAbsolutePathPrefix */)
{
QString line;
if (!file.seek(startPos))
{
return false;
}
bool continueParsing = true;
do
{
line = file.readLine();
line = line.trimmed();
if (line.startsWith("--", Qt::CaseInsensitive))
{
continue;
}
if (!keywordToStopParsing.isEmpty() && line.startsWith(keywordToStopParsing, Qt::CaseInsensitive))
{
if (isStopParsingKeywordDetected)
{
*isStopParsingKeywordDetected = true;
}
return false;
}
if (line.startsWith(includeKeyword, Qt::CaseInsensitive))
{
line = file.readLine();
line = line.trimmed();
while (line.startsWith("--", Qt::CaseInsensitive))
{
line = file.readLine();
line = line.trimmed();
}
int firstQuote = line.indexOf("'");
int lastQuote = line.lastIndexOf("'");
if (!(firstQuote < 0 || lastQuote < 0 || firstQuote == lastQuote))
{
QDir currentFileFolder;
{
QFileInfo fi(file.fileName());
currentFileFolder = fi.absoluteDir();
}
// Read include file name, and both relative and absolute path is supported
QString includeFilename = line.mid(firstQuote + 1, lastQuote - firstQuote - 1);
for (auto entry : pathAliasDefinitions)
{
QString textToReplace = "$" + entry.first;
includeFilename.replace(textToReplace, entry.second);
}
#ifdef WIN32
if (includeFilename.startsWith('/'))
{
// Absolute UNIX path, prefix on Windows
includeFilename = faultIncludeFileAbsolutePathPrefix + includeFilename;
}
#endif
QFileInfo fi(currentFileFolder, includeFilename);
if (fi.exists())
{
QString absoluteFilename = fi.canonicalFilePath();
QFile includeFile(absoluteFilename);
if (includeFile.open(QFile::ReadOnly))
{
// qDebug() << "Found include statement, and start parsing of\n " << absoluteFilename;
if (!readKeywordAndParseIncludeStatementsRecursively(keyword,
keywordToStopParsing,
includeFile,
0,
pathAliasDefinitions,
keywordDataContent,
filenamesContainingKeyword,
isStopParsingKeywordDetected,
faultIncludeFileAbsolutePathPrefix))
{
qDebug() << "Error when parsing include file : " << absoluteFilename;
}
}
}
}
}
else if (line.startsWith(keyword, Qt::CaseInsensitive))
{
if (!line.contains("/"))
{
readKeywordDataContent(file, file.pos(), keywordDataContent, isStopParsingKeywordDetected);
filenamesContainingKeyword->push_back(file.fileName());
}
}
if (isStopParsingKeywordDetected && *isStopParsingKeywordDetected)
{
continueParsing = false;
}
if (file.atEnd())
{
continueParsing = false;
}
} while (continueParsing);
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::readKeywordDataContent(QFile& data,
qint64 filePos,
QStringList* textContent,
bool* isEditKeywordDetected)
{
if (!data.seek(filePos))
{
return;
}
// This function assumes the keyword is read from file, and the file pointer is pointing to the first line containing data for
// the keyword
do
{
QString line = data.readLine();
line = line.trimmed();
if (line.startsWith("--", Qt::CaseInsensitive))
{
// Skip comment lines
continue;
}
else if (line.startsWith("/", Qt::CaseInsensitive))
{
// Detected end of keyword data section
return;
}
else if (line.startsWith(editKeyword, Qt::CaseInsensitive))
{
// End parsing when edit keyword is detected
if (isEditKeywordDetected)
{
*isEditKeywordDetected = true;
}
return;
}
textContent->push_back(line);
} while (!data.atEnd());
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaEclipseUnitTools::UnitSystem RifEclipseInputFileTools::readUnitSystem(QFile& file, qint64 gridunitPos)
{
bool stopParsing = false;
QStringList unitText;
readKeywordDataContent(file, gridunitPos, &unitText, &stopParsing);
for (QString unitString : unitText)
{
if (unitString.contains("FEET", Qt::CaseInsensitive))
{
return RiaEclipseUnitTools::UNITS_FIELD;
}
else if (unitString.contains("CM", Qt::CaseInsensitive))
{
return RiaEclipseUnitTools::UNITS_LAB;
}
else if (unitString.contains("MET", Qt::CaseInsensitive))
{
return RiaEclipseUnitTools::UNITS_METRIC;
}
}
return RiaEclipseUnitTools::UNITS_UNKNOWN;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::StructGridInterface::FaceEnum RifEclipseInputFileTools::faceEnumFromText(const QString& faceString)
{
QString upperCaseText = faceString.toUpper().trimmed();
if (upperCaseText.size() > 1)
{
QString firstTwoChars = upperCaseText.mid(0, 2);
if (firstTwoChars == "X+" || firstTwoChars == "I+") return cvf::StructGridInterface::POS_I;
if (firstTwoChars == "Y+" || firstTwoChars == "J+") return cvf::StructGridInterface::POS_J;
if (firstTwoChars == "Z+" || firstTwoChars == "K+") return cvf::StructGridInterface::POS_K;
if (firstTwoChars == "X-" || firstTwoChars == "I-") return cvf::StructGridInterface::NEG_I;
if (firstTwoChars == "Y-" || firstTwoChars == "J-") return cvf::StructGridInterface::NEG_J;
if (firstTwoChars == "Z-" || firstTwoChars == "K-") return cvf::StructGridInterface::NEG_K;
}
if (upperCaseText.size() > 0)
{
QString firstChar = upperCaseText.mid(0, 1);
if (firstChar == "X" || firstChar == "I") return cvf::StructGridInterface::POS_I;
if (firstChar == "Y" || firstChar == "J") return cvf::StructGridInterface::POS_J;
if (firstChar == "Z" || firstChar == "K") return cvf::StructGridInterface::POS_K;
}
return cvf::StructGridInterface::NO_FACE;
}
//--------------------------------------------------------------------------------------------------
/// The file pointer is pointing at the line following the FAULTS keyword.
/// Parse content of this keyword until end of file or
/// end of keyword when a single line with '/' is found
//--------------------------------------------------------------------------------------------------
void RifEclipseInputFileTools::readFaults(QFile& data,
qint64 filePos,
cvf::Collection<RigFault>* faults,
bool* isEditKeywordDetected)
{
if (!data.seek(filePos))
{
return;
}
// qDebug() << "Reading faults from\n " << data.fileName();
RigFault* fault = nullptr;
do
{
QString line = data.readLine();
line = line.trimmed();
if (line.startsWith("--", Qt::CaseInsensitive))
{
// Skip comment lines
continue;
}
else if (line.startsWith("/", Qt::CaseInsensitive))
{
// Detected end of keyword data section
return;
}
else if (line.startsWith(editKeyword, Qt::CaseInsensitive))
{
// End parsing when edit keyword is detected
if (isEditKeywordDetected)
{
*isEditKeywordDetected = true;
}
return;
}
// Replace tab with space to be able to split the string using space as splitter
line.replace("\t", " ");
QStringList entries;
bool insideQuotes = false;
QString column;
for (int i = 0; i < line.length(); ++i)
{
if (line[i] == '\'')
{
insideQuotes = !insideQuotes;
}
else if (line[i] == ' ' && !insideQuotes)
{
if (column.length() > 0)
{
entries.push_back(column);
}
column.clear();
}
else
{
column += line[i];
}
}
if (entries.size() < 8)
{
continue;
}
QString faultName = entries[0];
if (faultName.contains(' '))
{
RiaLogging::error(QString("Fault name '%1' contains spaces").arg(faultName));
continue;
}
else if (faultName.length() > 8)
{
// Keep going anyway, eclipse files sometimes have longer than
// the specified 8 characters in the name without Eclipse complaining
RiaLogging::warning(QString("Fault name '%1' is longer than 8 characters").arg(faultName));
}
int i1, i2, j1, j2, k1, k2;
i1 = entries[1].toInt();
i2 = entries[2].toInt();
j1 = entries[3].toInt();
j2 = entries[4].toInt();
k1 = entries[5].toInt();
k2 = entries[6].toInt();
QString faceString = entries[7];
cvf::StructGridInterface::FaceEnum cellFaceEnum = RifEclipseInputFileTools::faceEnumFromText(faceString);
// Adjust from 1-based to 0-based cell indices
// Guard against invalid cell ranges by limiting lowest possible range value to zero
cvf::CellRange cellrange(CVF_MAX(i1 - 1, 0),
CVF_MAX(j1 - 1, 0),
CVF_MAX(k1 - 1, 0),
CVF_MAX(i2 - 1, 0),
CVF_MAX(j2 - 1, 0),
CVF_MAX(k2 - 1, 0));
if (!(fault && fault->name() == faultName))
{
if (findFaultByName(*faults, faultName) == cvf::UNDEFINED_SIZE_T)
{
RigFault* newFault = new RigFault;
newFault->setName(faultName);
faults->push_back(newFault);
}
size_t faultIndex = findFaultByName(*faults, faultName);
if (faultIndex == cvf::UNDEFINED_SIZE_T)
{
CVF_ASSERT(faultIndex != cvf::UNDEFINED_SIZE_T);
continue;
}
fault = faults->at(faultIndex);
}
CVF_ASSERT(fault);
fault->addCellRangeForFace(cellFaceEnum, cellrange);
} while (!data.atEnd());
}