Use NNC info for well target generation and streamlines (#12279)

* Add support for NNC when growing clusters
* Trace streamlines through NNCs, too
This commit is contained in:
jonjenssen authored and GitHub committed 2025-03-21 13:00:49 +01:00
1 parent 4ccf67beb5
commit 540c8c3b36
7 files changed
+397 -196

No files matched your search

@@ -23,6 +23,7 @@
#include "RigEclipseCaseData.h" #include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h" #include "RigEclipseResultAddress.h"
#include "RigMainGrid.h" #include "RigMainGrid.h"
#include "RigNNCData.h"
#include "RigResultAccessor.h" #include "RigResultAccessor.h"
#include "RigResultAccessorFactory.h" #include "RigResultAccessorFactory.h"
@@ -75,6 +76,24 @@ bool RimStreamlineDataAccess::setupDataAccess( RigMainGrid* grid, RigEclipseCase
} }
} }
auto nncData = grid->nncData();
m_nncData.clear();
if ( nncData != nullptr )
{
m_nncData[RiaDefines::PhaseType::WATER_PHASE] =
nncData->dynamicConnectionScalarResultByName( RiaDefines::propertyNameFluxWat(), timeIdx );
m_nncData[RiaDefines::PhaseType::OIL_PHASE] =
nncData->dynamicConnectionScalarResultByName( RiaDefines::propertyNameFluxOil(), timeIdx );
m_nncData[RiaDefines::PhaseType::GAS_PHASE] =
nncData->dynamicConnectionScalarResultByName( RiaDefines::propertyNameFluxGas(), timeIdx );
}
else
{
m_nncData[RiaDefines::PhaseType::WATER_PHASE] = nullptr;
m_nncData[RiaDefines::PhaseType::OIL_PHASE] = nullptr;
m_nncData[RiaDefines::PhaseType::GAS_PHASE] = nullptr;
}
return true; return true;
} }
@@ -229,3 +248,50 @@ double RimStreamlineDataAccess::combinedFaceRate( RigCell
return retValue; return retValue;
} }
//--------------------------------------------------------------------------------------------------
/// Return the nnc scalar value for the given connection, by combining flow for all specified phases
/// Positive values is flow from cell1 to cell2, negative values is the other way
//--------------------------------------------------------------------------------------------------
double RimStreamlineDataAccess::combinedNNCRate( size_t resultIdx,
std::list<RiaDefines::PhaseType> phases,
double direction,
RiaDefines::PhaseType& outDominantPhase ) const
{
double retValue = 0.0;
outDominantPhase = phases.front();
double max = 0.0;
for ( auto phase : phases )
{
double tmp = 0.0;
if ( m_nncData.at( phase ) != nullptr )
{
if ( resultIdx < m_nncData.at( phase )->size() )
{
tmp = m_nncData.at( phase )->at( resultIdx );
}
}
if ( tmp * direction > max )
{
outDominantPhase = phase;
max = std::abs( tmp );
}
retValue += tmp;
}
return retValue;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
const RigConnection& RimStreamlineDataAccess::nncConnection( size_t idx ) const
{
auto nncData = m_grid->nncData();
return nncData->availableConnections()[idx];
}
@@ -33,6 +33,7 @@ class RigMainGrid;
class RigGridBase; class RigGridBase;
class RigResultAccessor; class RigResultAccessor;
class RigEclipseCaseData; class RigEclipseCaseData;
class RigConnection;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// Specialized data access for streamline generation. Operates using flow rate in meters/day /// Specialized data access for streamline generation. Operates using flow rate in meters/day
@@ -54,7 +55,14 @@ public:
double direction, double direction,
RiaDefines::PhaseType& dominantPhaseOut ) const; RiaDefines::PhaseType& dominantPhaseOut ) const;
const RigMainGrid* grid() const { return m_grid; } double combinedNNCRate( size_t resultIdx,
std::list<RiaDefines::PhaseType> phases,
double direction,
RiaDefines::PhaseType& outDominantPhase ) const;
RigMainGrid* grid() const { return m_grid; }
const RigConnection& nncConnection( size_t idx ) const;
protected: protected:
cvf::ref<RigResultAccessor> getDataAccessor( cvf::StructGridInterface::FaceType faceIdx, RiaDefines::PhaseType phase, int timeIdx ); cvf::ref<RigResultAccessor> getDataAccessor( cvf::StructGridInterface::FaceType faceIdx, RiaDefines::PhaseType phase, int timeIdx );
@@ -68,4 +76,5 @@ private:
RigEclipseCaseData* m_data; RigEclipseCaseData* m_data;
std::map<RiaDefines::PhaseType, std::vector<cvf::ref<RigResultAccessor>>> m_dataAccess; std::map<RiaDefines::PhaseType, std::vector<cvf::ref<RigResultAccessor>>> m_dataAccess;
std::map<RiaDefines::PhaseType, const std::vector<double>*> m_nncData;
}; };
@@ -20,6 +20,8 @@
#include "RigCell.h" #include "RigCell.h"
#include "RigMainGrid.h" #include "RigMainGrid.h"
#include "RigNNCData.h"
#include "RigNncConnection.h"
#include "RimStreamline.h" #include "RimStreamline.h"
#include "RimStreamlineDataAccess.h" #include "RimStreamlineDataAccess.h"
@@ -32,18 +34,22 @@
class StreamlineSeedPoint class StreamlineSeedPoint
{ {
public: public:
StreamlineSeedPoint( double rate, size_t cellIdx, cvf::StructGridInterface::FaceType faceIdx ) StreamlineSeedPoint( double rate, size_t index, RimStreamlineGenerator::CellFaceType faceIdx )
: m_rate( rate ) : m_rate( rate )
, m_cellIdx( cellIdx ) , m_index( index )
, m_faceIdx( faceIdx ){}; , m_faceIdx( faceIdx ){};
~StreamlineSeedPoint(){}; ~StreamlineSeedPoint(){};
bool operator<( const StreamlineSeedPoint& other ) const { return m_rate < other.m_rate; }; bool operator<( const StreamlineSeedPoint& other ) const { return rate() < other.rate(); };
public: double rate() const { return m_rate; };
double m_rate; size_t index() const { return m_index; };
size_t m_cellIdx; RimStreamlineGenerator::CellFaceType face() const { return m_faceIdx; };
cvf::StructGridInterface::FaceType m_faceIdx;
private:
double m_rate;
size_t m_index;
RimStreamlineGenerator::CellFaceType m_faceIdx;
}; };
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@@ -77,19 +83,27 @@ void RimStreamlineGenerator::generateTracer( RigCell cell, double direction, QSt
double rate = m_dataAccess->combinedFaceRate( cell, faceIdx, m_phases, direction, dominantPhase ) * direction; double rate = m_dataAccess->combinedFaceRate( cell, faceIdx, m_phases, direction, dominantPhase ) * direction;
if ( rate > m_flowThreshold ) if ( rate > m_flowThreshold )
{ {
m_seeds.push( StreamlineSeedPoint( rate, cellIdx, faceIdx ) ); m_seeds.emplace( rate, cellIdx, faceIdx );
} }
} }
// add any nnc connections from this cell, too
auto nncSeeds = nncCandidates( cell.mainGridCellIndex(), m_phases, direction );
for ( auto& seed : nncSeeds )
{
m_seeds.push( seed );
}
// keep adding streamlines until we have no more seeds left in our prioritized (by flow rate) list
while ( !m_seeds.empty() ) while ( !m_seeds.empty() )
{ {
const size_t cellIdx = m_seeds.top().m_cellIdx; auto& seed = m_seeds.top();
const cvf::StructGridInterface::FaceType faceIdx = m_seeds.top().m_faceIdx; const size_t index = seed.index();
const cvf::StructGridInterface::FaceType faceIdx = seed.face();
m_seeds.pop(); m_seeds.pop();
RimStreamline* streamline = new RimStreamline( simWellName ); RimStreamline* streamline = new RimStreamline( simWellName );
growStreamline( streamline, index, faceIdx, direction );
growStreamline( streamline, cellIdx, faceIdx, direction );
if ( direction < 0.0 ) streamline->reverse(); if ( direction < 0.0 ) streamline->reverse();
@@ -105,42 +119,86 @@ void RimStreamlineGenerator::generateTracer( RigCell cell, double direction, QSt
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RimStreamlineGenerator::growStreamline( RimStreamline* streamline, size_t cellIdx, cvf::StructGridInterface::FaceType faceIdx, double direction ) void RimStreamlineGenerator::growStreamline( RimStreamline* streamline, size_t index, CellFaceType faceIdx, double direction )
{ {
// get the cell double rate = 0.0;
RigCell cell = m_dataAccess->grid()->cell( cellIdx );
// get rate
RiaDefines::PhaseType dominantPhaseOut; RiaDefines::PhaseType dominantPhaseOut;
size_t currentCellIdx = 0;
RigCell currentCell;
double rate = m_dataAccess->combinedFaceRate( cell, faceIdx, m_phases, direction, dominantPhaseOut ); while ( true )
// if we go backwards from a producer, the rate needs to be flipped
rate *= direction;
// grow from start cell center to face center, exiting if we reach the max length
if ( !growStreamlineFromTo( streamline, cell.center(), cell.faceCenter( faceIdx ), rate, dominantPhaseOut ) ) return;
while ( rate >= m_flowThreshold )
{ {
// find next cell and entry face // no face? -> nnc connection
cell = cell.neighborCell( faceIdx ); if ( faceIdx == CellFaceType::NO_FACE )
if ( cell.isInvalid() ) break; {
faceIdx = cvf::StructGridInterface::oppositeFace( faceIdx ); const auto nncIdx = index;
RigConnection nnc = m_dataAccess->nncConnection( nncIdx );
// grow from given face center to cell center, exiting if we reach the max length size_t localCellIdx1 = 0;
if ( !growStreamlineFromTo( streamline, cell.faceCenter( faceIdx ), cell.center(), rate, dominantPhaseOut ) ) break; auto localGrid1 = m_dataAccess->grid()->gridAndGridLocalIdxFromGlobalCellIdx( nnc.c1GlobIdx(), &localCellIdx1 );
size_t localCellIdx2 = 0;
auto localGrid2 = m_dataAccess->grid()->gridAndGridLocalIdxFromGlobalCellIdx( nnc.c2GlobIdx(), &localCellIdx2 );
const size_t cellIdx = cell.gridLocalCellIndex(); // no support for LGRs, yet
if ( localGrid1->gridId() != 0 ) return;
if ( localGrid2->gridId() != 0 ) return;
if ( m_visitedCells.count( cellIdx ) > 0 ) break; RigCell cell1 = m_dataAccess->grid()->cell( localCellIdx1 );
if ( m_wellCells.count( cellIdx ) > 0 ) break; RigCell cell2 = m_dataAccess->grid()->cell( localCellIdx2 );
m_visitedCells.insert( cellIdx ); // get rate
rate = m_dataAccess->combinedNNCRate( nncIdx, m_phases, direction, dominantPhaseOut );
// if we go backwards from a producer, the rate needs to be flipped
rate *= direction;
// grow from cell1 center to cell2 center, exiting if we reach max length
if ( !growStreamlineFromTo( streamline, cell1.center(), cell2.center(), rate, dominantPhaseOut ) ) return;
// give up if too low rate
if ( rate < m_flowThreshold ) return;
currentCellIdx = localCellIdx2;
currentCell = cell2;
}
else
{
// get the current cell
const auto cellIdx = index;
RigCell cell = m_dataAccess->grid()->cell( cellIdx );
// get rate
rate = m_dataAccess->combinedFaceRate( cell, faceIdx, m_phases, direction, dominantPhaseOut );
// if we go backwards from a producer, the rate needs to be flipped
rate *= direction;
// grow from start cell center to face center, exiting if we reach the max length
if ( !growStreamlineFromTo( streamline, cell.center(), cell.faceCenter( faceIdx ), rate, dominantPhaseOut ) ) return;
// find next cell and entry face
currentCell = cell.neighborCell( faceIdx );
if ( currentCell.isInvalid() ) return;
faceIdx = cvf::StructGridInterface::oppositeFace( faceIdx );
// grow from given face center to neighbour cell center, exiting if we reach the max length
if ( !growStreamlineFromTo( streamline, currentCell.faceCenter( faceIdx ), currentCell.center(), rate, dominantPhaseOut ) )
break;
// give up if too low rate
if ( rate < m_flowThreshold ) return;
currentCellIdx = currentCell.gridLocalCellIndex();
}
// have we been here before?
if ( m_visitedCells.count( currentCellIdx ) > 0 ) return;
if ( m_wellCells.count( currentCellIdx ) > 0 ) return;
m_visitedCells.insert( currentCellIdx );
// find the face with max flow where we should exit the cell // find the face with max flow where we should exit the cell
cvf::StructGridInterface::FaceType exitFace = cvf::StructGridInterface::FaceType::NO_FACE; CellFaceType exitFace = cvf::StructGridInterface::FaceType::NO_FACE;
std::map<cvf::StructGridInterface::FaceType, double> rateMap; std::map<CellFaceType, double> rateMap;
double maxRate = 0.0; double maxRate = 0.0;
@@ -150,7 +208,7 @@ void RimStreamlineGenerator::growStreamline( RimStreamline* streamline, size_t c
if ( face == faceIdx ) continue; if ( face == faceIdx ) continue;
RiaDefines::PhaseType tempDominantFace; RiaDefines::PhaseType tempDominantFace;
double faceRate = m_dataAccess->combinedFaceRate( cell, face, m_phases, direction, tempDominantFace ); double faceRate = m_dataAccess->combinedFaceRate( currentCell, face, m_phases, direction, tempDominantFace );
// if we go backwards from a producer, the rate needs to be flipped // if we go backwards from a producer, the rate needs to be flipped
faceRate *= direction; faceRate *= direction;
@@ -160,27 +218,51 @@ void RimStreamlineGenerator::growStreamline( RimStreamline* streamline, size_t c
exitFace = face; exitFace = face;
maxRate = faceRate; maxRate = faceRate;
dominantPhaseOut = tempDominantFace; dominantPhaseOut = tempDominantFace;
index = currentCellIdx;
} }
rateMap[face] = faceRate; rateMap[face] = faceRate;
} }
// check if we have any NNC connections here
int nncId = -1;
auto nncConnections = nncCandidates( currentCellIdx, m_phases, direction );
for ( auto& nncPoint : nncConnections )
{
RiaDefines::PhaseType tempDominantFace;
double nncRate = m_dataAccess->combinedNNCRate( nncPoint.index(), m_phases, direction, tempDominantFace ) * direction;
if ( nncRate > maxRate )
{
nncId = (int)nncPoint.index();
maxRate = nncRate;
dominantPhaseOut = tempDominantFace;
exitFace = CellFaceType::NO_FACE;
}
}
// did we find an exit? // did we find an exit?
if ( exitFace == cvf::StructGridInterface::FaceType::NO_FACE ) break; if ( exitFace == cvf::StructGridInterface::FaceType::NO_FACE )
{
if ( nncId < 0 ) return;
index = (size_t)nncId;
for ( auto& nncPoint : nncConnections )
{
if ( nncPoint.index() == index ) continue;
m_seeds.push( nncPoint );
}
}
// add seeds for other faces with flow > threshold // add seeds for other faces with flow > threshold
for ( auto& kvp : rateMap ) for ( auto& kvp : rateMap )
{ {
if ( kvp.first == exitFace ) continue; if ( kvp.first == exitFace ) continue;
if ( kvp.second >= m_flowThreshold ) m_seeds.push( StreamlineSeedPoint( kvp.second, cell.gridLocalCellIndex(), kvp.first ) ); if ( kvp.second >= m_flowThreshold )
m_seeds.push( StreamlineSeedPoint( kvp.second, currentCell.gridLocalCellIndex(), kvp.first ) );
} }
rate = maxRate; rate = maxRate;
// grow from cell center to exit face center, stopping if we reach the max point limit
if ( !growStreamlineFromTo( streamline, cell.center(), cell.faceCenter( exitFace ), rate, dominantPhaseOut ) ) break;
faceIdx = exitFace; faceIdx = exitFace;
} }
} }
@@ -218,3 +300,31 @@ bool RimStreamlineGenerator::growStreamlineFromTo( RimStreamline* streaml
return true; return true;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::list<StreamlineSeedPoint> RimStreamlineGenerator::nncCandidates( size_t cellIdx, std::list<RiaDefines::PhaseType> phases, double direction )
{
std::list<StreamlineSeedPoint> foundCells;
auto mainGrid = m_dataAccess->grid();
if ( mainGrid->nncData() == nullptr ) return foundCells;
auto& connections = mainGrid->nncData()->allConnections();
for ( size_t i = 0; i < connections.size(); i++ )
{
if ( connections[i].c1GlobIdx() == cellIdx )
{
RiaDefines::PhaseType domPhase;
double rate = m_dataAccess->combinedNNCRate( i, phases, direction, domPhase ) * direction;
if ( rate > m_flowThreshold )
{
foundCells.emplace_back( rate, i, cvf::StructGridInterface::FaceType::NO_FACE );
}
}
}
return foundCells;
}
@@ -27,6 +27,7 @@
#include <list> #include <list>
#include <queue> #include <queue>
#include <set> #include <set>
#include <utility>
class RigCell; class RigCell;
class RimStreamline; class RimStreamline;
@@ -34,6 +35,9 @@ class StreamlineSeedPoint;
class RimStreamlineGenerator : public RimStreamlineGeneratorBase class RimStreamlineGenerator : public RimStreamlineGeneratorBase
{ {
public:
using CellFaceType = cvf::StructGridInterface::FaceType;
public: public:
RimStreamlineGenerator( std::set<size_t>& wellCells ); RimStreamlineGenerator( std::set<size_t>& wellCells );
~RimStreamlineGenerator(); ~RimStreamlineGenerator();
@@ -41,9 +45,11 @@ public:
void generateTracer( RigCell cell, double direction, QString simWellName, std::list<RimStreamline*>& outStreamlines ) override; void generateTracer( RigCell cell, double direction, QString simWellName, std::list<RimStreamline*>& outStreamlines ) override;
protected: protected:
void growStreamline( RimStreamline* streamline, size_t cellIdx, cvf::StructGridInterface::FaceType faceIdx, double direction ); void growStreamline( RimStreamline* streamline, size_t index, CellFaceType faceIdx, double direction );
bool growStreamlineFromTo( RimStreamline* streamline, cvf::Vec3d startPos, cvf::Vec3d endpos, double rate, RiaDefines::PhaseType dominantPhase ); bool growStreamlineFromTo( RimStreamline* streamline, cvf::Vec3d startPos, cvf::Vec3d endpos, double rate, RiaDefines::PhaseType dominantPhase );
std::list<StreamlineSeedPoint> nncCandidates( size_t cellIdx, std::list<RiaDefines::PhaseType> phases, double direction );
std::priority_queue<StreamlineSeedPoint> m_seeds; std::priority_queue<StreamlineSeedPoint> m_seeds;
}; };
@@ -436,6 +436,9 @@ void RimStreamlineInViewCollection::updateStreamlines()
auto eclView = firstAncestorOrThisOfType<RimEclipseView>(); auto eclView = firstAncestorOrThisOfType<RimEclipseView>();
if ( !eclView ) return; if ( !eclView ) return;
auto mainGrid = eclView->mainGrid();
if ( !mainGrid ) return;
if ( m_shouldGenerateTracers && isActive() ) if ( m_shouldGenerateTracers && isActive() )
{ {
// reset generated streamlines // reset generated streamlines
@@ -452,8 +455,8 @@ void RimStreamlineInViewCollection::updateStreamlines()
// set up the data access helper // set up the data access helper
RimStreamlineDataAccess dataAccess; RimStreamlineDataAccess dataAccess;
bool accessOk =
dataAccess.setupDataAccess( eclipseCase()->eclipseCaseData()->mainGrid(), eclipseCase()->eclipseCaseData(), phases(), timeIdx ); bool accessOk = dataAccess.setupDataAccess( mainGrid, eclipseCase()->eclipseCaseData(), phases(), timeIdx );
// did we find the data we needed? // did we find the data we needed?
if ( accessOk ) if ( accessOk )
@@ -25,8 +25,10 @@
#include "RigActiveCellInfo.h" #include "RigActiveCellInfo.h"
#include "RigCaseCellResultsData.h" #include "RigCaseCellResultsData.h"
#include "RigEclipseCaseData.h"
#include "RigEclipseResultAddress.h" #include "RigEclipseResultAddress.h"
#include "RigMainGrid.h" #include "RigMainGrid.h"
#include "RigNNCData.h"
#include "RigStatisticsMath.h" #include "RigStatisticsMath.h"
#include "RimEclipseCase.h" #include "RimEclipseCase.h"
@@ -69,8 +71,10 @@ void RigWellTargetCandidatesGenerator::generateCandidates( RimEclipseCase*
auto resultsData = eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL ); auto resultsData = eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
if ( !resultsData ) return; if ( !resultsData ) return;
std::vector<double> volume = getVolumeVector( *resultsData, volumeType, volumesType, volumeResultType, timeStepIdx ); DataContainer data;
if ( volume.empty() )
data.volume = getVolumeVector( *resultsData, volumeType, volumesType, volumeResultType, timeStepIdx );
if ( data.volume.empty() )
{ {
RiaLogging::error( "Unable to produce volume vector." ); RiaLogging::error( "Unable to produce volume vector." );
return; return;
@@ -78,31 +82,41 @@ void RigWellTargetCandidatesGenerator::generateCandidates( RimEclipseCase*
RigEclipseResultAddress pressureAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "PRESSURE" ); RigEclipseResultAddress pressureAddress( RiaDefines::ResultCatType::DYNAMIC_NATIVE, "PRESSURE" );
resultsData->ensureKnownResultLoaded( pressureAddress ); resultsData->ensureKnownResultLoaded( pressureAddress );
const std::vector<double>& pressure = resultsData->cellScalarResults( pressureAddress, timeStepIdx ); data.pressure = resultsData->cellScalarResults( pressureAddress, timeStepIdx );
RigEclipseResultAddress permeabilityXAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMX" ); RigEclipseResultAddress permeabilityXAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMX" );
resultsData->ensureKnownResultLoaded( permeabilityXAddress ); resultsData->ensureKnownResultLoaded( permeabilityXAddress );
const std::vector<double>& permeabilityX = resultsData->cellScalarResults( permeabilityXAddress, 0 ); data.permeabilityX = resultsData->cellScalarResults( permeabilityXAddress, 0 );
RigEclipseResultAddress permeabilityYAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMY" ); RigEclipseResultAddress permeabilityYAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMY" );
resultsData->ensureKnownResultLoaded( permeabilityYAddress ); resultsData->ensureKnownResultLoaded( permeabilityYAddress );
const std::vector<double>& permeabilityY = resultsData->cellScalarResults( permeabilityYAddress, 0 ); data.permeabilityY = resultsData->cellScalarResults( permeabilityYAddress, 0 );
RigEclipseResultAddress permeabilityZAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMZ" ); RigEclipseResultAddress permeabilityZAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "PERMZ" );
resultsData->ensureKnownResultLoaded( permeabilityZAddress ); resultsData->ensureKnownResultLoaded( permeabilityZAddress );
const std::vector<double>& permeabilityZ = resultsData->cellScalarResults( permeabilityZAddress, 0 ); data.permeabilityZ = resultsData->cellScalarResults( permeabilityZAddress, 0 );
RigEclipseResultAddress transmissibilityXAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANX" ); RigEclipseResultAddress transmissibilityXAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANX" );
resultsData->ensureKnownResultLoaded( transmissibilityXAddress ); resultsData->ensureKnownResultLoaded( transmissibilityXAddress );
const std::vector<double>& transmissibilityX = resultsData->cellScalarResults( transmissibilityXAddress, 0 ); data.transmissibilityX = resultsData->cellScalarResults( transmissibilityXAddress, 0 );
RigEclipseResultAddress transmissibilityYAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANY" ); RigEclipseResultAddress transmissibilityYAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANY" );
resultsData->ensureKnownResultLoaded( transmissibilityYAddress ); resultsData->ensureKnownResultLoaded( transmissibilityYAddress );
const std::vector<double>& transmissibilityY = resultsData->cellScalarResults( transmissibilityYAddress, 0 ); data.transmissibilityY = resultsData->cellScalarResults( transmissibilityYAddress, 0 );
RigEclipseResultAddress transmissibilityZAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANZ" ); RigEclipseResultAddress transmissibilityZAddress( RiaDefines::ResultCatType::STATIC_NATIVE, "TRANZ" );
resultsData->ensureKnownResultLoaded( transmissibilityZAddress ); resultsData->ensureKnownResultLoaded( transmissibilityZAddress );
const std::vector<double>& transmissibilityZ = resultsData->cellScalarResults( transmissibilityZAddress, 0 ); data.transmissibilityZ = resultsData->cellScalarResults( transmissibilityZAddress, 0 );
auto mainGrid = eclipseCase->eclipseCaseData()->mainGrid();
if ( mainGrid != nullptr )
{
data.transmissibilityNNC = mainGrid->nncData()->staticConnectionScalarResultByName( RiaDefines::propertyNameCombTrans() );
}
else
{
data.transmissibilityNNC = nullptr;
}
std::vector<double> filterVector; std::vector<double> filterVector;
if ( limits.filterAddress.isValid() ) if ( limits.filterAddress.isValid() )
@@ -112,7 +126,7 @@ void RigWellTargetCandidatesGenerator::generateCandidates( RimEclipseCase*
} }
else else
{ {
filterVector.resize( pressure.size(), std::numeric_limits<double>::infinity() ); filterVector.resize( data.pressure.size(), std::numeric_limits<double>::infinity() );
} }
std::vector<int> clusters( activeCellCount.value(), 0 ); std::vector<int> clusters( activeCellCount.value(), 0 );
@@ -122,19 +136,7 @@ void RigWellTargetCandidatesGenerator::generateCandidates( RimEclipseCase*
int numClustersFound = 0; int numClustersFound = 0;
for ( int clusterId = 1; clusterId <= numClusters; clusterId++ ) for ( int clusterId = 1; clusterId <= numClusters; clusterId++ )
{ {
std::optional<caf::VecIjk> startCell = findStartCell( eclipseCase, std::optional<caf::VecIjk> startCell = findStartCell( eclipseCase, timeStepIdx, limits, data, filterVector, clusters );
timeStepIdx,
limits,
volume,
pressure,
permeabilityX,
permeabilityY,
permeabilityZ,
transmissibilityX,
transmissibilityY,
transmissibilityZ,
filterVector,
clusters );
if ( startCell.has_value() ) if ( startCell.has_value() )
{ {
@@ -144,22 +146,7 @@ void RigWellTargetCandidatesGenerator::generateCandidates( RimEclipseCase*
.arg( startCell->j() + 1 ) .arg( startCell->j() + 1 )
.arg( startCell->k() + 1 ) ); .arg( startCell->k() + 1 ) );
growCluster( eclipseCase, growCluster( eclipseCase, startCell.value(), limits, data, filterVector, clusters, clusterId, timeStepIdx, maxIterations );
startCell.value(),
limits,
volume,
pressure,
permeabilityX,
permeabilityY,
permeabilityZ,
transmissibilityX,
transmissibilityY,
transmissibilityZ,
filterVector,
clusters,
clusterId,
timeStepIdx,
maxIterations );
numClustersFound++; numClustersFound++;
} }
else else
@@ -191,13 +178,19 @@ void RigWellTargetCandidatesGenerator::generateCandidates( RimEclipseCase*
} }
} }
std::vector<ClusterStatistics> statistics = std::vector<ClusterStatistics> statistics = generateStatistics( eclipseCase,
generateStatistics( eclipseCase, pressure, permeabilityX, permeabilityY, permeabilityZ, numClustersFound, timeStepIdx, resultName ); data.pressure,
std::vector<double> totalPorvSoil( clusters.size(), std::numeric_limits<double>::infinity() ); data.permeabilityX,
std::vector<double> totalPorvSgas( clusters.size(), std::numeric_limits<double>::infinity() ); data.permeabilityY,
std::vector<double> totalPorvSoilAndSgas( clusters.size(), std::numeric_limits<double>::infinity() ); data.permeabilityZ,
std::vector<double> totalFipOil( clusters.size(), std::numeric_limits<double>::infinity() ); numClustersFound,
std::vector<double> totalFipGas( clusters.size(), std::numeric_limits<double>::infinity() ); timeStepIdx,
resultName );
std::vector<double> totalPorvSoil( clusters.size(), std::numeric_limits<double>::infinity() );
std::vector<double> totalPorvSgas( clusters.size(), std::numeric_limits<double>::infinity() );
std::vector<double> totalPorvSoilAndSgas( clusters.size(), std::numeric_limits<double>::infinity() );
std::vector<double> totalFipOil( clusters.size(), std::numeric_limits<double>::infinity() );
std::vector<double> totalFipGas( clusters.size(), std::numeric_limits<double>::infinity() );
auto addValuesForClusterId = []( std::vector<double>& values, const std::vector<int>& clusters, int clusterId, double value ) auto addValuesForClusterId = []( std::vector<double>& values, const std::vector<int>& clusters, int clusterId, double value )
{ {
@@ -209,7 +202,7 @@ void RigWellTargetCandidatesGenerator::generateCandidates( RimEclipseCase*
}; };
int clusterId = 1; int clusterId = 1;
for ( auto s : statistics ) for ( const auto& s : statistics )
{ {
RiaLogging::info( QString( "Cluster #%1 Statistics" ).arg( s.id ) ); RiaLogging::info( QString( "Cluster #%1 Statistics" ).arg( s.id ) );
RiaLogging::info( QString( "Number of cells: %1" ).arg( s.numCells ) ); RiaLogging::info( QString( "Number of cells: %1" ).arg( s.numCells ) );
@@ -252,14 +245,7 @@ void RigWellTargetCandidatesGenerator::generateCandidates( RimEclipseCase*
std::optional<caf::VecIjk> RigWellTargetCandidatesGenerator::findStartCell( RimEclipseCase* eclipseCase, std::optional<caf::VecIjk> RigWellTargetCandidatesGenerator::findStartCell( RimEclipseCase* eclipseCase,
size_t timeStepIdx, size_t timeStepIdx,
const ClusteringLimits& limits, const ClusteringLimits& limits,
const std::vector<double>& volume, const DataContainer& data,
const std::vector<double>& pressure,
const std::vector<double>& permeabilityX,
const std::vector<double>& permeabilityY,
const std::vector<double>& permeabilityZ,
const std::vector<double>& transmissibilityX,
const std::vector<double>& transmissibilityY,
const std::vector<double>& transmissibilityZ,
const std::vector<double>& filterVector, const std::vector<double>& filterVector,
const std::vector<int>& clusters ) const std::vector<int>& clusters )
{ {
@@ -278,12 +264,12 @@ std::optional<caf::VecIjk> RigWellTargetCandidatesGenerator::findStartCell( RimE
size_t resultIndex = resultsData->activeCellInfo()->cellResultIndex( reservoirCellIdx ); size_t resultIndex = resultsData->activeCellInfo()->cellResultIndex( reservoirCellIdx );
if ( resultIndex != cvf::UNDEFINED_SIZE_T && clusters[resultIndex] == 0 ) if ( resultIndex != cvf::UNDEFINED_SIZE_T && clusters[resultIndex] == 0 )
{ {
const double cellVolume = volume[resultIndex]; const double cellVolume = data.volume[resultIndex];
const double cellPressure = pressure[resultIndex]; const double cellPressure = data.pressure[resultIndex];
const double cellPermeabiltyX = permeabilityX[resultIndex]; const double cellPermeabiltyX = data.permeabilityX[resultIndex];
const double cellPermeabiltyY = permeabilityY[resultIndex]; const double cellPermeabiltyY = data.permeabilityY[resultIndex];
const double cellPermeabiltyZ = permeabilityZ[resultIndex]; const double cellPermeabiltyZ = data.permeabilityZ[resultIndex];
const bool permeabilityValidInAnyDirection = ( cellPermeabiltyX >= limits.permeability || cellPermeabiltyY >= limits.permeability || const bool permeabilityValidInAnyDirection = ( cellPermeabiltyX >= limits.permeability || cellPermeabiltyY >= limits.permeability ||
cellPermeabiltyZ >= limits.permeability ); cellPermeabiltyZ >= limits.permeability );
@@ -309,14 +295,7 @@ std::optional<caf::VecIjk> RigWellTargetCandidatesGenerator::findStartCell( RimE
void RigWellTargetCandidatesGenerator::growCluster( RimEclipseCase* eclipseCase, void RigWellTargetCandidatesGenerator::growCluster( RimEclipseCase* eclipseCase,
const caf::VecIjk& startCell, const caf::VecIjk& startCell,
const ClusteringLimits& limits, const ClusteringLimits& limits,
const std::vector<double>& volume, const DataContainer& data,
const std::vector<double>& pressure,
const std::vector<double>& permeabilityX,
const std::vector<double>& permeabilityY,
const std::vector<double>& permeabilityZ,
const std::vector<double>& transmissibilityX,
const std::vector<double>& transmissibilityY,
const std::vector<double>& transmissibilityZ,
const std::vector<double>& filterVector, const std::vector<double>& filterVector,
std::vector<int>& clusters, std::vector<int>& clusters,
int clusterId, int clusterId,
@@ -332,19 +311,7 @@ void RigWellTargetCandidatesGenerator::growCluster( RimEclipseCase* e
for ( int i = 0; i < maxIterations; i++ ) for ( int i = 0; i < maxIterations; i++ )
{ {
foundCells = findCandidates( *eclipseCase, foundCells = findCandidates( eclipseCase, foundCells, limits, data, filterVector, clusters );
foundCells,
limits,
volume,
pressure,
permeabilityX,
permeabilityY,
permeabilityZ,
transmissibilityX,
transmissibilityY,
transmissibilityZ,
filterVector,
clusters );
if ( foundCells.empty() ) break; if ( foundCells.empty() ) break;
assignClusterIdToCells( *resultsData->activeCellInfo(), foundCells, clusters, clusterId ); assignClusterIdToCells( *resultsData->activeCellInfo(), foundCells, clusters, clusterId );
} }
@@ -353,24 +320,18 @@ void RigWellTargetCandidatesGenerator::growCluster( RimEclipseCase* e
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::vector<size_t> RigWellTargetCandidatesGenerator::findCandidates( const RimEclipseCase& eclipseCase, std::vector<size_t> RigWellTargetCandidatesGenerator::findCandidates( RimEclipseCase* eclipseCase,
const std::vector<size_t>& previousCells, const std::vector<size_t>& previousCells,
const ClusteringLimits& limits, const ClusteringLimits& limits,
const std::vector<double>& volume, const DataContainer& data,
const std::vector<double>& pressure,
const std::vector<double>& permeabilityX,
const std::vector<double>& permeabilityY,
const std::vector<double>& permeabilityZ,
const std::vector<double>& transmissibilityX,
const std::vector<double>& transmissibilityY,
const std::vector<double>& transmissibilityZ,
const std::vector<double>& filterVector, const std::vector<double>& filterVector,
std::vector<int>& clusters ) std::vector<int>& clusters )
{ {
std::vector<size_t> candidates; std::vector<size_t> candidates;
auto resultsData = eclipseCase.results( RiaDefines::PorosityModelType::MATRIX_MODEL ); auto resultsData = eclipseCase->results( RiaDefines::PorosityModelType::MATRIX_MODEL );
auto mainGrid = eclipseCase->eclipseCaseData()->mainGrid();
const std::vector<cvf::StructGridInterface::FaceType> faces = { const std::vector<CellFaceType> faces = {
cvf::StructGridInterface::FaceType::POS_I, cvf::StructGridInterface::FaceType::POS_I,
cvf::StructGridInterface::FaceType::NEG_I, cvf::StructGridInterface::FaceType::NEG_I,
cvf::StructGridInterface::FaceType::POS_J, cvf::StructGridInterface::FaceType::POS_J,
@@ -381,7 +342,7 @@ std::vector<size_t> RigWellTargetCandidatesGenerator::findCandidates( const RimE
for ( size_t cellIdx : previousCells ) for ( size_t cellIdx : previousCells )
{ {
const RigCell& cell = eclipseCase.mainGrid()->cell( cellIdx ); const RigCell& cell = mainGrid->cell( cellIdx );
if ( cell.isInvalid() ) continue; if ( cell.isInvalid() ) continue;
RigGridBase* grid = cell.hostGrid(); RigGridBase* grid = cell.hostGrid();
@@ -392,7 +353,7 @@ std::vector<size_t> RigWellTargetCandidatesGenerator::findCandidates( const RimE
grid->ijkFromCellIndex( gridLocalCellIndex, &i, &j, &k ); grid->ijkFromCellIndex( gridLocalCellIndex, &i, &j, &k );
for ( cvf::StructGridInterface::FaceType face : faces ) for ( CellFaceType face : faces )
{ {
size_t gridLocalNeighborCellIdx; size_t gridLocalNeighborCellIdx;
if ( grid->cellIJKNeighbor( i, j, k, face, &gridLocalNeighborCellIdx ) ) if ( grid->cellIJKNeighbor( i, j, k, face, &gridLocalNeighborCellIdx ) )
@@ -401,16 +362,17 @@ std::vector<size_t> RigWellTargetCandidatesGenerator::findCandidates( const RimE
size_t neighborResultIndex = resultsData->activeCellInfo()->cellResultIndex( neighborResvCellIdx ); size_t neighborResultIndex = resultsData->activeCellInfo()->cellResultIndex( neighborResvCellIdx );
if ( neighborResultIndex != cvf::UNDEFINED_SIZE_T && clusters[neighborResultIndex] == 0 ) if ( neighborResultIndex != cvf::UNDEFINED_SIZE_T && clusters[neighborResultIndex] == 0 )
{ {
double permeability = getValueForFace( permeabilityX, permeabilityY, permeabilityZ, face, neighborResultIndex ); double permeability =
double transmissibility = getTransmissibilityValueForFace( transmissibilityX, getValueForFace( data.permeabilityX, data.permeabilityY, data.permeabilityZ, face, neighborResultIndex );
transmissibilityY, double transmissibility = getTransmissibilityValueForFace( data.transmissibilityX,
transmissibilityZ, data.transmissibilityY,
data.transmissibilityZ,
face, face,
resultIndex, resultIndex,
neighborResultIndex ); neighborResultIndex );
bool filterValue = !std::isinf( filterVector[neighborResultIndex] ) && filterVector[neighborResultIndex] > 0.0; bool filterValue = !std::isinf( filterVector[neighborResultIndex] ) && filterVector[neighborResultIndex] > 0.0;
if ( volume[neighborResultIndex] > limits.volume && pressure[neighborResultIndex] > limits.pressure && if ( data.volume[neighborResultIndex] > limits.volume && data.pressure[neighborResultIndex] > limits.pressure &&
permeability > limits.permeability && transmissibility > limits.transmissibility && filterValue ) permeability > limits.permeability && transmissibility > limits.transmissibility && filterValue )
{ {
candidates.push_back( neighborResvCellIdx ); candidates.push_back( neighborResvCellIdx );
@@ -419,6 +381,29 @@ std::vector<size_t> RigWellTargetCandidatesGenerator::findCandidates( const RimE
} }
} }
} }
if ( data.transmissibilityNNC != nullptr )
{
auto nncCells = nncConnectionCellAndResult( cellIdx, mainGrid );
for ( auto& [cellInfo, nncResultIdx] : nncCells )
{
auto& [otherCellIdx, face] = cellInfo;
double transmissibility = data.transmissibilityNNC->at( nncResultIdx );
size_t otherResultIndex = resultsData->activeCellInfo()->cellResultIndex( otherCellIdx );
double permeability = getValueForFace( data.permeabilityX, data.permeabilityY, data.permeabilityZ, face, otherResultIndex );
bool filterValue = !std::isinf( filterVector[otherResultIndex] ) && filterVector[otherResultIndex] > 0.0;
if ( data.volume[otherResultIndex] > limits.volume && data.pressure[otherResultIndex] > limits.pressure &&
permeability > limits.permeability && transmissibility > limits.transmissibility && filterValue )
{
candidates.push_back( otherCellIdx );
clusters[otherResultIndex] = -1;
}
}
}
} }
return candidates; return candidates;
@@ -531,11 +516,11 @@ std::optional<size_t> RigWellTargetCandidatesGenerator::getActiveCellCount( RimE
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
double RigWellTargetCandidatesGenerator::getValueForFace( const std::vector<double>& x, double RigWellTargetCandidatesGenerator::getValueForFace( const std::vector<double>& x,
const std::vector<double>& y, const std::vector<double>& y,
const std::vector<double>& z, const std::vector<double>& z,
cvf::StructGridInterface::FaceType face, CellFaceType face,
size_t resultIndex ) size_t resultIndex )
{ {
if ( face == cvf::StructGridInterface::FaceType::POS_I || face == cvf::StructGridInterface::FaceType::NEG_I ) return x[resultIndex]; if ( face == cvf::StructGridInterface::FaceType::POS_I || face == cvf::StructGridInterface::FaceType::NEG_I ) return x[resultIndex];
if ( face == cvf::StructGridInterface::FaceType::POS_J || face == cvf::StructGridInterface::FaceType::NEG_J ) return y[resultIndex]; if ( face == cvf::StructGridInterface::FaceType::POS_J || face == cvf::StructGridInterface::FaceType::NEG_J ) return y[resultIndex];
@@ -546,12 +531,12 @@ double RigWellTargetCandidatesGenerator::getValueForFace( const std::vector<doub
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
double RigWellTargetCandidatesGenerator::getTransmissibilityValueForFace( const std::vector<double>& x, double RigWellTargetCandidatesGenerator::getTransmissibilityValueForFace( const std::vector<double>& x,
const std::vector<double>& y, const std::vector<double>& y,
const std::vector<double>& z, const std::vector<double>& z,
cvf::StructGridInterface::FaceType face, CellFaceType face,
size_t resultIndex, size_t resultIndex,
size_t neighborResultIndex ) size_t neighborResultIndex )
{ {
// For negative directions (NEG_I, NEG_J, NEG_K) use the value from the neighbor cell // For negative directions (NEG_I, NEG_J, NEG_K) use the value from the neighbor cell
bool isPos = face == cvf::StructGridInterface::FaceType::POS_I || face == cvf::StructGridInterface::FaceType::POS_J || bool isPos = face == cvf::StructGridInterface::FaceType::POS_I || face == cvf::StructGridInterface::FaceType::POS_J ||
@@ -959,3 +944,25 @@ cvf::BoundingBox RigWellTargetCandidatesGenerator::computeBoundingBoxForResult(
return boundingBox; return boundingBox;
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::list<std::pair<std::pair<size_t, RigWellTargetCandidatesGenerator::CellFaceType>, size_t>>
RigWellTargetCandidatesGenerator::nncConnectionCellAndResult( size_t cellIdx, RigMainGrid* mainGrid )
{
std::list<std::pair<std::pair<size_t, CellFaceType>, size_t>> foundCells;
if ( mainGrid->nncData() == nullptr ) return foundCells;
auto& connections = mainGrid->nncData()->allConnections();
for ( size_t i = 0; i < connections.size(); i++ )
{
if ( connections[i].c1GlobIdx() == cellIdx )
{
foundCells.push_back( std::make_pair( std::make_pair( connections[i].c2GlobIdx(), connections[i].face() ), i ) );
}
}
return foundCells;
}
@@ -25,11 +25,14 @@
#include "RigEclipseResultAddress.h" #include "RigEclipseResultAddress.h"
#include <list>
#include <map> #include <map>
#include <optional> #include <optional>
#include <utility>
class RigActiveCellInfo; class RigActiveCellInfo;
class RigCaseCellResultsData; class RigCaseCellResultsData;
class RigMainGrid;
class RimEclipseCase; class RimEclipseCase;
class RimEclipseCaseEnsemble; class RimEclipseCaseEnsemble;
class RimRegularGridCase; class RimRegularGridCase;
@@ -41,6 +44,8 @@ class RimRegularGridCase;
class RigWellTargetCandidatesGenerator class RigWellTargetCandidatesGenerator
{ {
public: public:
using CellFaceType = cvf::StructGridInterface::FaceType;
enum class VolumeType enum class VolumeType
{ {
OIL, OIL,
@@ -72,6 +77,20 @@ public:
RigEclipseResultAddress filterAddress; RigEclipseResultAddress filterAddress;
}; };
struct DataContainer
{
std::vector<double> volume;
std::vector<double> pressure;
std::vector<double> permeabilityX;
std::vector<double> permeabilityY;
std::vector<double> permeabilityZ;
std::vector<double> permeabilityNNC;
std::vector<double> transmissibilityX;
std::vector<double> transmissibilityY;
std::vector<double> transmissibilityZ;
const std::vector<double>* transmissibilityNNC;
};
static void generateCandidates( RimEclipseCase* eclipseCase, static void generateCandidates( RimEclipseCase* eclipseCase,
size_t timeStepIdx, size_t timeStepIdx,
VolumeType volumeType, VolumeType volumeType,
@@ -124,45 +143,24 @@ private:
static std::optional<caf::VecIjk> findStartCell( RimEclipseCase* eclipseCase, static std::optional<caf::VecIjk> findStartCell( RimEclipseCase* eclipseCase,
size_t timeStepIdx, size_t timeStepIdx,
const ClusteringLimits& limits, const ClusteringLimits& limits,
const std::vector<double>& volume, const DataContainer& data,
const std::vector<double>& pressure,
const std::vector<double>& permeabilityX,
const std::vector<double>& permeabilityY,
const std::vector<double>& permeabilityZ,
const std::vector<double>& transmissibilityX,
const std::vector<double>& transmissibilityY,
const std::vector<double>& transmissibilityZ,
const std::vector<double>& filterVector, const std::vector<double>& filterVector,
const std::vector<int>& clusters ); const std::vector<int>& clusters );
static void growCluster( RimEclipseCase* eclipseCase, static void growCluster( RimEclipseCase* eclipseCase,
const caf::VecIjk& startCell, const caf::VecIjk& startCell,
const ClusteringLimits& limits, const ClusteringLimits& limits,
const std::vector<double>& volume, const DataContainer& data,
const std::vector<double>& pressure,
const std::vector<double>& permeabilityX,
const std::vector<double>& permeabilityY,
const std::vector<double>& permeabilityZ,
const std::vector<double>& transmissibilityX,
const std::vector<double>& transmissibilityY,
const std::vector<double>& transmissibilityZ,
const std::vector<double>& filterVector, const std::vector<double>& filterVector,
std::vector<int>& clusters, std::vector<int>& clusters,
int clusterId, int clusterId,
size_t timeStepIdx, size_t timeStepIdx,
int maxIterations ); int maxIterations );
static std::vector<size_t> findCandidates( const RimEclipseCase& eclipseCase, static std::vector<size_t> findCandidates( RimEclipseCase* eclipseCase,
const std::vector<size_t>& previousCells, const std::vector<size_t>& previousCells,
const ClusteringLimits& limits, const ClusteringLimits& limits,
const std::vector<double>& volume, const DataContainer& data,
const std::vector<double>& pressure,
const std::vector<double>& permeabilityX,
const std::vector<double>& permeabilityY,
const std::vector<double>& permeabilityZ,
const std::vector<double>& transmissibilityX,
const std::vector<double>& transmissibilityY,
const std::vector<double>& transmissibilityZ,
const std::vector<double>& filterVector, const std::vector<double>& filterVector,
std::vector<int>& clusters ); std::vector<int>& clusters );
@@ -179,18 +177,18 @@ private:
static void createResultVector( RimEclipseCase& eclipseCase, const QString& resultName, const std::vector<int>& clusterIds, double value ); static void createResultVector( RimEclipseCase& eclipseCase, const QString& resultName, const std::vector<int>& clusterIds, double value );
static double getValueForFace( const std::vector<double>& x, static double getValueForFace( const std::vector<double>& x,
const std::vector<double>& y, const std::vector<double>& y,
const std::vector<double>& z, const std::vector<double>& z,
cvf::StructGridInterface::FaceType face, CellFaceType face,
size_t resultIndex ); size_t resultIndex );
static double getTransmissibilityValueForFace( const std::vector<double>& x, static double getTransmissibilityValueForFace( const std::vector<double>& x,
const std::vector<double>& y, const std::vector<double>& y,
const std::vector<double>& z, const std::vector<double>& z,
cvf::StructGridInterface::FaceType face, CellFaceType face,
size_t resultIndex, size_t resultIndex,
size_t neighborResultIndex ); size_t neighborResultIndex );
static std::vector<RigWellTargetCandidatesGenerator::ClusterStatistics> generateStatistics( RimEclipseCase* eclipseCase, static std::vector<RigWellTargetCandidatesGenerator::ClusterStatistics> generateStatistics( RimEclipseCase* eclipseCase,
const std::vector<double>& pressure, const std::vector<double>& pressure,
@@ -211,4 +209,6 @@ private:
std::vector<int>& occupancy ); std::vector<int>& occupancy );
static cvf::BoundingBox computeBoundingBoxForResult( RimEclipseCase& eclipseCase, const QString& resultName, size_t timeStepIndex ); static cvf::BoundingBox computeBoundingBoxForResult( RimEclipseCase& eclipseCase, const QString& resultName, size_t timeStepIndex );
static std::list<std::pair<std::pair<size_t, CellFaceType>, size_t>> nncConnectionCellAndResult( size_t cellIdx, RigMainGrid* mainGrid );
}; };