Add support for grid import using opm-common

Add support for import of geometry and results for main grid. Currently no support for LGR.

Add selection in Preferences to either use libecl or opm-common for grid import.

If RESINSIGHT_DEVEL flag is set, display reader in an Eclipse case to make it possible to compare Eclipse and opm-common in same project.

Add more includes to custom-opm-common to be able to support this functionality. opm-common is unchanged.
This commit is contained in:
Magne Sjaastad 2023-08-28 12:17:34 +02:00
parent 559f02c13a
commit 81809efee9
25 changed files with 1114 additions and 120 deletions

View File

@ -62,6 +62,15 @@ void caf::AppEnum<RiaDefines::DepthUnitType>::setUp()
setDefault( RiaDefines::DepthUnitType::UNIT_METER );
}
template <>
void caf::AppEnum<RiaDefines::GridModelReader>::setUp()
{
addItem( RiaDefines::GridModelReader::LIBECL, "LIBECL", "libecl" );
addItem( RiaDefines::GridModelReader::OPM_COMMON, "OPM_COMMON", "opm-common (beta)" );
setDefault( RiaDefines::GridModelReader::LIBECL );
}
template <>
void caf::AppEnum<RiaDefines::EclipseUnitSystem>::setUp()
{

View File

@ -167,6 +167,12 @@ enum class GridCaseAxis
UNDEFINED_AXIS
};
enum class GridModelReader
{
LIBECL,
OPM_COMMON
};
enum class ThemeEnum
{
DEFAULT,

View File

@ -28,6 +28,7 @@ void caf::AppEnum<RiaEclipseFileNameTools::EclipseFileType>::setUp()
addItem( RiaEclipseFileNameTools::EclipseFileType::ECLIPSE_DATA, "DATA", "Data Deck" );
addItem( RiaEclipseFileNameTools::EclipseFileType::ECLIPSE_GRID, "GRID", "Grid" );
addItem( RiaEclipseFileNameTools::EclipseFileType::ECLIPSE_EGRID, "EGRID", "Grid" );
addItem( RiaEclipseFileNameTools::EclipseFileType::ECLIPSE_INIT, "INIT", "Init file" );
addItem( RiaEclipseFileNameTools::EclipseFileType::ECLIPSE_UNRST, "UNRST", "Unified Restart" );
addItem( RiaEclipseFileNameTools::EclipseFileType::ECLIPSE_SMSPEC, "SMSPEC", "Summary Specification" );
addItem( RiaEclipseFileNameTools::EclipseFileType::ECLIPSE_UNSMRY, "UNSMR", "Summary Vectors" );

View File

@ -35,6 +35,7 @@ public:
ECLIPSE_DATA,
ECLIPSE_GRID,
ECLIPSE_EGRID,
ECLIPSE_INIT,
ECLIPSE_UNRST,
ECLIPSE_SMSPEC,
ECLIPSE_UNSMRY,

View File

@ -192,6 +192,8 @@ RiaPreferences::RiaPreferences()
CAF_PDM_InitField( &csvTextExportFieldSeparator, "csvTextExportFieldSeparator", QString( "," ), "CSV Text Export Field Separator" );
CAF_PDM_InitFieldNoDefault( &m_gridModelReader, "gridModelReader", "Grid Model Reader" );
CAF_PDM_InitFieldNoDefault( &m_readerSettings, "readerSettings", "Reader Settings" );
m_readerSettings = new RifReaderSettings;
CAF_PDM_InitFieldNoDefault( &m_dateFormat, "dateFormat", "Date Format" );
@ -357,6 +359,8 @@ void RiaPreferences::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering&
}
else if ( uiConfigName == RiaPreferences::tabNameGrid() )
{
uiOrdering.add( &m_gridModelReader );
caf::PdmUiGroup* newCaseBehaviourGroup = uiOrdering.addNewGroup( "Behavior When Loading Data" );
newCaseBehaviourGroup->add( &autocomputeDepthRelatedProperties );
newCaseBehaviourGroup->add( &loadAndShowSoil );
@ -629,6 +633,14 @@ const RifReaderSettings* RiaPreferences::readerSettings() const
return m_readerSettings;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaDefines::GridModelReader RiaPreferences::gridModelReader() const
{
return m_gridModelReader();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -55,6 +55,7 @@ public:
using FontSizeEnum = RiaFontCache::FontSizeEnum;
using PageSizeEnum = caf::AppEnum<QPageSize::PageSizeId>;
using PageOrientationEnum = caf::AppEnum<QPageLayout::Orientation>;
using GridModelEnum = caf::AppEnum<RiaDefines::GridModelReader>;
bool enableFaultsByDefault() const;
@ -66,7 +67,8 @@ public:
QStringList tabNames();
const RifReaderSettings* readerSettings() const;
const RifReaderSettings* readerSettings() const;
RiaDefines::GridModelReader gridModelReader() const;
bool useUndoRedo() const;
@ -165,6 +167,7 @@ private:
static double defaultMarginSize( QPageSize::PageSizeId pageSizeId );
private:
caf::PdmField<GridModelEnum> m_gridModelReader;
caf::PdmChildField<RifReaderSettings*> m_readerSettings;
caf::PdmField<QString> m_dateFormat;

View File

@ -202,7 +202,7 @@ list(APPEND RI_PRIVATE_INCLUDES ${RESINSIGHT_OPENVDS_API_DIR}/include)
# Configure include directories if opm-common.lib is downloaded and linked
# without building from source
#
if(NOT BUILD_FROM_SOURCE)
if(NOT RESINSIGHT_BUILD_LIBS_FROM_SOURCE)
list(APPEND RI_PUBLIC_INCLUDES
${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/custom-opm-common/opm-common
)

View File

@ -85,6 +85,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RifRevealSummaryCsvReader.h
${CMAKE_CURRENT_LIST_DIR}/RifRevealCsvSectionSummaryReader.h
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanCsvSummaryReader.h
${CMAKE_CURRENT_LIST_DIR}/RifReaderOpmCommon.h
)
set(SOURCE_GROUP_SOURCE_FILES
@ -171,6 +172,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RifRevealCsvSummaryReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifRevealCsvSectionSummaryReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifStimPlanCsvSummaryReader.cpp
${CMAKE_CURRENT_LIST_DIR}/RifReaderOpmCommon.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

View File

@ -22,9 +22,17 @@
#include "RiaQDateTimeTools.h"
#include "RiaStringEncodingTools.h"
#include "RifEclipseRestartFilesetAccess.h"
#include "RifEclipseUnifiedRestartFileAccess.h"
#include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h"
#include "RigEclipseResultInfo.h"
#include "RigMainGrid.h"
#include "ert/ecl/ecl_file.h"
#include "ert/ecl/ecl_grid.h"
#include "ert/ecl/ecl_kw_magic.h"
@ -65,6 +73,54 @@ std::vector<RifKeywordValueCount> RifEclipseOutputFileTools::keywordValueCounts(
return reportstepMetaData.keywordValueCounts();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifEclipseOutputFileTools::createResultEntries( const std::vector<RifKeywordValueCount>& fileKeywordInfo,
const std::vector<RigEclipseTimeStepInfo>& timeStepInfo,
RiaDefines::ResultCatType resultCategory,
RigEclipseCaseData* eclipseCaseData )
{
if ( !eclipseCaseData ) return;
RigCaseCellResultsData* matrixModelResults = eclipseCaseData->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
RigCaseCellResultsData* fractureModelResults = eclipseCaseData->results( RiaDefines::PorosityModelType::FRACTURE_MODEL );
{
auto validKeywords = validKeywordsForPorosityModel( fileKeywordInfo,
eclipseCaseData->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL ),
eclipseCaseData->activeCellInfo( RiaDefines::PorosityModelType::FRACTURE_MODEL ),
RiaDefines::PorosityModelType::MATRIX_MODEL,
timeStepInfo.size() );
for ( const auto& keywordData : validKeywords )
{
RigEclipseResultAddress resAddr( resultCategory,
RifKeywordValueCount::mapType( keywordData.dataType() ),
QString::fromStdString( keywordData.keyword() ) );
matrixModelResults->createResultEntry( resAddr, false );
matrixModelResults->setTimeStepInfos( resAddr, timeStepInfo );
}
}
{
auto validKeywords = validKeywordsForPorosityModel( fileKeywordInfo,
eclipseCaseData->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL ),
eclipseCaseData->activeCellInfo( RiaDefines::PorosityModelType::FRACTURE_MODEL ),
RiaDefines::PorosityModelType::FRACTURE_MODEL,
timeStepInfo.size() );
for ( const auto& keywordData : validKeywords )
{
RigEclipseResultAddress resAddr( resultCategory,
RifKeywordValueCount::mapType( keywordData.dataType() ),
QString::fromStdString( keywordData.keyword() ) );
fractureModelResults->createResultEntry( resAddr, false );
fractureModelResults->setTimeStepInfos( resAddr, timeStepInfo );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -593,6 +649,73 @@ FILE* RifEclipseOutputFileTools::fopen( const QString& filePath, const QString&
return filePtr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifEclipseOutputFileTools::assignActiveCellData( std::vector<std::vector<int>>& actnumValuesPerGrid, RigEclipseCaseData* eclipseCaseData )
{
size_t reservoirCellCount = 0;
for ( const auto& actnumValues : actnumValuesPerGrid )
{
reservoirCellCount += actnumValues.size();
}
// Check if number of cells is matching
if ( eclipseCaseData->mainGrid()->globalCellArray().size() != reservoirCellCount )
{
return false;
}
RigActiveCellInfo* activeCellInfo = eclipseCaseData->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL );
RigActiveCellInfo* fractureActiveCellInfo = eclipseCaseData->activeCellInfo( RiaDefines::PorosityModelType::FRACTURE_MODEL );
activeCellInfo->setReservoirCellCount( reservoirCellCount );
fractureActiveCellInfo->setReservoirCellCount( reservoirCellCount );
activeCellInfo->setGridCount( actnumValuesPerGrid.size() );
fractureActiveCellInfo->setGridCount( actnumValuesPerGrid.size() );
size_t cellIdx = 0;
size_t globalActiveMatrixIndex = 0;
size_t globalActiveFractureIndex = 0;
const int matrixActive = 1;
const int fractureActive = 2;
const int matrixAndFractureActive = 3;
for ( size_t gridIndex = 0; gridIndex < actnumValuesPerGrid.size(); gridIndex++ )
{
size_t activeMatrixIndex = 0;
size_t activeFractureIndex = 0;
std::vector<int>& actnumValues = actnumValuesPerGrid[gridIndex];
for ( int actnumValue : actnumValues )
{
if ( actnumValue == matrixActive || actnumValue == matrixAndFractureActive )
{
activeCellInfo->setCellResultIndex( cellIdx, globalActiveMatrixIndex++ );
activeMatrixIndex++;
}
if ( actnumValue == fractureActive || actnumValue == matrixAndFractureActive )
{
fractureActiveCellInfo->setCellResultIndex( cellIdx, globalActiveFractureIndex++ );
activeFractureIndex++;
}
cellIdx++;
}
activeCellInfo->setGridActiveCellCounts( gridIndex, activeMatrixIndex );
fractureActiveCellInfo->setGridActiveCellCounts( gridIndex, activeFractureIndex );
}
activeCellInfo->computeDerivedData();
fractureActiveCellInfo->computeDerivedData();
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -664,3 +787,100 @@ RifRestartReportKeywords RifEclipseOutputFileTools::createReportStepsMetaData( c
return reportSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RifKeywordValueCount>
RifEclipseOutputFileTools::validKeywordsForPorosityModel( const std::vector<RifKeywordValueCount>& keywordItemCounts,
const RigActiveCellInfo* matrixActiveCellInfo,
const RigActiveCellInfo* fractureActiveCellInfo,
RiaDefines::PorosityModelType porosityModel,
size_t timeStepCount )
{
if ( !matrixActiveCellInfo ) return {};
if ( porosityModel == RiaDefines::PorosityModelType::FRACTURE_MODEL && ( fractureActiveCellInfo->reservoirActiveCellCount() == 0 ) )
{
return {};
}
std::vector<RifKeywordValueCount> keywordsWithCorrectNumberOfDataItems;
for ( const auto& keywordValueCount : keywordItemCounts )
{
QString keyword = QString::fromStdString( keywordValueCount.keyword() );
size_t valueCount = keywordValueCount.valueCount();
bool validKeyword = false;
size_t timeStepsAllCellsRest = valueCount % matrixActiveCellInfo->reservoirCellCount();
if ( timeStepsAllCellsRest == 0 && valueCount <= timeStepCount * matrixActiveCellInfo->reservoirCellCount() )
{
// Found result for all cells for N time steps, usually a static dataset for one time step
validKeyword = true;
}
else
{
size_t timeStepsMatrixRest = valueCount % matrixActiveCellInfo->reservoirActiveCellCount();
size_t timeStepsFractureRest = 0;
if ( fractureActiveCellInfo->reservoirActiveCellCount() > 0 )
{
timeStepsFractureRest = valueCount % fractureActiveCellInfo->reservoirActiveCellCount();
}
size_t sumFractureMatrixActiveCellCount = matrixActiveCellInfo->reservoirActiveCellCount() +
fractureActiveCellInfo->reservoirActiveCellCount();
size_t timeStepsMatrixAndFractureRest = valueCount % sumFractureMatrixActiveCellCount;
if ( porosityModel == RiaDefines::PorosityModelType::MATRIX_MODEL && timeStepsMatrixRest == 0 )
{
if ( valueCount <=
timeStepCount * std::max( matrixActiveCellInfo->reservoirActiveCellCount(), sumFractureMatrixActiveCellCount ) )
{
validKeyword = true;
}
}
else if ( porosityModel == RiaDefines::PorosityModelType::FRACTURE_MODEL &&
fractureActiveCellInfo->reservoirActiveCellCount() > 0 && timeStepsFractureRest == 0 )
{
if ( valueCount <=
timeStepCount * std::max( fractureActiveCellInfo->reservoirActiveCellCount(), sumFractureMatrixActiveCellCount ) )
{
validKeyword = true;
}
}
else if ( timeStepsMatrixAndFractureRest == 0 )
{
if ( valueCount <= timeStepCount * sumFractureMatrixActiveCellCount )
{
validKeyword = true;
}
}
}
// Check for INIT values that has only values for main grid active cells
if ( !validKeyword )
{
if ( timeStepCount == 1 )
{
size_t mainGridMatrixActiveCellCount = matrixActiveCellInfo->gridActiveCellCounts( 0 );
size_t mainGridFractureActiveCellCount = fractureActiveCellInfo->gridActiveCellCounts( 0 );
if ( valueCount == mainGridMatrixActiveCellCount || valueCount == mainGridFractureActiveCellCount ||
valueCount == mainGridMatrixActiveCellCount + mainGridFractureActiveCellCount )
{
validKeyword = true;
}
}
}
if ( validKeyword )
{
keywordsWithCorrectNumberOfDataItems.push_back( keywordValueCount );
}
}
return keywordsWithCorrectNumberOfDataItems;
}

View File

@ -35,6 +35,8 @@
using ecl_file_type = struct ecl_file_struct;
class RifEclipseRestartDataAccess;
class RigEclipseTimeStepInfo;
class RigActiveCellInfo;
class QByteArray;
//==================================================================================================
@ -50,6 +52,11 @@ public:
static std::vector<RifKeywordValueCount> keywordValueCounts( const std::vector<ecl_file_type*>& ecl_files );
static void createResultEntries( const std::vector<RifKeywordValueCount>& fileKeywordInfo,
const std::vector<RigEclipseTimeStepInfo>& timeStepInfo,
RiaDefines::ResultCatType resultCategory,
RigEclipseCaseData* eclipseCaseData );
static bool keywordData( const ecl_file_type* ecl_file, const QString& keyword, size_t fileKeywordOccurrence, std::vector<double>* values );
static bool keywordData( const ecl_file_type* ecl_file, const QString& keyword, size_t fileKeywordOccurrence, std::vector<int>* values );
@ -85,6 +92,13 @@ public:
static FILE* fopen( const QString& filePath, const QString& mode );
static bool assignActiveCellData( std::vector<std::vector<int>>& actnumValuesPerGrid, RigEclipseCaseData* eclipseCaseData );
private:
static RifRestartReportKeywords createReportStepsMetaData( const std::vector<ecl_file_type*>& ecl_files );
static RifRestartReportKeywords createReportStepsMetaData( const std::vector<ecl_file_type*>& ecl_files );
static std::vector<RifKeywordValueCount> validKeywordsForPorosityModel( const std::vector<RifKeywordValueCount>& keywordItemCounts,
const RigActiveCellInfo* activeCellInfo,
const RigActiveCellInfo* fractureActiveCellInfo,
RiaDefines::PorosityModelType matrixOrFracture,
size_t timeStepCount );
};

View File

@ -23,6 +23,8 @@
#include "RifReaderEclipseOutput.h"
#include "RigActiveCellInfo.h"
#include "RigEclipseCaseData.h"
#include "RigMainGrid.h"
#include "cvfGeometryTools.h"
@ -98,6 +100,61 @@ void RifOpmGridTools::importCoordinatesForRadialGrid( const std::string& gridFil
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RifOpmGridTools::cellCount( const std::string& gridFilePath )
{
Opm::EclIO::EGrid opmGrid( gridFilePath );
return opmGrid.totalNumberOfCells();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifOpmGridTools::importGrid( const std::string& gridFilePath, RigMainGrid* mainGrid, RigEclipseCaseData* caseData )
{
Opm::EclIO::EGrid opmGrid( gridFilePath );
auto dims = opmGrid.dimension();
mainGrid->setGridPointDimensions( cvf::Vec3st( dims[0] + 1, dims[1] + 1, dims[2] + 1 ) );
RigCell defaultCell;
defaultCell.setHostGrid( mainGrid );
auto cellCount = opmGrid.totalNumberOfCells();
mainGrid->globalCellArray().resize( cellCount, defaultCell );
mainGrid->nodes().resize( 8 * cellCount );
transferCoordinatesCartesian( opmGrid, opmGrid, mainGrid, mainGrid, caseData );
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::vector<int>> RifOpmGridTools::activeCellsFromActnumKeyword( Opm::EclIO::EGrid& grid )
{
auto arrayNames = grid.arrayNames();
int actnumArrayIndex = -1;
for ( size_t i = 0; i < arrayNames.size(); i++ )
{
if ( arrayNames[i] == "ACTNUM" )
{
actnumArrayIndex = static_cast<int>( i );
break;
}
}
if ( actnumArrayIndex < 0 ) return {};
auto actnumMainGrid = grid.get<int>( actnumArrayIndex );
return { actnumMainGrid };
}
//--------------------------------------------------------------------------------------------------
//
// A radial grid is defined by a center point and a set of cylindrical coordinates. The coordinates at the
@ -251,6 +308,79 @@ void RifOpmGridTools::transferCoordinates( Opm::EclIO::EGrid& opmMainGrid, Opm::
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifOpmGridTools::transferCoordinatesCartesian( Opm::EclIO::EGrid& opmMainGrid,
Opm::EclIO::EGrid& opmGrid,
RigMainGrid* riMainGrid,
RigGridBase* riGrid,
RigEclipseCaseData* caseData )
{
// Prefix OPM structures with _opm_and ResInsight structures with _ri_
auto& riNodes = riMainGrid->nodes();
opmGrid.loadData();
opmGrid.load_grid_data();
auto riActiveCells = caseData->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL );
auto riActiveCellsFrac = caseData->activeCellInfo( RiaDefines::PorosityModelType::FRACTURE_MODEL );
riActiveCellsFrac->setGridCount( 1 );
riActiveCellsFrac->setGridActiveCellCounts( 0, 0 );
riActiveCells->setReservoirCellCount( riMainGrid->cellCount() );
// same mapping as libecl
const size_t cellMappingECLRi[8] = { 0, 1, 3, 2, 4, 5, 7, 6 };
#pragma omp parallel for
for ( int opmCellIndex = 0; opmCellIndex < static_cast<int>( riMainGrid->cellCount() ); opmCellIndex++ )
{
auto opmIJK = opmGrid.ijk_from_global_index( opmCellIndex );
auto riReservoirIndex = riGrid->cellIndexFromIJK( opmIJK[0], opmIJK[1], opmIJK[2] );
RigCell& cell = riMainGrid->globalCellArray()[riReservoirIndex];
cell.setGridLocalCellIndex( riReservoirIndex );
std::array<double, 8> opmX{};
std::array<double, 8> opmY{};
std::array<double, 8> opmZ{};
opmGrid.getCellCorners( opmCellIndex, opmX, opmY, opmZ );
// Each cell has 8 nodes, use reservoir cell index and multiply to find first node index for cell
auto riNodeStartIndex = riReservoirIndex * 8;
for ( size_t opmNodeIndex = 0; opmNodeIndex < 8; opmNodeIndex++ )
{
auto riCornerIndex = cellMappingECLRi[opmNodeIndex];
size_t riNodeIndex = riNodeStartIndex + riCornerIndex;
auto& riNode = riNodes[riNodeIndex];
riNode.x() = opmX[opmNodeIndex];
riNode.y() = opmY[opmNodeIndex];
riNode.z() = -opmZ[opmNodeIndex];
cell.cornerIndices()[riCornerIndex] = riNodeIndex;
}
if ( riActiveCells )
{
auto activeIndex = opmGrid.active_index( opmIJK[0], opmIJK[1], opmIJK[2] );
if ( activeIndex > -1 )
{
riActiveCells->setCellResultIndex( riReservoirIndex, activeIndex );
}
}
}
riActiveCells->setGridCount( 1 );
riActiveCells->setGridActiveCellCounts( 0, opmGrid.activeCells() );
riActiveCells->computeDerivedData();
riMainGrid->initAllSubGridsParentGridPointer();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -34,6 +34,7 @@ namespace EclIO
class RigMainGrid;
class RigGridBase;
class RigEclipseCaseData;
//==================================================================================================
///
@ -44,8 +45,18 @@ public:
// If the grid is radial, the coordinates are imported and adjusted to fit the host cells
static void importCoordinatesForRadialGrid( const std::string& gridFilePath, RigMainGrid* mainGrid );
static size_t cellCount( const std::string& gridFilePath );
static bool importGrid( const std::string& gridFilePath, RigMainGrid* mainGrid, RigEclipseCaseData* caseData );
static std::vector<std::vector<int>> activeCellsFromActnumKeyword( Opm::EclIO::EGrid& grid );
private:
static void transferCoordinates( Opm::EclIO::EGrid& opmMainGrid, Opm::EclIO::EGrid& opmGrid, RigMainGrid* riMainGrid, RigGridBase* riGrid );
static void transferCoordinatesCartesian( Opm::EclIO::EGrid& opmMainGrid,
Opm::EclIO::EGrid& opmGrid,
RigMainGrid* riMainGrid,
RigGridBase* riGrid,
RigEclipseCaseData* caseData );
static std::map<int, std::pair<double, double>>
computeXyCenterForTopOfCells( Opm::EclIO::EGrid& opmMainGrid, Opm::EclIO::EGrid& opmGrid, RigGridBase* riGrid );

View File

@ -837,62 +837,7 @@ bool RifReaderEclipseOutput::readActiveCellInfo()
}
}
size_t reservoirCellCount = 0;
for ( const auto& actnumValues : actnumValuesPerGrid )
{
reservoirCellCount += actnumValues.size();
}
// Check if number of cells is matching
if ( m_eclipseCase->mainGrid()->globalCellArray().size() != reservoirCellCount )
{
return false;
}
RigActiveCellInfo* activeCellInfo = m_eclipseCase->activeCellInfo( RiaDefines::PorosityModelType::MATRIX_MODEL );
RigActiveCellInfo* fractureActiveCellInfo = m_eclipseCase->activeCellInfo( RiaDefines::PorosityModelType::FRACTURE_MODEL );
activeCellInfo->setReservoirCellCount( reservoirCellCount );
fractureActiveCellInfo->setReservoirCellCount( reservoirCellCount );
activeCellInfo->setGridCount( actnumValuesPerGrid.size() );
fractureActiveCellInfo->setGridCount( actnumValuesPerGrid.size() );
size_t cellIdx = 0;
size_t globalActiveMatrixIndex = 0;
size_t globalActiveFractureIndex = 0;
for ( size_t gridIndex = 0; gridIndex < actnumValuesPerGrid.size(); gridIndex++ )
{
size_t activeMatrixIndex = 0;
size_t activeFractureIndex = 0;
std::vector<int>& actnumValues = actnumValuesPerGrid[gridIndex];
for ( int actnumValue : actnumValues )
{
if ( actnumValue == 1 || actnumValue == 3 )
{
activeCellInfo->setCellResultIndex( cellIdx, globalActiveMatrixIndex++ );
activeMatrixIndex++;
}
if ( actnumValue == 2 || actnumValue == 3 )
{
fractureActiveCellInfo->setCellResultIndex( cellIdx, globalActiveFractureIndex++ );
activeFractureIndex++;
}
cellIdx++;
}
activeCellInfo->setGridActiveCellCounts( gridIndex, activeMatrixIndex );
fractureActiveCellInfo->setGridActiveCellCounts( gridIndex, activeFractureIndex );
}
activeCellInfo->computeDerivedData();
fractureActiveCellInfo->computeDerivedData();
return true;
return RifEclipseOutputFileTools::assignActiveCellData( actnumValuesPerGrid, m_eclipseCase );
}
//--------------------------------------------------------------------------------------------------
@ -2109,7 +2054,7 @@ std::vector<RifKeywordValueCount>
const RigActiveCellInfo* matrixActiveCellInfo,
const RigActiveCellInfo* fractureActiveCellInfo,
RiaDefines::PorosityModelType porosityModel,
size_t timeStepCount ) const
size_t timeStepCount )
{
CVF_ASSERT( matrixActiveCellInfo );

View File

@ -90,6 +90,7 @@ public:
private:
bool readActiveCellInfo();
void buildMetaData( ecl_grid_type* grid );
void readWellCells( const ecl_grid_type* mainEclGrid, bool importCompleteMswData );
@ -114,11 +115,11 @@ private:
void ensureDynamicResultAccessIsPresent();
std::vector<RifKeywordValueCount> validKeywordsForPorosityModel( const std::vector<RifKeywordValueCount>& keywordItemCounts,
const RigActiveCellInfo* activeCellInfo,
const RigActiveCellInfo* fractureActiveCellInfo,
RiaDefines::PorosityModelType matrixOrFracture,
size_t timeStepCount ) const;
static std::vector<RifKeywordValueCount> validKeywordsForPorosityModel( const std::vector<RifKeywordValueCount>& keywordItemCounts,
const RigActiveCellInfo* activeCellInfo,
const RigActiveCellInfo* fractureActiveCellInfo,
RiaDefines::PorosityModelType matrixOrFracture,
size_t timeStepCount );
std::vector<RigEclipseTimeStepInfo> createFilteredTimeStepInfos();

View File

@ -0,0 +1,470 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor 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 "RifReaderOpmCommon.h"
#include "RiaEclipseFileNameTools.h"
#include "RiaLogging.h"
#include "RiaQDateTimeTools.h"
#include "RifEclipseOutputFileTools.h"
#include "RifOpmGridTools.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultInfo.h"
#include "RigMainGrid.h"
#include "RigSimWellData.h"
#include "RigWellResultFrame.h"
#include "opm/input/eclipse/Deck/Deck.hpp"
#include "opm/input/eclipse/EclipseState/Runspec.hpp"
#include "opm/input/eclipse/Parser/Parser.hpp"
#include "opm/input/eclipse/Schedule/Well/Connection.hpp"
#include "opm/input/eclipse/Schedule/Well/Well.hpp"
#include "opm/io/eclipse/EInit.hpp"
#include "opm/io/eclipse/ERst.hpp"
#include "opm/io/eclipse/RestartFileView.hpp"
#include "opm/io/eclipse/rst/state.hpp"
#include "opm/output/eclipse/VectorItems/group.hpp"
#include "opm/output/eclipse/VectorItems/well.hpp"
using namespace Opm;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderOpmCommon::RifReaderOpmCommon()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifReaderOpmCommon::~RifReaderOpmCommon()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderOpmCommon::open( const QString& fileName, RigEclipseCaseData* eclipseCase )
{
QStringList fileSet;
if ( !RifEclipseOutputFileTools::findSiblingFilesWithSameBaseName( fileName, &fileSet ) ) return false;
try
{
m_gridFileName = fileName.toStdString();
if ( !RifOpmGridTools::importGrid( m_gridFileName, eclipseCase->mainGrid(), eclipseCase ) )
{
RiaLogging::error( "Failed to open grid file " + fileName );
return false;
}
buildMetaData( eclipseCase );
return true;
}
catch ( std::exception& e )
{
auto description = e.what();
RiaLogging::error( description );
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderOpmCommon::staticResult( const QString& result, RiaDefines::PorosityModelType matrixOrFracture, std::vector<double>* values )
{
if ( m_initFile )
{
try
{
auto resultName = result.toStdString();
auto resultEntries = m_initFile->getList();
for ( const auto& entry : resultEntries )
{
const auto& [keyword, kwType, size] = entry;
if ( keyword == resultName )
{
if ( kwType == EclIO::eclArrType::REAL )
{
auto fileValues = m_initFile->getInitData<float>( resultName );
values->insert( values->end(), fileValues.begin(), fileValues.end() );
}
else if ( kwType == EclIO::eclArrType::DOUB )
{
auto fileValues = m_initFile->getInitData<double>( resultName );
values->insert( values->end(), fileValues.begin(), fileValues.end() );
}
else if ( kwType == EclIO::eclArrType::INTE )
{
auto fileValues = m_initFile->getInitData<int>( resultName );
values->insert( values->end(), fileValues.begin(), fileValues.end() );
}
}
}
return true;
}
catch ( std::exception& e )
{
RiaLogging::error( e.what() );
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RifReaderOpmCommon::dynamicResult( const QString& result,
RiaDefines::PorosityModelType matrixOrFracture,
size_t stepIndex,
std::vector<double>* values )
{
if ( m_restartFile )
{
try
{
auto resultName = result.toStdString();
auto stepNumbers = m_restartFile->listOfReportStepNumbers();
auto stepNumber = stepNumbers[stepIndex];
auto resultEntries = m_restartFile->getList();
for ( const auto& entry : resultEntries )
{
const auto& [keyword, kwType, size] = entry;
if ( keyword == resultName )
{
if ( kwType == EclIO::eclArrType::DOUB )
{
auto fileValues = m_restartFile->getRestartData<double>( resultName, stepNumber );
values->insert( values->end(), fileValues.begin(), fileValues.end() );
}
if ( kwType == EclIO::eclArrType::REAL )
{
auto fileValues = m_restartFile->getRestartData<float>( resultName, stepNumber );
values->insert( values->end(), fileValues.begin(), fileValues.end() );
}
else if ( kwType == EclIO::eclArrType::INTE )
{
auto fileValues = m_restartFile->getRestartData<int>( resultName, stepNumber );
values->insert( values->end(), fileValues.begin(), fileValues.end() );
}
}
}
return true;
}
catch ( std::exception& e )
{
RiaLogging::error( e.what() );
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RifKeywordValueCount> createKeywordInfo( std::vector<EclIO::EclFile::EclEntry> entries )
{
std::vector<RifKeywordValueCount> fileKeywordInfo;
for ( const auto& entry : entries )
{
const auto& [keyword, kwType, size] = entry;
RifKeywordValueCount::KeywordDataType dataType = RifKeywordValueCount::KeywordDataType::UNKNOWN;
if ( kwType == EclIO::eclArrType::INTE )
dataType = RifKeywordValueCount::KeywordDataType::INTEGER;
else if ( kwType == EclIO::eclArrType::REAL )
dataType = RifKeywordValueCount::KeywordDataType::FLOAT;
else if ( kwType == EclIO::eclArrType::DOUB )
dataType = RifKeywordValueCount::KeywordDataType::DOUBLE;
if ( dataType != RifKeywordValueCount::KeywordDataType::UNKNOWN )
{
fileKeywordInfo.emplace_back( RifKeywordValueCount( keyword, static_cast<size_t>( size ), dataType ) );
}
}
return fileKeywordInfo;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderOpmCommon::buildMetaData( RigEclipseCaseData* eclipseCase )
{
auto getFileNameForType = []( RiaEclipseFileNameTools::EclipseFileType fileType, const QString& candidate ) -> std::string
{
const QString ext = caf::AppEnum<RiaEclipseFileNameTools::EclipseFileType>::text( fileType );
if ( candidate.endsWith( ext, Qt::CaseInsensitive ) ) return candidate.toStdString();
return {};
};
std::string initFileName;
std::string restartFileName;
QStringList fileSet;
RifEclipseOutputFileTools::findSiblingFilesWithSameBaseName( QString::fromStdString( m_gridFileName ), &fileSet );
for ( const auto& s : fileSet )
{
auto initCandidate = getFileNameForType( RiaEclipseFileNameTools::EclipseFileType::ECLIPSE_INIT, s );
auto restartCandidate = getFileNameForType( RiaEclipseFileNameTools::EclipseFileType::ECLIPSE_UNRST, s );
if ( !initCandidate.empty() ) initFileName = initCandidate;
if ( !restartCandidate.empty() ) restartFileName = restartCandidate;
}
RigEclipseTimeStepInfo firstTimeStepInfo{ QDateTime(), 0, 0.0 };
if ( !restartFileName.empty() )
{
m_restartFile = std::make_shared<EclIO::ERst>( restartFileName );
std::vector<EclIO::EclFile::EclEntry> entries;
for ( auto reportNumber : m_restartFile->listOfReportStepNumbers() )
{
auto reportEntries = m_restartFile->listOfRstArrays( reportNumber );
entries.insert( entries.end(), reportEntries.begin(), reportEntries.end() );
}
auto timeStepsFromFile = readTimeSteps( m_restartFile );
std::vector<RigEclipseTimeStepInfo> timeStepInfos;
std::vector<QDateTime> dateTimes;
for ( const auto& timeStep : timeStepsFromFile )
{
QDate date( timeStep.year, timeStep.month, timeStep.day );
QDateTime dateTime = RiaQDateTimeTools::createDateTime( date );
dateTimes.push_back( dateTime );
timeStepInfos.emplace_back( dateTime, timeStep.sequenceNumber, 0.0 );
}
m_timeSteps = dateTimes;
auto last = std::unique( entries.begin(), entries.end() );
entries.erase( last, entries.end() );
std::vector<RifKeywordValueCount> keywordInfo = createKeywordInfo( entries );
RifEclipseOutputFileTools::createResultEntries( keywordInfo, timeStepInfos, RiaDefines::ResultCatType::DYNAMIC_NATIVE, eclipseCase );
firstTimeStepInfo = timeStepInfos.front();
readWellCells( m_restartFile, eclipseCase, m_timeSteps );
}
if ( !initFileName.empty() )
{
m_initFile = std::make_unique<EclIO::EInit>( initFileName );
auto entries = m_initFile->list_arrays();
std::vector<RifKeywordValueCount> keywordInfo = createKeywordInfo( entries );
RifEclipseOutputFileTools::createResultEntries( keywordInfo, { firstTimeStepInfo }, RiaDefines::ResultCatType::STATIC_NATIVE, eclipseCase );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderOpmCommon::readWellCells( std::shared_ptr<EclIO::ERst> restartFile,
RigEclipseCaseData* eclipseCase,
const std::vector<QDateTime>& timeSteps )
{
// It is required to create a deck as the input parameter to runspec. The default() initialization of the runspec keyword does not
// initialize the object as expected.
Deck deck;
Runspec runspec( deck );
Parser parser( false );
cvf::Collection<RigSimWellData> wells;
try
{
if ( restartFile->numberOfReportSteps() != timeSteps.size() )
{
RiaLogging::error( "Number of time steps is not matching number of report steps" );
return;
}
auto getWellStateAndNames = [&]() -> std::pair<std::vector<RestartIO::RstState>, std::set<std::string>>
{
std::vector<RestartIO::RstState> states;
std::set<std::string> wellNames;
for ( auto seqNumber : restartFile->listOfReportStepNumbers() )
{
auto fileView = std::make_shared<EclIO::RestartFileView>( restartFile, seqNumber );
auto state = RestartIO::RstState::load( fileView, runspec, parser );
states.emplace_back( state );
for ( const auto& w : state.wells )
{
wellNames.insert( w.name );
}
}
return std::make_pair( states, wellNames );
};
auto [states, wellNames] = getWellStateAndNames();
for ( const auto& wellName : wellNames )
{
cvf::ref<RigSimWellData> simWellData = new RigSimWellData;
simWellData->setWellName( QString::fromStdString( wellName ) );
simWellData->m_wellCellsTimeSteps.resize( timeSteps.size() );
for ( size_t timeIdx = 0; timeIdx < timeSteps.size(); ++timeIdx )
{
auto state = states[timeIdx];
auto it = std::find_if( state.wells.begin(),
state.wells.end(),
[&wellName]( const RestartIO::RstWell& well ) { return well.name == wellName; } );
if ( it == state.wells.end() ) continue;
RestartIO::RstWell rstWell = *it;
RigWellResultFrame& wellResFrame = simWellData->m_wellCellsTimeSteps[timeIdx];
wellResFrame.setTimestamp( timeSteps[timeIdx] );
auto wellType = [&rstWell]() -> RiaDefines::WellProductionType
{
if ( rstWell.wtype.producer() ) return RiaDefines::WellProductionType::PRODUCER;
if ( rstWell.wtype.injector_type() == InjectorType::WATER ) return RiaDefines::WellProductionType::WATER_INJECTOR;
if ( rstWell.wtype.injector_type() == InjectorType::GAS ) return RiaDefines::WellProductionType::GAS_INJECTOR;
if ( rstWell.wtype.injector_type() == InjectorType::OIL ) return RiaDefines::WellProductionType::OIL_INJECTOR;
return RiaDefines::WellProductionType::UNDEFINED_PRODUCTION_TYPE;
};
wellResFrame.setProductionType( wellType() );
wellResFrame.setIsOpen( rstWell.well_status == RestartIO::Helpers::VectorItems::IWell::Value::Status::Open );
// Well head
RigWellResultPoint wellHead;
wellHead.setGridIndex( 0 );
auto cellIndex = eclipseCase->mainGrid()->cellIndexFromIJK( rstWell.ij[0], rstWell.ij[1], 0 );
wellHead.setGridCellIndex( cellIndex );
wellResFrame.setWellHead( wellHead );
// Grid cells
if ( !rstWell.connections.empty() )
{
RigWellResultBranch wellResultBranch;
wellResultBranch.setErtBranchId( 0 ); // Normal wells have only one branch
std::vector<RigWellResultPoint> branchResultPoints = wellResultBranch.branchResultPoints();
const size_t existingCellCount = branchResultPoints.size();
branchResultPoints.reserve( existingCellCount + rstWell.connections.size() );
for ( const auto& conn : rstWell.connections )
{
RigWellResultPoint wellResPoint;
wellResPoint.setGridIndex( 0 );
auto cellIndex = eclipseCase->mainGrid()->cellIndexFromIJK( conn.ijk[0], conn.ijk[1], conn.ijk[2] );
wellResPoint.setGridCellIndex( cellIndex );
wellResPoint.setIsOpen( conn.state == Connection::State::OPEN );
// All units for a Connection is given in SI units
// Convert back to the original units
// See RestartIO::RstConnection::RstConnection
auto us = state.unit_system;
wellResPoint.setFlowData( us.from_si( UnitSystem::measure::rate, conn.resv_rate ),
us.from_si( UnitSystem::measure::liquid_surface_rate, conn.oil_rate ),
us.from_si( UnitSystem::measure::gas_surface_rate, conn.gas_rate ),
us.from_si( UnitSystem::measure::liquid_surface_rate, conn.water_rate ) );
wellResPoint.setConnectionFactor( us.from_si( UnitSystem::measure::transmissibility, conn.cf ) );
branchResultPoints.push_back( wellResPoint );
}
wellResultBranch.setBranchResultPoints( branchResultPoints );
wellResFrame.addWellResultBranch( wellResultBranch );
}
}
simWellData->computeMappingFromResultTimeIndicesToWellTimeIndices( timeSteps );
wells.push_back( simWellData.p() );
}
}
catch ( std::exception& e )
{
std::cout << "Exception: " << e.what() << std::endl;
}
eclipseCase->setSimWellData( wells );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RifReaderOpmCommon::TimeDataFile> RifReaderOpmCommon::readTimeSteps( std::shared_ptr<EclIO::ERst> restartFile )
{
// It is required to create a deck as the input parameter to runspec. The default() initialization of the runspec keyword does not
// initialize the object as expected.
Deck deck;
Runspec runspec( deck );
Parser parser( false );
std::vector<RifReaderOpmCommon::TimeDataFile> reportTimeData;
try
{
for ( auto seqNumber : restartFile->listOfReportStepNumbers() )
{
auto fileView = std::make_shared<EclIO::RestartFileView>( restartFile, seqNumber );
auto state = RestartIO::RstState::load( fileView, runspec, parser );
auto header = state.header;
int year = header.year;
int month = header.month;
int day = header.mday;
double daySinceSimStart = header.next_timestep1;
reportTimeData.emplace_back(
TimeDataFile{ .sequenceNumber = seqNumber, .year = year, .month = month, .day = day, .simulationTimeFromStart = daySinceSimStart } );
}
}
catch ( std::exception& e )
{
std::cout << "Exception: " << e.what() << std::endl;
}
return reportTimeData;
}

View File

@ -0,0 +1,70 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2023- Equinor 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 "RifReaderInterface.h"
#include <memory>
namespace Opm::EclIO
{
class EInit;
class ERst;
} // namespace Opm::EclIO
//==================================================================================================
//
//
//==================================================================================================
class RifReaderOpmCommon : public RifReaderInterface
{
public:
struct TimeDataFile
{
int sequenceNumber;
int year;
int month;
int day;
double simulationTimeFromStart;
};
RifReaderOpmCommon();
~RifReaderOpmCommon() override;
bool open( const QString& fileName, RigEclipseCaseData* eclipseCase ) override;
bool staticResult( const QString& result, RiaDefines::PorosityModelType matrixOrFracture, std::vector<double>* values ) override;
bool dynamicResult( const QString& result, RiaDefines::PorosityModelType matrixOrFracture, size_t stepIndex, std::vector<double>* values ) override;
private:
void buildMetaData( RigEclipseCaseData* eclipseCase );
static std::vector<TimeDataFile> readTimeSteps( std::shared_ptr<Opm::EclIO::ERst> restartFile );
static void readWellCells( std::shared_ptr<Opm::EclIO::ERst> restartFile,
RigEclipseCaseData* eclipseCase,
const std::vector<QDateTime>& timeSteps );
private:
std::string m_gridFileName;
std::shared_ptr<Opm::EclIO::ERst> m_restartFile;
std::shared_ptr<Opm::EclIO::EInit> m_initFile;
std::vector<QDateTime> m_timeSteps;
};

View File

@ -34,6 +34,7 @@
#include "RifReaderEclipseOutput.h"
#include "RifReaderEclipseRft.h"
#include "RifReaderMockModel.h"
#include "RifReaderOpmCommon.h"
#include "RifReaderOpmRft.h"
#include "RifReaderSettings.h"
@ -77,6 +78,14 @@ RimEclipseResultCase::RimEclipseResultCase()
{
CAF_PDM_InitScriptableObject( "Eclipse Case", ":/Case48x48.png", "", "The Regular Eclipse Results Case" );
auto defaultReader = RiaPreferences::current()->gridModelReader();
CAF_PDM_InitField( &m_gridModelReader, "gridModelReader", caf::AppEnum<RiaDefines::GridModelReader>( defaultReader ), "Grid Model Reader" );
if ( !RiaApplication::enableDevelopmentFeatures() )
{
m_gridModelReader.xmlCapability()->disableIO();
m_gridModelReader.uiCapability()->setUiHidden( true );
}
CAF_PDM_InitFieldNoDefault( &m_unitSystem, "UnitSystem", "Unit System" );
m_unitSystem.registerGetMethod( RimProject::current(), &RimProject::commonUnitSystemForAllCases );
m_unitSystem.uiCapability()->setUiReadOnly( true );
@ -86,9 +95,7 @@ RimEclipseResultCase::RimEclipseResultCase()
m_flowDiagSolutions.uiCapability()->setUiTreeChildrenHidden( true );
m_flipXAxis.xmlCapability()->setIOWritable( true );
// flipXAxis.uiCapability()->setUiHidden(true);
m_flipYAxis.xmlCapability()->setIOWritable( true );
// flipYAxis.uiCapability()->setUiHidden(true);
CAF_PDM_InitFieldNoDefault( &m_sourSimFileName, "SourSimFileName", "SourSim File Name" );
m_sourSimFileName.uiCapability()->setUiEditorTypeName( caf::PdmUiFilePathEditor::uiEditorTypeName() );
@ -133,60 +140,68 @@ bool RimEclipseResultCase::importGridAndResultMetaData( bool showTimeStepFilter
return false;
}
cvf::ref<RifReaderEclipseOutput> readerEclipseOutput = new RifReaderEclipseOutput;
readerEclipseOutput->setFilenamesWithFaults( filesContainingFaults() );
readerEclipseOutput->setReaderSettings( m_readerSettings );
cvf::ref<RifEclipseRestartDataAccess> restartDataAccess = RifEclipseOutputFileTools::createDynamicResultAccess( gridFileName() );
if ( m_gridModelReader == RiaDefines::GridModelReader::LIBECL )
{
std::vector<QDateTime> timeSteps;
std::vector<double> daysSinceSimulationStart;
auto readerEclipseOutput = new RifReaderEclipseOutput();
cvf::ref<RifEclipseRestartDataAccess> restartDataAccess = RifEclipseOutputFileTools::createDynamicResultAccess( gridFileName() );
if ( restartDataAccess.notNull() )
{
restartDataAccess->timeSteps( &timeSteps, &daysSinceSimulationStart );
std::vector<QDateTime> timeSteps;
std::vector<double> daysSinceSimulationStart;
if ( restartDataAccess.notNull() )
{
restartDataAccess->timeSteps( &timeSteps, &daysSinceSimulationStart );
}
m_timeStepFilter->setTimeStepsFromFile( timeSteps );
}
m_timeStepFilter->setTimeStepsFromFile( timeSteps );
if ( showTimeStepFilter )
{
caf::PdmUiPropertyViewDialog propertyDialog( nullptr,
m_timeStepFilter,
"Time Step Filter",
"",
QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
propertyDialog.resize( QSize( 400, 400 ) );
// Push arrow cursor onto the cursor stack so it takes over from the wait cursor.
QApplication::setOverrideCursor( QCursor( Qt::ArrowCursor ) );
// Show GUI to select time steps
int dialogReturnValue = propertyDialog.exec();
// Pop arrow cursor off the cursor stack so that the previous (wait) cursor takes over.
QApplication::restoreOverrideCursor();
if ( dialogReturnValue != QDialog::Accepted )
{
return false;
}
m_timeStepFilter->updateFilteredTimeStepsFromUi();
}
readerEclipseOutput->setFileDataAccess( restartDataAccess.p() );
readerEclipseOutput->setTimeStepFilter( m_timeStepFilter->filteredTimeSteps() );
readerInterface = readerEclipseOutput;
}
else
{
readerInterface = new RifReaderOpmCommon;
}
if ( showTimeStepFilter )
{
caf::PdmUiPropertyViewDialog propertyDialog( nullptr,
m_timeStepFilter,
"Time Step Filter",
"",
QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
propertyDialog.resize( QSize( 400, 400 ) );
// Push arrow cursor onto the cursor stack so it takes over from the wait cursor.
QApplication::setOverrideCursor( QCursor( Qt::ArrowCursor ) );
// Show GUI to select time steps
int dialogReturnValue = propertyDialog.exec();
// Pop arrow cursor off the cursor stack so that the previous (wait) cursor takes over.
QApplication::restoreOverrideCursor();
if ( dialogReturnValue != QDialog::Accepted )
{
return false;
}
m_timeStepFilter->updateFilteredTimeStepsFromUi();
}
readerEclipseOutput->setFileDataAccess( restartDataAccess.p() );
readerEclipseOutput->setTimeStepFilter( m_timeStepFilter->filteredTimeSteps() );
readerInterface->setFilenamesWithFaults( filesContainingFaults() );
readerInterface->setReaderSettings( m_readerSettings );
cvf::ref<RigEclipseCaseData> eclipseCase = new RigEclipseCaseData( this );
if ( !readerEclipseOutput->open( gridFileName(), eclipseCase.p() ) )
if ( !readerInterface->open( gridFileName(), eclipseCase.p() ) )
{
return false;
}
setFilesContainingFaults( readerEclipseOutput->filenamesWithFaults() );
setFilesContainingFaults( readerInterface->filenamesWithFaults() );
setReservoirData( eclipseCase.p() );
readerInterface = readerEclipseOutput;
}
results( RiaDefines::PorosityModelType::MATRIX_MODEL )->setReaderInterface( readerInterface.p() );
@ -581,6 +596,7 @@ bool RimEclipseResultCase::hasSourSimFile()
//--------------------------------------------------------------------------------------------------
void RimEclipseResultCase::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_gridModelReader );
uiOrdering.add( &m_caseUserDescription );
uiOrdering.add( &m_displayNameOption );
uiOrdering.add( &m_caseId );

View File

@ -81,17 +81,16 @@ private:
void loadAndUpdateSourSimData();
void ensureRftDataIsImported();
private:
cvf::ref<RifReaderInterface> createMockModel( QString modelName );
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
private:
cvf::ref<RigFlowDiagSolverInterface> m_flowDagSolverInterface;
cvf::ref<RifReaderEclipseRft> m_readerEclipseRft;
cvf::ref<RifReaderOpmRft> m_readerOpmRft;
// Fields:
caf::PdmField<caf::AppEnum<RiaDefines::GridModelReader>> m_gridModelReader;
caf::PdmProxyValueField<caf::AppEnum<RiaDefines::EclipseUnitSystem>> m_unitSystem;
caf::PdmChildArrayField<RimFlowDiagSolution*> m_flowDiagSolutions;
caf::PdmField<caf::FilePath> m_sourSimFileName;

View File

@ -54,6 +54,11 @@ bool RigCellVolumeResultCalculator::isMatching( const RigEclipseResultAddress& r
//--------------------------------------------------------------------------------------------------
void RigCellVolumeResultCalculator::calculate( const RigEclipseResultAddress& resVarAddr, size_t timeStepIndex )
{
if ( m_resultsData->activeCellInfo()->reservoirActiveCellCount() == 0 )
{
return;
}
size_t cellVolIdx = m_resultsData->findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::ResultCatType::STATIC_NATIVE,
RiaResultNames::riCellVolumeResultName() ),
false );

View File

@ -292,6 +292,14 @@ bool RigSimWellData::isMultiSegmentWell() const
return m_isMultiSegmentWell;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigSimWellData::setWellName( const QString& wellName )
{
m_wellName = wellName;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------

View File

@ -43,6 +43,8 @@ public:
void setMultiSegmentWell( bool isMultiSegmentWell );
bool isMultiSegmentWell() const;
void setWellName( const QString& wellName );
bool hasWellResult( size_t resultTimeStepIndex ) const;
bool hasAnyValidCells( size_t resultTimeStepIndex ) const;

View File

@ -96,6 +96,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimWellLogCalculatedCurve-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RigWellLogCurveData-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaNumericalTools-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/opm-import-well-data-Test.cpp
)
if(RESINSIGHT_ENABLE_GRPC)

View File

@ -0,0 +1,54 @@
#include "RiaTestDataDirectory.h"
#include "gtest/gtest.h"
#include "opm/input/eclipse/Deck/Deck.hpp"
#include "opm/input/eclipse/Parser/Parser.hpp"
#include "opm/io/eclipse/ERst.hpp"
#include "opm/io/eclipse/RestartFileView.hpp"
#include "opm/io/eclipse/rst/state.hpp"
#include "opm/io/eclipse/rst/well.hpp"
#include <QDir>
#include <QString>
const std::string drogonPath = "e:/gitroot/resinsight-tutorials/model-data/drogon/DROGON-0.UNRST";
TEST( DISABLED_opm_well_data_test, TestImport )
{
Opm::Deck deck;
// It is required to create a deck as the input parameter to runspec. The = default() initialization of the runspec keyword does not
// initialize the object as expected.
Opm::Runspec runspec( deck );
Opm::Parser parser( false );
try
{
QDir baseFolder( TEST_MODEL_DIR );
bool subFolderExists = baseFolder.cd( "TEST10K_FLT_LGR_NNC" );
EXPECT_TRUE( subFolderExists );
QString filename( "TEST10K_FLT_LGR_NNC.UNRST" );
QString filePath = baseFolder.absoluteFilePath( filename );
auto stdFilename = baseFolder.absoluteFilePath( filename ).toStdString();
auto rstFile = std::make_shared<Opm::EclIO::ERst>( drogonPath );
for ( auto seqNumber : rstFile->listOfReportStepNumbers() )
{
auto fileView = std::make_shared<Opm::EclIO::RestartFileView>( rstFile, seqNumber );
auto state = Opm::RestartIO::RstState::load( fileView, runspec, parser );
for ( const auto& w : state.wells )
{
auto name = w.name;
std::cout << name << std::endl;
}
}
}
catch ( std::exception& e )
{
std::cout << "Exception: " << e.what() << std::endl;
}
}

View File

@ -448,16 +448,19 @@ if((NOT RESINSIGHT_BUILD_LIBS_FROM_SOURCE) AND MSVC)
URL https://github.com/CeetronSolutions/resinsight-dependencies/releases/download/2023.08/custom-opm-common.zip
)
FetchContent_Populate(ri-dependencies)
add_library(custom-opm-common STATIC IMPORTED)
set_target_properties(custom-opm-common PROPERTIES
IMPORTED_CONFIGURATIONS "Debug;Release"
IMPORTED_LOCATION_DEBUG "${ri-dependencies_SOURCE_DIR}/custom-opm-common_debug.lib"
IMPORTED_LOCATION_RELEASE "${ri-dependencies_SOURCE_DIR}/custom-opm-common.lib"
)
set_target_properties(
custom-opm-common
PROPERTIES IMPORTED_CONFIGURATIONS "Debug;Release"
IMPORTED_LOCATION_DEBUG
"${ri-dependencies_SOURCE_DIR}/custom-opm-common_debug.lib"
IMPORTED_LOCATION_RELEASE
"${ri-dependencies_SOURCE_DIR}/custom-opm-common.lib"
)
list(APPEND EXTERNAL_LINK_LIBRARIES custom-opm-common)
message(STATUS "opm-common: Enabled use of precompiled library")
else()
add_subdirectory(ThirdParty/custom-opm-common)

View File

@ -92,10 +92,21 @@ add_library(${PROJECT_NAME}
opm-common/src/opm/io/eclipse/rst/connection.cpp
# Required for use of RstHeader::restart_info
opm-common/src/opm/io/eclipse/rst/action.cpp
opm-common/src/opm/io/eclipse/rst/aquifer.cpp
opm-common/src/opm/io/eclipse/rst/connection.cpp
opm-common/src/opm/io/eclipse/rst/group.cpp
opm-common/src/opm/io/eclipse/rst/header.cpp
opm-common/src/opm/io/eclipse/rst/network.cpp
opm-common/src/opm/io/eclipse/rst/segment.cpp
opm-common/src/opm/io/eclipse/rst/state.cpp
opm-common/src/opm/io/eclipse/rst/udq.cpp
opm-common/src/opm/io/eclipse/rst/well.cpp
opm-common/src/opm/output/eclipse/InteHEAD.cpp
opm-common/src/opm/output/eclipse/UDQDims.cpp
opm-common/src/opm/output/eclipse/CreateActionRSTDims.cpp
# 2022.06 additional includes
opm-common/src/opm/io/eclipse/rst/aquifer.cpp
opm-common/src/opm/io/eclipse/ERst.cpp
opm-common/src/opm/io/eclipse/RestartFileView.cpp
opm-common/cross-platform/windows/Substitutes.cpp