Improved simulation well visualization

* Move members to private in RigWellResultPoint
* Create simulation well path geometry using well topology
* Add separate MSW well pipe centerline computations
* Review comments

---------

Co-authored-by: magnesj <magnesj@users.noreply.github.com>
This commit is contained in:
Magne Sjaastad 2023-02-28 16:06:37 +01:00 committed by GitHub
parent 9b12885c23
commit d2f435c00a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 976 additions and 241 deletions

View File

@ -1268,11 +1268,10 @@ size_t localGridCellIndexFromErtConnection( const RigGridBase* grid, const well_
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigWellResultPoint RifReaderEclipseOutput::createWellResultPoint( const RigGridBase* grid,
const well_conn_type* ert_connection,
int ertBranchId,
int ertSegmentId,
const char* wellName )
RigWellResultPoint RifReaderEclipseOutput::createWellResultPoint( const RigGridBase* grid,
const well_conn_type* ert_connection,
const well_segment_type* segment,
const char* wellName )
{
CVF_ASSERT( ert_connection );
CVF_ASSERT( grid );
@ -1290,25 +1289,47 @@ RigWellResultPoint RifReaderEclipseOutput::createWellResultPoint( const RigGridB
if ( gridCellIndex != cvf::UNDEFINED_SIZE_T )
{
resultPoint.m_gridIndex = grid->gridIndex();
resultPoint.m_gridCellIndex = gridCellIndex;
int branchId = -1, segmentId = -1, outletBranchId = -1, outletSegmentId = -1;
resultPoint.m_isOpen = isCellOpen;
if ( segment )
{
branchId = well_segment_get_branch_id( segment );
segmentId = well_segment_get_id( segment );
resultPoint.m_ertBranchId = ertBranchId;
resultPoint.m_ertSegmentId = ertSegmentId;
resultPoint.m_flowRate = volumeRate;
resultPoint.m_oilRate = oilRate;
resultPoint.m_waterRate = waterRate;
auto outletSegment = well_segment_get_outlet( segment );
if ( outletSegment )
{
outletBranchId = well_segment_get_branch_id( outletSegment );
outletSegmentId = well_segment_get_id( outletSegment );
}
}
resultPoint.m_gasRate = RiaEclipseUnitTools::convertSurfaceGasFlowRateToOilEquivalents( m_eclipseCase->unitsType(), gasRate );
resultPoint.setGridIndex( grid->gridIndex() );
resultPoint.setGridCellIndex( gridCellIndex );
resultPoint.m_connectionFactor = connectionFactor;
resultPoint.setIsOpen( isCellOpen );
resultPoint.setSegmentData( branchId, segmentId );
resultPoint.setOutletSegmentData( outletBranchId, outletSegmentId );
const double adjustedGasRate = RiaEclipseUnitTools::convertSurfaceGasFlowRateToOilEquivalents( m_eclipseCase->unitsType(), gasRate );
resultPoint.setFlowData( volumeRate, oilRate, adjustedGasRate, waterRate );
resultPoint.setConnectionFactor( connectionFactor );
}
return resultPoint;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RigWellResultPoint
RifReaderEclipseOutput::createWellResultPoint( const RigGridBase* grid, const well_conn_type* ert_connection, const char* wellName )
{
return createWellResultPoint( grid, ert_connection, nullptr, wellName );
}
//--------------------------------------------------------------------------------------------------
/// Inverse distance interpolation of the supplied points and distance weights for
/// the contributing points which are closest above, and closest below
@ -1493,8 +1514,8 @@ public:
{
if ( !wellResultPoint.isCell() ) return false;
size_t gridIndex = wellResultPoint.m_gridIndex;
size_t gridCellIndex = wellResultPoint.m_gridCellIndex;
size_t gridIndex = wellResultPoint.gridIndex();
size_t gridCellIndex = wellResultPoint.cellIndex();
size_t reservoirCellIdx = m_mainGrid->reservoirCellIndexByGridAndGridLocalCellIndex( gridIndex, gridCellIndex );
@ -1657,11 +1678,11 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
const well_conn_type* ert_wellhead = well_state_iget_wellhead( ert_well_state, static_cast<int>( gridNr ) );
if ( ert_wellhead )
{
wellResFrame.m_wellHead = createWellResultPoint( grids[gridNr], ert_wellhead, -1, -1, wellName );
wellResFrame.m_wellHead = createWellResultPoint( grids[gridNr], ert_wellhead, wellName );
// HACK: Ert returns open as "this is equally wrong as closed for well heads".
// Well heads are not open jfr mail communication with HHGS and JH Statoil 07.01.2016
wellResFrame.m_wellHead.m_isOpen = false;
wellResFrame.m_wellHead.setIsOpen( false );
break;
}
}
@ -1717,7 +1738,7 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
{
well_conn_type* ert_connection = well_conn_collection_iget( connections, connIdx );
wellResultBranch.m_branchResultPoints.push_back(
createWellResultPoint( grids[gridNr], ert_connection, branchId, well_segment_get_id( segment ), wellName ) );
createWellResultPoint( grids[gridNr], ert_connection, segment, wellName ) );
}
segmentHasConnections = true;
@ -1725,11 +1746,10 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
// Prepare data for segment position calculation
well_conn_type* ert_connection = well_conn_collection_iget( connections, 0 );
RigWellResultPoint point =
createWellResultPoint( grids[gridNr], ert_connection, branchId, well_segment_get_id( segment ), wellName );
lastConnectionPos = grids[gridNr]->cell( point.m_gridCellIndex ).center();
RigWellResultPoint point = createWellResultPoint( grids[gridNr], ert_connection, segment, wellName );
lastConnectionPos = grids[gridNr]->cell( point.cellIndex() ).center();
cvf::Vec3d cellVxes[8];
grids[gridNr]->cellCornerVertices( point.m_gridCellIndex, cellVxes );
grids[gridNr]->cellCornerVertices( point.cellIndex(), cellVxes );
lastConnectionCellCorner = cellVxes[0];
lastConnectionCellSize = ( lastConnectionPos - cellVxes[0] ).length();
@ -1747,8 +1767,7 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
if ( !segmentHasConnections )
{
RigWellResultPoint data;
data.m_ertBranchId = branchId;
data.m_ertSegmentId = well_segment_get_id( segment );
data.setSegmentData( branchId, well_segment_get_id( segment ) );
wellResultBranch.m_branchResultPoints.push_back( data );
@ -1801,11 +1820,7 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
// Select the deepest connection
well_conn_type* ert_connection = well_conn_collection_iget( connections, connectionCount - 1 );
auto resultPoint = createWellResultPoint( grids[gridNr],
ert_connection,
well_segment_get_branch_id( outletSegment ),
well_segment_get_id( outletSegment ),
wellName );
auto resultPoint = createWellResultPoint( grids[gridNr], ert_connection, outletSegment, wellName );
// This result point is only supposed to be used to indicate connection to a parent well
// Clear all flow in this result point
resultPoint.clearAllFlow();
@ -1822,8 +1837,7 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
// Store the result point
RigWellResultPoint data;
data.m_ertBranchId = well_segment_get_branch_id( outletSegment );
data.m_ertSegmentId = well_segment_get_id( outletSegment );
data.setSegmentData( well_segment_get_branch_id( outletSegment ), well_segment_get_id( outletSegment ) );
wellResultBranch.m_branchResultPoints.push_back( data );
// Store data for segment position calculation,
@ -1954,17 +1968,12 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
prevResPoint = wellResultBranch.m_branchResultPoints[rpIdx - 1];
}
cvf::Vec3d lastConnectionPos = grids[prevResPoint.m_gridIndex]->cell( prevResPoint.m_gridCellIndex ).center();
cvf::Vec3d lastConnectionPos = grids[prevResPoint.gridIndex()]->cell( prevResPoint.cellIndex() ).center();
SegmentPositionContribution posContrib( prevResPoint.m_ertSegmentId,
lastConnectionPos,
0.0,
false,
-1,
prevResPoint.m_ertSegmentId,
true );
SegmentPositionContribution
posContrib( prevResPoint.segmentId(), lastConnectionPos, 0.0, false, -1, prevResPoint.segmentId(), true );
int ertSegmentId = resPoint.m_ertSegmentId;
int ertSegmentId = resPoint.segmentId();
std::map<int, std::vector<SegmentPositionContribution>>::iterator posContribIt;
posContribIt = segmentIdToPositionContrib.find( ertSegmentId );
@ -1973,7 +1982,7 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
std::vector<SegmentPositionContribution> posContributions = posContribIt->second;
for ( size_t i = 0; i < posContributions.size(); ++i )
{
posContributions[i].m_segmentIdAbove = prevResPoint.m_ertSegmentId;
posContributions[i].m_segmentIdAbove = prevResPoint.segmentId();
}
posContributions.push_back( posContrib );
@ -2006,7 +2015,7 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
RigWellResultPoint& resPoint = wellResultBranch.m_branchResultPoints[rpIdx];
if ( !resPoint.isCell() )
{
resPoint.m_bottomPosition = bottomPositions[resPoint.m_ertSegmentId];
resPoint.setBottomPosition( bottomPositions[resPoint.segmentId()] );
}
}
}
@ -2023,10 +2032,10 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
const well_conn_type* ert_wellhead = well_state_iget_wellhead( ert_well_state, static_cast<int>( gridNr ) );
if ( ert_wellhead )
{
RigWellResultPoint wellHeadRp = createWellResultPoint( grids[gridNr], ert_wellhead, -1, -1, wellName );
RigWellResultPoint wellHeadRp = createWellResultPoint( grids[gridNr], ert_wellhead, wellName );
// HACK: Ert returns open as "this is equally wrong as closed for well heads".
// Well heads are not open jfr mail communication with HHGS and JH Statoil 07.01.2016
wellHeadRp.m_isOpen = false;
wellHeadRp.setIsOpen( false );
if ( !subCellConnCalc.hasSubCellConnection( wellHeadRp ) ) wellResFrame.m_wellHead = wellHeadRp;
}
@ -2051,7 +2060,7 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo
for ( int connIdx = 0; connIdx < connectionCount; connIdx++ )
{
well_conn_type* ert_connection = well_conn_collection_iget( connections, connIdx );
RigWellResultPoint wellRp = createWellResultPoint( grids[gridNr], ert_connection, -1, -1, wellName );
RigWellResultPoint wellRp = createWellResultPoint( grids[gridNr], ert_connection, wellName );
if ( !subCellConnCalc.hasSubCellConnection( wellRp ) )
{

View File

@ -39,9 +39,10 @@ class QDateTime;
struct RigWellResultPoint;
typedef struct ecl_grid_struct ecl_grid_type;
typedef struct ecl_file_struct ecl_file_type;
typedef struct well_conn_struct well_conn_type;
typedef struct ecl_grid_struct ecl_grid_type;
typedef struct ecl_file_struct ecl_file_type;
typedef struct well_conn_struct well_conn_type;
typedef struct well_segment_struct well_segment_type;
//==================================================================================================
//
@ -91,11 +92,12 @@ private:
std::string ertGridName( size_t gridNr );
RigWellResultPoint createWellResultPoint( const RigGridBase* grid,
const well_conn_type* ert_connection,
int ertBranchId,
int ertSegmentId,
const char* wellName );
RigWellResultPoint createWellResultPoint( const RigGridBase* grid, const well_conn_type* ert_connection, const char* wellName );
RigWellResultPoint createWellResultPoint( const RigGridBase* grid,
const well_conn_type* ert_connection,
const well_segment_type* segment,
const char* wellName );
void importFaults( const QStringList& fileSet, cvf::Collection<RigFault>* faults );

View File

@ -22,8 +22,11 @@
#include "RiaColorTables.h"
#include "RiaExtractionTools.h"
#include "RiaPreferences.h"
#include "RigEclipseWellLogExtractor.h"
#include "RigMswCenterLineCalculator.h"
#include "RigSimulationWellCenterLineCalculator.h"
#include "RigVirtualPerforationTransmissibilities.h"
#include "RigWellLogExtractor.h"
#include "RigWellPath.h"
@ -154,9 +157,27 @@ void RivSimWellPipesPartMgr::buildWellPipeParts( const caf::DisplayCoordTransfor
m_wellBranches.clear();
m_flattenedBranchWellHeadOffsets.clear();
m_pipeBranchesCLCoords.clear();
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
m_simWellInView->calculateWellPipeStaticCenterLine( m_pipeBranchesCLCoords, pipeBranchesCellIds );
auto createSimWells = []( RimSimWellInView* simWellInView ) -> std::vector<SimulationWellCellBranch> {
std::vector<SimulationWellCellBranch> simWellBranches;
const RigSimWellData* simWellData = simWellInView->simWellData();
if ( simWellData && simWellData->isMultiSegmentWell() )
{
simWellBranches = RigMswCenterLineCalculator::calculateMswWellPipeGeometry( simWellInView );
}
else
{
simWellBranches = RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( simWellInView );
}
return simWellBranches;
};
auto simWells = createSimWells( m_simWellInView );
const auto& [coords, wellCells] = RigSimulationWellCenterLineCalculator::extractBranchData( simWells );
m_pipeBranchesCLCoords = coords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds = wellCells;
double pipeRadius = m_simWellInView->pipeRadius();
int crossSectionVertexCount = m_simWellInView->pipeCrossSectionVertexCount();
@ -294,7 +315,7 @@ void RivSimWellPipesPartMgr::buildWellPipeParts( const caf::DisplayCoordTransfor
continue;
}
if ( !virtualPerforationResult->showConnectionFactorsOnClosedConnections() && !wResCell->m_isOpen )
if ( !virtualPerforationResult->showConnectionFactorsOnClosedConnections() && !wResCell->isOpen() )
{
continue;
}
@ -417,14 +438,14 @@ void RivSimWellPipesPartMgr::updatePipeResultColor( size_t frameIndex )
if ( cellIds[wcIdx].isCell() )
{
wResCell = wResFrame->findResultCellWellHeadExcluded( cellIds[wcIdx].m_gridIndex, cellIds[wcIdx].m_gridCellIndex );
wResCell = wResFrame->findResultCellWellHeadExcluded( cellIds[wcIdx].gridIndex(), cellIds[wcIdx].cellIndex() );
}
if ( wResCell )
{
double cellState = defaultState;
if ( wResCell->m_isOpen )
if ( wResCell->isOpen() )
{
switch ( wResFrame->m_productionType )
{

View File

@ -88,13 +88,13 @@ void RivWellSpheresPartMgr::appendDynamicGeometryPartsToModel( cvf::ModelBasicLi
{
for ( const RigWellResultPoint& wellResultPoint : wellResultBranch.m_branchResultPoints )
{
size_t gridIndex = wellResultPoint.m_gridIndex;
size_t gridIndex = wellResultPoint.gridIndex();
if ( gridIndex >= mainGrid->gridCount() ) continue;
const RigGridBase* rigGrid = mainGrid->gridByIndex( gridIndex );
size_t gridCellIndex = wellResultPoint.m_gridCellIndex;
size_t gridCellIndex = wellResultPoint.cellIndex();
if ( gridCellIndex >= rigGrid->cellCount() ) continue;
const RigCell& rigCell = rigGrid->cell( gridCellIndex );
@ -207,7 +207,7 @@ cvf::Color3f RivWellSpheresPartMgr::wellCellColor( const RigWellResultFrame* wel
if ( wellColl )
{
if ( wellResultPoint.m_isOpen )
if ( wellResultPoint.isOpen() )
{
switch ( wellResultFrame->m_productionType )
{

View File

@ -21,6 +21,8 @@
#include "RigCell.h"
#include "RigMainGrid.h"
#include "RigSimWellData.h"
#include "RigSimulationWellCenterLineCalculator.h"
#include "RigWellPath.h"
#include "RigWellResultPoint.h"
#include "RimEclipseView.h"
@ -30,7 +32,6 @@
#include "RimProject.h"
#include "RimSimWellInView.h"
#include "RigWellPath.h"
#include "cafPdmUiDoubleSliderEditor.h"
CAF_PDM_SOURCE_INIT( RimSimWellFracture, "SimWellFracture" );
@ -344,14 +345,10 @@ void RimSimWellFracture::computeSimWellBranchCenterLines()
this->firstAncestorOrThisOfType( rimWell );
CVF_ASSERT( rimWell );
std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
rimWell->calculateWellPipeStaticCenterLine( pipeBranchesCLCoords, pipeBranchesCellIds );
for ( const auto& branch : pipeBranchesCLCoords )
const auto simWellBranches = RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( rimWell );
for ( const auto& [coords, wellCells] : simWellBranches )
{
RigSimulationWellCoordsAndMD wellPathWithMD( branch );
RigSimulationWellCoordsAndMD wellPathWithMD( coords );
m_branchCenterLines.push_back( wellPathWithMD );
}

View File

@ -191,11 +191,11 @@ std::map<std::string, std::vector<int>> RimFlowDiagSolution::allTracerActiveCell
{
for ( const RigWellResultPoint& wrp : wBr.m_branchResultPoints )
{
if ( wrp.isValid() && wrp.m_isOpen &&
if ( wrp.isValid() && wrp.isOpen() &&
( ( useInjectors && wrp.flowRate() < 0.0 ) || ( !useInjectors && wrp.flowRate() > 0.0 ) ) )
{
RigGridBase* grid = mainGrid->gridByIndex( wrp.m_gridIndex );
size_t reservoirCellIndex = grid->reservoirCellIndex( wrp.m_gridCellIndex );
RigGridBase* grid = mainGrid->gridByIndex( wrp.gridIndex() );
size_t reservoirCellIndex = grid->reservoirCellIndex( wrp.cellIndex() );
int cellActiveIndex = static_cast<int>( activeCellInfo->cellResultIndex( reservoirCellIndex ) );

View File

@ -454,18 +454,16 @@ RimWellAllocationOverTimeCollection RimWellAllocationOverTimePlot::createWellAll
continue;
}
std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
std::map<QString, const std::vector<double>*> tracerFractionCellValues =
RimWellAllocationTools::findOrCreateRelevantTracerCellFractions( simWellData, m_flowDiagSolution, i );
RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineFromWellFrame( m_case->eclipseCaseData(),
simWellData,
i,
branchDetection,
true,
pipeBranchesCLCoords,
pipeBranchesCellIds );
auto simWellBranches = RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineForTimeStep( m_case->eclipseCaseData(),
simWellData,
i,
branchDetection,
true );
const auto& [pipeBranchesCLCoords, pipeBranchesCellIds] = RigSimulationWellCenterLineCalculator::extractBranchData( simWellBranches );
if ( tracerFractionCellValues.size() )
{

View File

@ -246,16 +246,12 @@ void RimWellAllocationPlot::updateFromWell()
if ( !simWellData ) return;
// Set up the Accumulated Well Flow Calculator
std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineFromWellFrame( m_case->eclipseCaseData(),
simWellData,
m_timeStep,
m_branchDetection,
true,
pipeBranchesCLCoords,
pipeBranchesCellIds );
const auto simWellBranches = RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineForTimeStep( m_case->eclipseCaseData(),
simWellData,
m_timeStep,
m_branchDetection,
true );
const auto& [pipeBranchesCLCoords, pipeBranchesCellIds] = RigSimulationWellCenterLineCalculator::extractBranchData( simWellBranches );
std::map<QString, const std::vector<double>*> tracerFractionCellValues =
RimWellAllocationTools::findOrCreateRelevantTracerCellFractions( simWellData, m_flowDiagSolution, m_timeStep );

View File

@ -353,15 +353,14 @@ public:
m_pipeBranchMeasuredDepths.push_back( intersections[wpExIdx].endMD );
RigWellResultPoint resPoint;
resPoint.m_isOpen = true;
resPoint.m_gridIndex = 0; // Always main grid
resPoint.m_gridCellIndex = globCellIdx; // Shortcut, since we only have
// main grid results from RFT
resPoint.setIsOpen( true );
resPoint.setGridIndex( 0 ); // Always main grid
resPoint.setGridCellIndex( globCellIdx ); // Shortcut, since we only have
// main grid results from RFT
resPoint.m_gasRate = RiaEclipseUnitTools::convertSurfaceGasFlowRateToOilEquivalents( eclCase->eclipseCaseData()->unitsType(),
gasRates[it->second] );
resPoint.m_oilRate = oilRates[it->second];
resPoint.m_waterRate = watRates[it->second];
const double adjustedGasRate =
RiaEclipseUnitTools::convertSurfaceGasFlowRateToOilEquivalents( eclCase->eclipseCaseData()->unitsType(), gasRates[it->second] );
resPoint.setFlowData( -1.0, oilRates[it->second], adjustedGasRate, watRates[it->second] );
m_pipeBranchWellResultPoints.push_back( resPoint );
@ -415,8 +414,8 @@ public:
const std::vector<RigWellResultPoint>& branchResPoints = resFrame->m_wellResultBranches[brIdx].m_branchResultPoints;
for ( size_t wrpIdx = 0; wrpIdx < branchResPoints.size(); wrpIdx++ )
{
const RigGridBase* grid = mainGrid->gridByIndex( branchResPoints[wrpIdx].m_gridIndex );
size_t globalCellIndex = grid->reservoirCellIndex( branchResPoints[wrpIdx].m_gridCellIndex );
const RigGridBase* grid = mainGrid->gridByIndex( branchResPoints[wrpIdx].gridIndex() );
size_t globalCellIndex = grid->reservoirCellIndex( branchResPoints[wrpIdx].cellIndex() );
globCellIdxToIdxInSimWellBranch[globalCellIndex] = std::make_pair( brIdx, wrpIdx );
}

View File

@ -433,7 +433,7 @@ const RigVirtualPerforationTransmissibilities* RimEclipseCase::computeAndGetVirt
if ( r.isCell() )
{
RigCompletionData compData( wellRes->m_wellName,
RigCompletionDataGridCell( r.m_gridCellIndex, rigEclipseCase->mainGrid() ),
RigCompletionDataGridCell( r.cellIndex(), rigEclipseCase->mainGrid() ),
0 );
compData.setTransmissibility( r.connectionFactor() );

View File

@ -1685,14 +1685,14 @@ void RimEclipseView::calculateVisibleWellCellsIncFence( cvf::UByteArray* visible
const std::vector<RigWellResultPoint>& wsResCells = wellResSegments[wsIdx].m_branchResultPoints;
for ( size_t cIdx = 0; cIdx < wsResCells.size(); ++cIdx )
{
if ( wsResCells[cIdx].m_gridIndex == grid->gridIndex() )
if ( wsResCells[cIdx].gridIndex() == grid->gridIndex() )
{
if ( !wsResCells[cIdx].isCell() )
{
continue;
}
size_t gridCellIndex = wsResCells[cIdx].m_gridCellIndex;
size_t gridCellIndex = wsResCells[cIdx].cellIndex();
( *visibleCells )[gridCellIndex] = true;
// Calculate well fence cells

View File

@ -192,15 +192,6 @@ std::vector<const RigWellPath*> RimSimWellInView::wellPipeBranches() const
return std::vector<const RigWellPath*>();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSimWellInView::calculateWellPipeStaticCenterLine( std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds )
{
RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( this, pipeBranchesCLCoords, pipeBranchesCellIds );
}
//--------------------------------------------------------------------------------------------------
/// frameIndex = -1 will use the static well frame
//--------------------------------------------------------------------------------------------------
@ -340,8 +331,8 @@ bool RimSimWellInView::intersectsWellCellsFilteredCells( const RigWellResultFram
// First check the wellhead:
size_t gridIndex = wrsf->m_wellHead.m_gridIndex;
size_t gridCellIndex = wrsf->m_wellHead.m_gridCellIndex;
size_t gridIndex = wrsf->m_wellHead.gridIndex();
size_t gridCellIndex = wrsf->m_wellHead.cellIndex();
if ( gridIndex != cvf::UNDEFINED_SIZE_T && gridCellIndex != cvf::UNDEFINED_SIZE_T )
{
@ -362,8 +353,8 @@ bool RimSimWellInView::intersectsWellCellsFilteredCells( const RigWellResultFram
{
if ( wellResultPoint.isCell() )
{
gridIndex = wellResultPoint.m_gridIndex;
gridCellIndex = wellResultPoint.m_gridCellIndex;
gridIndex = wellResultPoint.gridIndex();
gridCellIndex = wellResultPoint.cellIndex();
const cvf::UByteArray* cellVisibility = rvMan->cellVisibility( visGridPart, gridIndex, frameIndex );
if ( gridCellIndex < cellVisibility->size() && ( *cellVisibility )[gridCellIndex] )
@ -770,24 +761,21 @@ void RimSimWellInView::scaleDisk( double minValue, double maxValue )
//--------------------------------------------------------------------------------------------------
cvf::BoundingBox RimSimWellInView::boundingBoxInDomainCoords() const
{
std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
auto noConst = const_cast<RimSimWellInView*>( this );
RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( noConst, pipeBranchesCLCoords, pipeBranchesCellIds );
auto noConst = const_cast<RimSimWellInView*>( this );
auto simWellBranches = RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( noConst );
cvf::BoundingBox bb;
for ( auto branch : pipeBranchesCLCoords )
for ( const auto& [coords, wellCells] : simWellBranches )
{
if ( !branch.empty() )
if ( !coords.empty() )
{
// Estimate the bounding box based on first, middle and last coordinate of branches
bb.add( branch.front() );
bb.add( coords.front() );
size_t mid = branch.size() / 2;
bb.add( branch[mid] );
size_t mid = coords.size() / 2;
bb.add( coords[mid] );
bb.add( branch.back() );
bb.add( coords.back() );
}
}

View File

@ -76,9 +76,6 @@ public:
std::vector<const RigWellPath*> wellPipeBranches() const;
void calculateWellPipeStaticCenterLine( std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds );
void wellHeadTopBottomPosition( int frameIndex, cvf::Vec3d* top, cvf::Vec3d* bottom );
double pipeRadius();
int pipeCrossSectionVertexCount();

View File

@ -409,9 +409,9 @@ void RimStreamlineInViewCollection::findStartCells( int
{
for ( const auto& point : branch.m_branchResultPoints )
{
if ( point.isValid() && point.m_isOpen )
if ( point.isValid() && point.isOpen() )
{
RigCell cell = grids[point.m_gridIndex]->cell( point.m_gridCellIndex );
RigCell cell = grids[point.gridIndex()]->cell( point.cellIndex() );
if ( frame->m_productionType == RiaDefines::WellProductionType::PRODUCER )
{
outProducerCells.push_back( std::pair<QString, RigCell>( swdata->m_wellName, cell ) );

View File

@ -96,6 +96,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RigSurfaceStatisticsCalculator.h
${CMAKE_CURRENT_LIST_DIR}/RigWellLogIndexDepthOffset.h
${CMAKE_CURRENT_LIST_DIR}/RigPressureDepthData.h
${CMAKE_CURRENT_LIST_DIR}/RigMswCenterLineCalculator.h
)
set(SOURCE_GROUP_SOURCE_FILES
@ -189,6 +190,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RigSurfaceStatisticsCalculator.cpp
${CMAKE_CURRENT_LIST_DIR}/RigWellLogIndexDepthOffset.cpp
${CMAKE_CURRENT_LIST_DIR}/RigPressureDepthData.cpp
${CMAKE_CURRENT_LIST_DIR}/RigMswCenterLineCalculator.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})

View File

@ -711,9 +711,9 @@ std::vector<double> RigAccWellFlowCalculator::calculateWellCellFlowPrTracer( con
if ( m_tracerCellFractionValues )
{
if ( wellCell.isCell() && wellCell.m_isOpen )
if ( wellCell.isCell() && wellCell.isOpen() )
{
size_t resCellIndex = m_cellIndexCalculator.resultCellIndex( wellCell.m_gridIndex, wellCell.m_gridCellIndex );
size_t resCellIndex = m_cellIndexCalculator.resultCellIndex( wellCell.gridIndex(), wellCell.cellIndex() );
size_t tracerIdx = 0;
double totalTracerFractionInCell = 0.0;
for ( const auto& tracerFractionValsPair : ( *m_tracerCellFractionValues ) )
@ -768,23 +768,23 @@ std::vector<size_t> RigAccWellFlowCalculator::wrpToUniqueWrpIndexFromBottom( con
if ( clSegIdx < 0 ) return resPointToConnectionIndexFromBottom;
size_t prevGridIdx = branchCells[clSegIdx].m_gridIndex;
size_t prevGridCellIdx = branchCells[clSegIdx].m_gridCellIndex;
int prevErtSegId = branchCells[clSegIdx].m_ertSegmentId;
int prevErtBranchId = branchCells[clSegIdx].m_ertBranchId;
size_t prevGridIdx = branchCells[clSegIdx].gridIndex();
size_t prevGridCellIdx = branchCells[clSegIdx].cellIndex();
int prevErtSegId = branchCells[clSegIdx].segmentId();
int prevErtBranchId = branchCells[clSegIdx].branchId();
while ( clSegIdx >= 0 )
{
if ( branchCells[clSegIdx].isValid() &&
( branchCells[clSegIdx].m_gridIndex != prevGridIdx || branchCells[clSegIdx].m_gridCellIndex != prevGridCellIdx ||
branchCells[clSegIdx].m_ertSegmentId != prevErtSegId || branchCells[clSegIdx].m_ertBranchId != prevErtBranchId ) )
( branchCells[clSegIdx].gridIndex() != prevGridIdx || branchCells[clSegIdx].cellIndex() != prevGridCellIdx ||
branchCells[clSegIdx].segmentId() != prevErtSegId || branchCells[clSegIdx].branchId() != prevErtBranchId ) )
{
++connIdxFromBottom;
prevGridIdx = branchCells[clSegIdx].m_gridIndex;
prevGridCellIdx = branchCells[clSegIdx].m_gridCellIndex;
prevErtSegId = branchCells[clSegIdx].m_ertSegmentId;
prevErtBranchId = branchCells[clSegIdx].m_ertBranchId;
prevGridIdx = branchCells[clSegIdx].gridIndex();
prevGridCellIdx = branchCells[clSegIdx].cellIndex();
prevErtSegId = branchCells[clSegIdx].segmentId();
prevErtBranchId = branchCells[clSegIdx].branchId();
}
resPointToConnectionIndexFromBottom[clSegIdx] = connIdxFromBottom;
@ -812,10 +812,10 @@ std::vector<size_t> RigAccWellFlowCalculator::findDownStreamBranchIdxs( const Ri
for ( size_t bIdx = 0; bIdx < m_pipeBranchesWellResultPoints.size(); ++bIdx )
{
if ( m_pipeBranchesWellResultPoints[bIdx][0].m_gridIndex == connectionPoint.m_gridIndex &&
m_pipeBranchesWellResultPoints[bIdx][0].m_gridCellIndex == connectionPoint.m_gridCellIndex &&
m_pipeBranchesWellResultPoints[bIdx][0].m_ertBranchId == connectionPoint.m_ertBranchId &&
m_pipeBranchesWellResultPoints[bIdx][0].m_ertSegmentId == connectionPoint.m_ertSegmentId )
if ( m_pipeBranchesWellResultPoints[bIdx][0].gridIndex() == connectionPoint.gridIndex() &&
m_pipeBranchesWellResultPoints[bIdx][0].cellIndex() == connectionPoint.cellIndex() &&
m_pipeBranchesWellResultPoints[bIdx][0].branchId() == connectionPoint.branchId() &&
m_pipeBranchesWellResultPoints[bIdx][0].segmentId() == connectionPoint.segmentId() )
{
downStreamBranchIdxs.push_back( bIdx );
}

View File

@ -248,8 +248,8 @@ void RigEclipseCaseData::computeWellCellsPrGrid()
size_t cdIdx;
for ( cdIdx = 0; cdIdx < wellSegment.m_branchResultPoints.size(); ++cdIdx )
{
size_t gridIndex = wellSegment.m_branchResultPoints[cdIdx].m_gridIndex;
size_t gridCellIndex = wellSegment.m_branchResultPoints[cdIdx].m_gridCellIndex;
size_t gridIndex = wellSegment.m_branchResultPoints[cdIdx].gridIndex();
size_t gridCellIndex = wellSegment.m_branchResultPoints[cdIdx].cellIndex();
if ( gridIndex < m_wellCellsInGrid.size() && gridCellIndex < m_wellCellsInGrid[gridIndex]->size() )
{
@ -340,8 +340,8 @@ const RigCell& RigEclipseCaseData::cellFromWellResultCell( const RigWellResultPo
{
CVF_ASSERT( wellResultCell.isCell() );
size_t gridIndex = wellResultCell.m_gridIndex;
size_t gridCellIndex = wellResultCell.m_gridCellIndex;
size_t gridIndex = wellResultCell.gridIndex();
size_t gridCellIndex = wellResultCell.cellIndex();
std::vector<const RigGridBase*> grids;
allGrids( &grids );
@ -356,11 +356,11 @@ bool RigEclipseCaseData::findSharedSourceFace( cvf::StructGridInterface::FaceTyp
const RigWellResultPoint& sourceWellCellResult,
const RigWellResultPoint& otherWellCellResult ) const
{
size_t gridIndex = sourceWellCellResult.m_gridIndex;
size_t gridCellIndex = sourceWellCellResult.m_gridCellIndex;
size_t gridIndex = sourceWellCellResult.gridIndex();
size_t gridCellIndex = sourceWellCellResult.cellIndex();
size_t otherGridIndex = otherWellCellResult.m_gridIndex;
size_t otherGridCellIndex = otherWellCellResult.m_gridCellIndex;
size_t otherGridIndex = otherWellCellResult.gridIndex();
size_t otherGridCellIndex = otherWellCellResult.cellIndex();
if ( gridIndex != otherGridIndex ) return false;
@ -504,22 +504,17 @@ std::vector<const RigWellPath*>
if ( m_simWellBranchCache.find( simWellSeachItem ) == m_simWellBranchCache.end() )
{
std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineFromWellFrame( this,
simWellData,
-1,
useAutoDetectionOfBranches,
includeAllCellCenters,
pipeBranchesCLCoords,
pipeBranchesCellIds );
const auto simWellBranches = RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineForTimeStep( this,
simWellData,
-1,
useAutoDetectionOfBranches,
includeAllCellCenters );
m_simWellBranchCache.insert( std::make_pair( simWellSeachItem, cvf::Collection<RigWellPath>() ) );
for ( size_t brIdx = 0; brIdx < pipeBranchesCLCoords.size(); ++brIdx )
for ( const auto& [coords, wellCells] : simWellBranches )
{
auto wellMdCalculator = RigSimulationWellCoordsAndMD( pipeBranchesCLCoords[brIdx] );
auto wellMdCalculator = RigSimulationWellCoordsAndMD( coords );
cvf::ref<RigWellPath> newWellPath = new RigWellPath( wellMdCalculator.wellPathPoints(), wellMdCalculator.measuredDepths() );

View File

@ -0,0 +1,342 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RigMswCenterLineCalculator.h"
#include "RiaLogging.h"
#include "RigCell.h"
#include "RigCellFaceGeometryTools.h"
#include "RigEclipseCaseData.h"
#include "RigMainGrid.h"
#include "RigSimWellData.h"
#include "RimEclipseCase.h"
#include "RimEclipseView.h"
#include "RimSimWellInView.h"
#include "RimSimWellInViewCollection.h"
#include "cvfRay.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<SimulationWellCellBranch> RigMswCenterLineCalculator::calculateMswWellPipeGeometry( RimSimWellInView* rimWell )
{
CVF_ASSERT( rimWell );
const RigSimWellData* simWellData = rimWell->simWellData();
if ( !simWellData ) return {};
RimEclipseView* eclipseView;
rimWell->firstAncestorOrThisOfType( eclipseView );
CVF_ASSERT( eclipseView );
if ( eclipseView->eclipseCase() && eclipseView->eclipseCase()->eclipseCaseData() )
{
auto eclipseCaseData = eclipseView->eclipseCase()->eclipseCaseData();
int timeStepIndex = eclipseView->currentTimeStep();
return calculateMswWellPipeGeometryForTimeStep( eclipseCaseData, simWellData, timeStepIndex );
}
return {};
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<SimulationWellCellBranch>
RigMswCenterLineCalculator::calculateMswWellPipeGeometryForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* wellResults,
int timeStepIndex )
{
if ( timeStepIndex >= 0 && !wellResults->hasAnyValidCells( timeStepIndex ) ) return {};
const RigWellResultFrame* wellFramePtr = nullptr;
if ( timeStepIndex < 0 )
{
wellFramePtr = wellResults->staticWellCells();
}
else
{
wellFramePtr = wellResults->wellResultFrame( timeStepIndex );
}
const RigWellResultFrame& wellFrame = *wellFramePtr;
const std::vector<RigWellResultBranch>& resultBranches = wellFrame.m_wellResultBranches;
std::vector<WellBranch> wellBranches = mergeShortBranchesIntoLongBranches( resultBranches );
// Connect outlet segment of branches to parent branch
for ( const auto& resultBranch : resultBranches )
{
if ( resultBranch.m_branchResultPoints.empty() ) continue;
const auto firstResultPoint = resultBranch.m_branchResultPoints.front();
for ( auto& wellBranch : wellBranches )
{
if ( wellBranch.m_branchId == resultBranch.m_ertBranchId )
{
if ( firstResultPoint.branchId() == resultBranch.m_ertBranchId )
{
// The first result point is on the same branch, use well head as outlet
RigWellResultPoint outletResultPoint = wellFrame.m_wellHead;
auto gridAndCellIndex = std::make_pair( outletResultPoint.gridIndex(), outletResultPoint.cellIndex() );
wellBranch.m_segmentsWithGridCells[outletResultPoint.segmentId()].push_back( gridAndCellIndex );
}
else
{
// The first result point on a different branch. Find the branch and add the grid cell
for ( const auto& candidateResultBranch : wellBranches )
{
if ( firstResultPoint.branchId() == candidateResultBranch.m_branchId )
{
std::pair<size_t, size_t> gridAndCellIndexForTieIn;
for ( const auto& [segment, gridAndCellIndices] : candidateResultBranch.m_segmentsWithGridCells )
{
if ( segment > firstResultPoint.segmentId() ) continue;
if ( !gridAndCellIndices.empty() )
{
gridAndCellIndexForTieIn = gridAndCellIndices.front();
}
}
wellBranch.m_segmentsWithGridCells[firstResultPoint.segmentId()].push_back( gridAndCellIndexForTieIn );
}
}
}
}
}
}
std::vector<SimulationWellCellBranch> simWellBranches;
for ( const auto& wellBranch : wellBranches )
{
std::vector<cvf::Vec3d> cellCenterCoords;
std::vector<RigWellResultPoint> cellCenterResultPoints;
if ( wellBranch.m_branchId == 1 && !wellBranch.m_segmentsWithGridCells.empty() )
{
const auto& [firstSegment, gridAndCellIndices] = *wellBranch.m_segmentsWithGridCells.begin();
if ( !gridAndCellIndices.empty() )
{
const auto& [gridIndex, cellIndex] = gridAndCellIndices.front();
if ( gridIndex < eclipseCaseData->gridCount() && cellIndex < eclipseCaseData->grid( gridIndex )->cellCount() )
{
const RigCell& cell = eclipseCaseData->grid( gridIndex )->cell( cellIndex );
cvf::Vec3d whStartPos = cell.faceCenter( cvf::StructGridInterface::NEG_K );
// Add extra coordinate between cell face and cell center
// to make sure the well pipe terminated in a segment parallel to z-axis
cvf::Vec3d whIntermediate = whStartPos;
whIntermediate.z() = ( whStartPos.z() + cell.center().z() ) / 2.0;
RigWellResultPoint resPoint;
for ( const auto& resBranch : resultBranches )
{
for ( const auto& respoint : resBranch.m_branchResultPoints )
{
if ( respoint.segmentId() == firstSegment )
{
resPoint = respoint;
break;
}
}
}
cellCenterCoords.push_back( whStartPos );
cellCenterResultPoints.push_back( resPoint );
cellCenterCoords.push_back( whIntermediate );
cellCenterResultPoints.push_back( resPoint );
}
}
}
for ( const auto& [segmentId, gridAndCellIndices] : wellBranch.m_segmentsWithGridCells )
{
for ( const auto& [gridIndex, cellIndex] : gridAndCellIndices )
{
if ( gridIndex < eclipseCaseData->gridCount() && cellIndex < eclipseCaseData->grid( gridIndex )->cellCount() )
{
const RigCell& cell = eclipseCaseData->grid( gridIndex )->cell( cellIndex );
cvf::Vec3d pos = cell.center();
RigWellResultPoint resPoint;
// The result point is only used to transport the grid index and cell index
// The current implementation will propagate the cell open state to the well segment from one cell to
// the next.
resPoint.setGridIndex( gridIndex );
resPoint.setGridCellIndex( cellIndex );
cellCenterCoords.push_back( pos );
cellCenterResultPoints.push_back( resPoint );
}
}
}
const auto simWellBranch = addCoordsAtCellFaceIntersectionsAndCreateBranch( cellCenterCoords, cellCenterResultPoints, eclipseCaseData );
simWellBranches.emplace_back( simWellBranch );
}
return simWellBranches;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
SimulationWellCellBranch
RigMswCenterLineCalculator::addCoordsAtCellFaceIntersectionsAndCreateBranch( const std::vector<cvf::Vec3d> branchCoords,
const std::vector<RigWellResultPoint>& resultPoints,
const RigEclipseCaseData* eclipseCaseData )
{
std::vector<cvf::Vec3d> adjustedCoords;
std::vector<RigWellResultPoint> adjustedResPoints;
RigWellResultPoint previusPoint;
for ( size_t resPointIdx = 0; resPointIdx < resultPoints.size(); resPointIdx++ )
{
if ( resPointIdx >= branchCoords.size() ) continue;
const auto& currentPoint = resultPoints[resPointIdx];
const auto& currentCellCenter = branchCoords[resPointIdx];
if ( previusPoint.isCell() )
{
const RigCell& prevCell = eclipseCaseData->cellFromWellResultCell( previusPoint );
const cvf::Vec3d previousCellCenter = prevCell.center();
{
// Insert extra coordinate at the location where the well path is leaving the previous cell
cvf::Ray rayToThisCell;
rayToThisCell.setOrigin( previousCellCenter );
rayToThisCell.setDirection( ( currentCellCenter - previousCellCenter ).getNormalized() );
cvf::Vec3d outOfPrevCell( previousCellCenter );
prevCell.firstIntersectionPoint( rayToThisCell, &outOfPrevCell );
if ( ( currentCellCenter - outOfPrevCell ).lengthSquared() > 1e-3 )
{
adjustedCoords.push_back( outOfPrevCell );
adjustedResPoints.push_back( RigWellResultPoint() );
}
}
if ( currentPoint.isCell() )
{
// Insert extra coordinate at the location where the well path is entering the current cell
const RigCell& currentCell = eclipseCaseData->cellFromWellResultCell( currentPoint );
cvf::Ray rayFromThisCell;
rayFromThisCell.setOrigin( currentCellCenter );
rayFromThisCell.setDirection( ( previousCellCenter - currentCellCenter ).getNormalized() );
cvf::Vec3d outOfCurrentCell( currentCellCenter );
currentCell.firstIntersectionPoint( rayFromThisCell, &outOfCurrentCell );
if ( ( currentCellCenter - outOfCurrentCell ).lengthSquared() > 1e-3 )
{
adjustedCoords.push_back( outOfCurrentCell );
adjustedResPoints.push_back( currentPoint );
}
}
}
adjustedResPoints.push_back( currentPoint );
adjustedCoords.push_back( currentCellCenter );
previusPoint = currentPoint;
}
// Duplicate last coord to make sure we have N+1 coordinates for N result points
adjustedCoords.push_back( adjustedCoords.back() );
return { adjustedCoords, adjustedResPoints };
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RigMswCenterLineCalculator::WellBranch>
RigMswCenterLineCalculator::mergeShortBranchesIntoLongBranches( const std::vector<RigWellResultBranch>& resBranches )
{
std::vector<WellBranch> longWellBranches;
std::vector<WellBranch> shortWellBranches;
for ( const auto& resultBranch : resBranches )
{
WellBranch branch;
branch.m_branchId = resultBranch.m_ertBranchId;
for ( const auto& resPoint : resultBranch.m_branchResultPoints )
{
size_t gridIndex = resPoint.gridIndex();
size_t gridCellIndex = resPoint.cellIndex();
auto gridAndCellIndex = std::make_pair( gridIndex, gridCellIndex );
if ( gridIndex != cvf::UNDEFINED_SIZE_T && gridCellIndex != cvf::UNDEFINED_SIZE_T && !branch.containsGridCell( gridAndCellIndex ) )
{
OutputSegment outputSegment{ resPoint.outletSegmentId(), resPoint.outletBranchId() };
branch.m_gridCellsConnectedToSegments[gridAndCellIndex] = outputSegment;
branch.m_segmentsWithGridCells[resPoint.segmentId()].push_back( gridAndCellIndex );
}
}
const int resultPointThreshold = 3;
if ( resultBranch.m_branchResultPoints.size() > resultPointThreshold )
{
longWellBranches.push_back( branch );
}
else
{
shortWellBranches.push_back( branch );
}
}
// Move all grid cells of small branch to the long branch
for ( const auto& branch : shortWellBranches )
{
if ( branch.m_gridCellsConnectedToSegments.empty() ) continue;
const auto& outputSegment = branch.m_gridCellsConnectedToSegments.begin()->second;
for ( auto& longBranch : longWellBranches )
{
if ( longBranch.m_branchId == outputSegment.outputSegmentBranchId )
{
for ( const auto& [gridAndCellIndex, localOutputSegment] : branch.m_gridCellsConnectedToSegments )
{
longBranch.m_segmentsWithGridCells[outputSegment.outputSegmentId].push_back( gridAndCellIndex );
}
}
}
}
return longWellBranches;
}

View File

@ -0,0 +1,78 @@
/////////////////////////////////////////////////////////////////////////////////
//
// 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 "RigWellResultPoint.h"
#include "cvfVector3.h"
#include <map>
#include <vector>
class RigEclipseCaseData;
class RimSimWellInView;
class RigSimWellData;
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
class RigMswCenterLineCalculator
{
public:
static std::vector<SimulationWellCellBranch> calculateMswWellPipeGeometry( RimSimWellInView* rimWell );
private:
struct OutputSegment
{
int outputSegmentId = -1;
int outputSegmentBranchId = -1;
};
struct WellBranch
{
int m_branchId = -1;
std::map<std::pair<size_t, size_t>, OutputSegment> m_gridCellsConnectedToSegments;
std::map<int, std::vector<std::pair<size_t, size_t>>> m_segmentsWithGridCells;
bool containsGridCell( const std::pair<size_t, size_t>& candidateGridAndCellIndex ) const
{
for ( const auto& [segmentId, gridAndCellIndex] : m_segmentsWithGridCells )
{
if ( std::find( gridAndCellIndex.begin(), gridAndCellIndex.end(), candidateGridAndCellIndex ) != gridAndCellIndex.end() )
{
return true;
}
}
return false;
};
};
private:
static std::vector<SimulationWellCellBranch> calculateMswWellPipeGeometryForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* simWellData,
int timeStepIndex );
static SimulationWellCellBranch addCoordsAtCellFaceIntersectionsAndCreateBranch( const std::vector<cvf::Vec3d> branchCoords,
const std::vector<RigWellResultPoint>& resultPoints,
const RigEclipseCaseData* eclipseCaseData );
static std::vector<WellBranch> mergeShortBranchesIntoLongBranches( const std::vector<RigWellResultBranch>& resBranches );
};

View File

@ -396,8 +396,8 @@ void RigReservoirBuilderMock::addWellData( RigEclipseCaseData* eclipseCase, RigG
wellCells.m_productionType = RiaDefines::WellProductionType::PRODUCER;
wellCells.m_isOpen = true;
wellCells.m_wellHead.m_gridIndex = 0;
wellCells.m_wellHead.m_gridCellIndex = grid->cellIndexFromIJK( 1, 0, 0 );
wellCells.m_wellHead.setGridIndex( 0 );
wellCells.m_wellHead.setGridCellIndex( grid->cellIndexFromIJK( 1, 0, 0 ) );
// Connections
// int connectionCount = std::min(dim.x(), std::min(dim.y(), dim.z())) - 2;
@ -414,53 +414,53 @@ void RigReservoirBuilderMock::addWellData( RigEclipseCaseData* eclipseCase, RigG
if ( connIdx == ( size_t )( connectionCount / 4 ) ) continue;
RigWellResultPoint data;
data.m_gridIndex = 0;
data.setGridIndex( 0 );
if ( connIdx < dim.y() - 2 )
data.m_gridCellIndex = grid->cellIndexFromIJK( 1, 1 + connIdx, 1 + connIdx );
data.setGridCellIndex( grid->cellIndexFromIJK( 1, 1 + connIdx, 1 + connIdx ) );
else
data.m_gridCellIndex = grid->cellIndexFromIJK( 1, dim.y() - 2, 1 + connIdx );
data.setGridCellIndex( grid->cellIndexFromIJK( 1, dim.y() - 2, 1 + connIdx ) );
if ( connIdx < connectionCount / 2 )
{
data.m_isOpen = true;
data.setIsOpen( true );
}
else
{
data.m_isOpen = false;
data.setIsOpen( false );
}
if ( wellSegment.m_branchResultPoints.size() == 0 ||
wellSegment.m_branchResultPoints.back().m_gridCellIndex != data.m_gridCellIndex )
wellSegment.m_branchResultPoints.back().cellIndex() != data.cellIndex() )
{
wellSegment.m_branchResultPoints.push_back( data );
if ( connIdx == connectionCount / 2 )
{
RigWellResultPoint deadEndData = data;
deadEndData.m_gridCellIndex = data.m_gridCellIndex + 1;
deadEndData.m_isOpen = true;
deadEndData.setGridCellIndex( data.cellIndex() + 1 );
deadEndData.setIsOpen( true );
RigWellResultPoint deadEndData1 = data;
deadEndData1.m_gridCellIndex = data.m_gridCellIndex + 2;
deadEndData1.m_isOpen = false;
deadEndData1.setGridCellIndex( data.cellIndex() + 2 );
deadEndData1.setIsOpen( false );
wellSegment.m_branchResultPoints.push_back( deadEndData );
wellSegment.m_branchResultPoints.push_back( deadEndData1 );
wellSegment.m_branchResultPoints.push_back( deadEndData );
data.m_isOpen = true;
data.setIsOpen( true );
wellSegment.m_branchResultPoints.push_back( data );
}
}
if ( connIdx < dim.y() - 2 )
{
data.m_gridCellIndex = grid->cellIndexFromIJK( 1, 1 + connIdx, 2 + connIdx );
data.setGridCellIndex( grid->cellIndexFromIJK( 1, 1 + connIdx, 2 + connIdx ) );
if ( wellSegment.m_branchResultPoints.size() == 0 ||
wellSegment.m_branchResultPoints.back().m_gridCellIndex != data.m_gridCellIndex )
wellSegment.m_branchResultPoints.back().cellIndex() != data.cellIndex() )
{
wellSegment.m_branchResultPoints.push_back( data );
}

View File

@ -138,11 +138,11 @@ bool RigSimWellData::hasAnyValidCells( size_t resultTimeStepIndex ) const
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool operator==( const RigWellResultPoint& p1, const RigWellResultPoint& p2 )
{
return p1.m_gridIndex == p2.m_gridIndex && p1.m_gridCellIndex == p2.m_gridCellIndex && p1.m_ertBranchId == p2.m_ertBranchId &&
p1.m_ertSegmentId == p2.m_ertSegmentId;
// TODO : Remove when <=> operator has been added to RigWellResultPoint
return p1.gridIndex() == p2.gridIndex() && p1.cellIndex() == p2.cellIndex() && p1.branchId() == p2.branchId() &&
p1.segmentId() == p2.segmentId();
}
//--------------------------------------------------------------------------------------------------
@ -369,7 +369,7 @@ const RigWellResultPoint* RigWellResultFrame::findResultCellWellHeadIncluded( si
// This behavior was different prior to release 2019.04 and was rendered as a closed connection (gray)
// https://github.com/OPM/ResInsight/issues/712
if ( m_wellHead.m_gridCellIndex == gridCellIndex && m_wellHead.m_gridIndex == gridIndex )
if ( m_wellHead.cellIndex() == gridCellIndex && m_wellHead.gridIndex() == gridIndex )
{
return &m_wellHead;
}
@ -388,8 +388,8 @@ const RigWellResultPoint* RigWellResultFrame::findResultCellWellHeadExcluded( si
{
for ( size_t wc = 0; wc < m_wellResultBranches[wb].m_branchResultPoints.size(); ++wc )
{
if ( m_wellResultBranches[wb].m_branchResultPoints[wc].m_gridCellIndex == gridCellIndex &&
m_wellResultBranches[wb].m_branchResultPoints[wc].m_gridIndex == gridIndex )
if ( m_wellResultBranches[wb].m_branchResultPoints[wc].cellIndex() == gridCellIndex &&
m_wellResultBranches[wb].m_branchResultPoints[wc].gridIndex() == gridIndex )
{
return &( m_wellResultBranches[wb].m_branchResultPoints[wc] );
}

View File

@ -19,6 +19,8 @@
#include "RigSimulationWellCenterLineCalculator.h"
#include "RiaLogging.h"
#include "RigCell.h"
#include "RigCellFaceGeometryTools.h"
#include "RigEclipseCaseData.h"
@ -38,6 +40,79 @@
#include <deque>
#include <list>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<SimulationWellCellBranch> RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( RimSimWellInView* rimWell )
{
std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
calculateWellPipeStaticCenterline( rimWell, pipeBranchesCLCoords, pipeBranchesCellIds );
std::vector<SimulationWellCellBranch> simuationBranches;
for ( size_t i = 0; i < pipeBranchesCLCoords.size(); i++ )
{
if ( i < pipeBranchesCellIds.size() )
{
simuationBranches.emplace_back( std::make_pair( pipeBranchesCLCoords[i], pipeBranchesCellIds[i] ) );
}
}
return simuationBranches;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<SimulationWellCellBranch>
RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* simWellData,
int timeStepIndex,
bool isAutoDetectBranches,
bool useAllCellCenters )
{
std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
calculateWellPipeCenterlineForTimeStep( eclipseCaseData,
simWellData,
timeStepIndex,
isAutoDetectBranches,
useAllCellCenters,
pipeBranchesCLCoords,
pipeBranchesCellIds );
std::vector<SimulationWellCellBranch> simuationBranches;
for ( size_t i = 0; i < pipeBranchesCLCoords.size(); i++ )
{
if ( i < pipeBranchesCellIds.size() )
{
simuationBranches.emplace_back( std::make_pair( pipeBranchesCLCoords[i], pipeBranchesCellIds[i] ) );
}
}
return simuationBranches;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::pair<std::vector<std::vector<cvf::Vec3d>>, std::vector<std::vector<RigWellResultPoint>>>
RigSimulationWellCenterLineCalculator::extractBranchData( const std::vector<SimulationWellCellBranch> simulationBranch )
{
std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
for ( const auto& [coords, wellCells] : simulationBranch )
{
pipeBranchesCLCoords.emplace_back( coords );
pipeBranchesCellIds.emplace_back( wellCells );
}
return { pipeBranchesCLCoords, pipeBranchesCellIds };
}
//--------------------------------------------------------------------------------------------------
/// Based on the points and cells, calculate a pipe centerline
/// The returned CellIds is one less than the number of centerline points,
@ -63,13 +138,56 @@ void RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( R
bool useAllCellCenters = rimWell->isUsingCellCenterForPipe();
int timeStepIndex = -1;
calculateWellPipeCenterlineFromWellFrame( eclipseCaseData,
simWellData,
timeStepIndex,
isAutoDetectBranches,
useAllCellCenters,
pipeBranchesCLCoords,
pipeBranchesCellIds );
calculateWellPipeCenterlineForTimeStep( eclipseCaseData,
simWellData,
timeStepIndex,
isAutoDetectBranches,
useAllCellCenters,
pipeBranchesCLCoords,
pipeBranchesCellIds );
// DEBUG output, please keep code
bool printDebug = false;
if ( printDebug )
{
QString txt;
for ( size_t idx = 0; idx < pipeBranchesCellIds.size(); idx++ )
{
const auto& branchCells = pipeBranchesCellIds[idx];
for ( const auto& resultPoint : branchCells )
{
QString myTxt;
int fieldWidth = 3;
myTxt += QString( "Ri branch index: %1 " ).arg( idx, fieldWidth );
myTxt += QString( "Seg: %1 Branch: %2 " ).arg( resultPoint.segmentId(), fieldWidth ).arg( resultPoint.branchId(), fieldWidth );
if ( resultPoint.isCell() )
{
size_t i = 0, j = 0, k = 0;
auto grid = eclipseCaseData->grid( resultPoint.gridIndex() );
grid->ijkFromCellIndex( resultPoint.cellIndex(), &i, &j, &k );
myTxt += QString( "Grid %1 %2 %3 " ).arg( i + 1, fieldWidth ).arg( j + 1, fieldWidth ).arg( k + 1, fieldWidth );
}
myTxt += QString( "OutSeg: %1 OutBranch: %2 " )
.arg( resultPoint.outletSegmentId(), fieldWidth )
.arg( resultPoint.outletBranchId(), fieldWidth );
int coordFieldWidth = 12;
myTxt += QString( "Bottom pos: %1 %2 %3 " )
.arg( resultPoint.bottomPosition().x(), coordFieldWidth )
.arg( resultPoint.bottomPosition().y(), coordFieldWidth )
.arg( resultPoint.bottomPosition().z(), coordFieldWidth );
myTxt += "\n";
txt += myTxt;
}
}
RiaLogging::debug( txt );
}
}
//--------------------------------------------------------------------------------------------------
@ -77,14 +195,13 @@ void RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( R
/// The returned CellIds is one less than the number of centerline points,
/// and are describing the lines between the points, starting with the first line
//--------------------------------------------------------------------------------------------------
void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineFromWellFrame(
const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* wellResults,
int timeStepIndex,
bool isAutoDetectBranches,
bool useAllCellCenters,
std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds )
void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* wellResults,
int timeStepIndex,
bool isAutoDetectBranches,
bool useAllCellCenters,
std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds )
{
// Initialize the return arrays
pipeBranchesCLCoords.clear();
@ -200,7 +317,7 @@ void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineFromWellF
// Use the interpolated value of branch head
CVF_ASSERT( currentWellResPoint.isPointValid() );
cvf::Vec3d currentPoint = currentWellResPoint.m_bottomPosition;
cvf::Vec3d currentPoint = currentWellResPoint.bottomPosition();
// If we have a real previous cell, we need to go out of it, before adding the current point
// That is: add a CL-point describing where it leaves the previous cell.
@ -273,7 +390,7 @@ void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineFromWellF
}
else
{
centerPreviousCell = prevWellResPoint->m_bottomPosition;
centerPreviousCell = prevWellResPoint->bottomPosition();
}
distanceToWellHeadIsLonger = ( centerThisCell - centerPreviousCell ).lengthSquared() <=
@ -378,7 +495,7 @@ void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineFromWellF
else if ( prevWellResPoint && prevWellResPoint->isPointValid() )
{
// Continue the line with the same point, just to keep the last Cell ID
pipeBranchesCLCoords.back().push_back( prevWellResPoint->m_bottomPosition );
pipeBranchesCLCoords.back().push_back( prevWellResPoint->bottomPosition() );
}
else
{
@ -660,7 +777,7 @@ private:
const RigCell& whCell = m_eclipseCaseData->cellFromWellResultCell( m_orgWellResultFrame.wellHeadOrStartCell() );
cvf::Vec3d whStartPos = whCell.faceCenter( cvf::StructGridInterface::NEG_K );
wellHeadAsPoint.m_bottomPosition = whStartPos;
wellHeadAsPoint.setBottomPosition( whStartPos );
m_branchedWell.m_wellResultBranches[branchIdx].m_branchResultPoints.push_back( wellHeadAsPoint );
}
@ -694,7 +811,7 @@ private:
}
}
branchStartAsResultPoint.m_bottomPosition = branchStartPos;
branchStartAsResultPoint.setBottomPosition( branchStartPos );
m_branchedWell.m_wellResultBranches[branchIdx].m_branchResultPoints.push_back( branchStartAsResultPoint );
}
else

View File

@ -19,8 +19,11 @@
#pragma once
#include "RigWellResultPoint.h"
#include "cvfVector3.h"
#include <map>
#include <vector>
class RigEclipseCaseData;
@ -36,19 +39,38 @@ class RigWellResultFrame;
class RigSimulationWellCenterLineCalculator
{
public:
static std::vector<SimulationWellCellBranch> calculateWellPipeStaticCenterline( RimSimWellInView* rimWell );
static std::vector<SimulationWellCellBranch> calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* simWellData,
int timeStepIndex,
bool isAutoDetectBranches,
bool useAllCellCenters );
static std::pair<std::vector<std::vector<cvf::Vec3d>>, std::vector<std::vector<RigWellResultPoint>>>
extractBranchData( const std::vector<SimulationWellCellBranch> simulationBranch );
private:
static void calculateWellPipeStaticCenterline( RimSimWellInView* rimWell,
std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds );
static void calculateWellPipeCenterlineFromWellFrame( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* simWellData,
int timeStepIndex,
bool isAutoDetectBranches,
bool useAllCellCenters,
std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds );
static void calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* simWellData,
int timeStepIndex,
bool isAutoDetectBranches,
bool useAllCellCenters,
std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds );
static std::vector<SimulationWellCellBranch> calculateMswWellPipeGeometryForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* simWellData,
int timeStepIndex );
static SimulationWellCellBranch addSegmentsToCellFaces( const std::vector<cvf::Vec3d> branchCoords,
const std::vector<RigWellResultPoint>& resultPoints,
const RigEclipseCaseData* eclipseCaseData );
private:
static bool hasAnyValidDataCells( const RigWellResultBranch& branch );
static void finishPipeCenterLine( std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords, const cvf::Vec3d& lastCellCenter );

View File

@ -23,10 +23,12 @@
//--------------------------------------------------------------------------------------------------
RigWellResultPoint::RigWellResultPoint()
: m_gridIndex( cvf::UNDEFINED_SIZE_T )
, m_gridCellIndex( cvf::UNDEFINED_SIZE_T )
, m_cellIndex( cvf::UNDEFINED_SIZE_T )
, m_isOpen( false )
, m_ertBranchId( -1 )
, m_ertSegmentId( -1 )
, m_ertOutletBranchId( -1 )
, m_ertOutletSegmentId( -1 )
, m_bottomPosition( cvf::Vec3d::UNDEFINED )
, m_flowRate( 0.0 )
, m_oilRate( 0.0 )
@ -36,6 +38,75 @@ RigWellResultPoint::RigWellResultPoint()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigWellResultPoint::setGridIndex( size_t gridIndex )
{
m_gridIndex = gridIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigWellResultPoint::setGridCellIndex( size_t cellIndex )
{
m_cellIndex = cellIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigWellResultPoint::setIsOpen( bool isOpen )
{
m_isOpen = isOpen;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigWellResultPoint::setFlowData( double flowRate, double oilRate, double gasRate, double waterRate )
{
m_flowRate = flowRate;
m_oilRate = oilRate;
m_gasRate = gasRate;
m_waterRate = waterRate;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigWellResultPoint::setConnectionFactor( double connectionFactor )
{
m_connectionFactor = connectionFactor;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigWellResultPoint::setSegmentData( int branchId, int segmentId )
{
m_ertBranchId = branchId;
m_ertSegmentId = segmentId;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigWellResultPoint::setOutletSegmentData( int outletBranchId, int outletSegmentId )
{
m_ertOutletBranchId = outletBranchId;
m_ertOutletSegmentId = outletSegmentId;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RigWellResultPoint::setBottomPosition( const cvf::Vec3d& bottomPosition )
{
m_bottomPosition = bottomPosition;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -49,7 +120,7 @@ bool RigWellResultPoint::isPointValid() const
//--------------------------------------------------------------------------------------------------
bool RigWellResultPoint::isCell() const
{
return m_gridCellIndex != cvf::UNDEFINED_SIZE_T;
return m_cellIndex != cvf::UNDEFINED_SIZE_T;
}
//--------------------------------------------------------------------------------------------------
@ -60,12 +131,20 @@ bool RigWellResultPoint::isValid() const
return isCell() || isPointValid();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigWellResultPoint::isOpen() const
{
return m_isOpen;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RigWellResultPoint::isEqual( const RigWellResultPoint& other ) const
{
return ( m_gridIndex == other.m_gridIndex && m_gridCellIndex == other.m_gridCellIndex && m_isOpen == other.m_isOpen &&
return ( m_gridIndex == other.m_gridIndex && m_cellIndex == other.m_cellIndex && m_isOpen == other.m_isOpen &&
m_ertBranchId == other.m_ertBranchId && m_ertSegmentId == other.m_ertSegmentId && m_flowRate == other.m_flowRate &&
m_oilRate == other.m_oilRate && m_gasRate == other.m_gasRate && m_waterRate == other.m_waterRate );
}
@ -149,3 +228,59 @@ void RigWellResultPoint::clearAllFlow()
m_gasRate = 0.0;
m_waterRate = 0.0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigWellResultPoint::gridIndex() const
{
return m_gridIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RigWellResultPoint::cellIndex() const
{
return m_cellIndex;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RigWellResultPoint::branchId() const
{
return m_ertBranchId;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RigWellResultPoint::segmentId() const
{
return m_ertSegmentId;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RigWellResultPoint::outletBranchId() const
{
return m_ertOutletBranchId;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RigWellResultPoint::outletSegmentId() const
{
return m_ertOutletSegmentId;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Vec3d RigWellResultPoint::bottomPosition() const
{
return m_bottomPosition;
}

View File

@ -34,9 +34,21 @@ struct RigWellResultPoint
{
RigWellResultPoint();
void setGridIndex( size_t gridIndex );
void setGridCellIndex( size_t cellIndex );
void setIsOpen( bool isOpen );
void setFlowData( double flowRate, double oilRate, double gasRate, double waterRate );
void setConnectionFactor( double connectionFactor );
void setSegmentData( int branchId, int segmentId );
void setOutletSegmentData( int outletBranchId, int outletSegmentId );
void setBottomPosition( const cvf::Vec3d& bottomPosition );
bool isPointValid() const;
bool isCell() const;
bool isValid() const;
bool isOpen() const;
bool isEqual( const RigWellResultPoint& other ) const;
double flowRate() const;
@ -46,12 +58,25 @@ struct RigWellResultPoint
double connectionFactor() const;
void clearAllFlow();
size_t gridIndex() const;
size_t cellIndex() const;
int branchId() const;
int segmentId() const;
int outletBranchId() const;
int outletSegmentId() const;
cvf::Vec3d bottomPosition() const;
private:
size_t m_gridIndex;
size_t m_gridCellIndex; //< Index to cell which is included in the well
size_t m_cellIndex; //< Index to cell which is included in the well
bool m_isOpen; //< Marks the well as open or closed as of Eclipse simulation
int m_ertBranchId;
int m_ertSegmentId;
int m_ertOutletBranchId;
int m_ertOutletSegmentId;
cvf::Vec3d m_bottomPosition; //< The estimated bottom position of the well segment, when we have no grid cell
// connections for the segment.
@ -103,3 +128,5 @@ public:
std::vector<RigWellResultBranch> m_wellResultBranches;
};
using SimulationWellCellBranch = std::pair<std::vector<cvf::Vec3d>, std::vector<RigWellResultPoint>>;

View File

@ -295,11 +295,11 @@ public:
size_t i;
size_t j;
size_t k;
size_t gridIdx = resPoint.m_gridIndex;
grids[gridIdx]->ijkFromCellIndex( resPoint.m_gridCellIndex, &i, &j, &k );
bool isOpen = resPoint.m_isOpen;
int branchId = resPoint.m_ertBranchId;
int segmentId = resPoint.m_ertSegmentId;
size_t gridIdx = resPoint.gridIndex();
grids[gridIdx]->ijkFromCellIndex( resPoint.cellIndex(), &i, &j, &k );
bool isOpen = resPoint.isOpen();
int branchId = resPoint.branchId();
int segmentId = resPoint.segmentId();
cellIs.push_back( static_cast<qint32>( i + 1 ) ); // NB: 1-based index in Octave
cellJs.push_back( static_cast<qint32>( j + 1 ) ); // NB: 1-based index in Octave

View File

@ -1155,24 +1155,34 @@ QString RiuResultTextBuilder::wellResultText()
if ( m_eclResDef->eclipseCase() && m_eclResDef->eclipseCase()->eclipseCaseData() )
{
cvf::Collection<RigSimWellData> simWellData = m_eclResDef->eclipseCase()->eclipseCaseData()->wellResults();
for ( size_t i = 0; i < simWellData.size(); i++ )
for ( const auto& singleWellResultData : simWellData )
{
RigSimWellData* singleWellResultData = simWellData.at( i );
if ( !singleWellResultData->hasWellResult( m_timeStepIndex ) )
{
continue;
}
const RigWellResultFrame* wellResultFrame = singleWellResultData->wellResultFrame( m_timeStepIndex );
const RigWellResultPoint* wellResultCell = wellResultFrame->findResultCellWellHeadIncluded( m_gridIndex, m_cellIndex );
if ( !wellResultFrame )
{
continue;
}
const RigWellResultPoint* wellResultCell = wellResultFrame->findResultCellWellHeadIncluded( m_gridIndex, m_cellIndex );
if ( wellResultCell )
{
const int branchId = wellResultCell->branchId();
const int segmentId = wellResultCell->segmentId();
const int outletBranchId = wellResultCell->outletBranchId();
const int outletSegmentId = wellResultCell->outletSegmentId();
text += QString( "-- Well-cell connection info --\n Well Name: %1\n Branch Id: %2\n Segment "
"Id: %3\n" )
"Id: %3\n Outlet Branch Id: %4\n Outlet Segment Id: %5" )
.arg( singleWellResultData->m_wellName )
.arg( wellResultCell->m_ertBranchId )
.arg( wellResultCell->m_ertSegmentId );
.arg( branchId )
.arg( segmentId )
.arg( outletBranchId )
.arg( outletSegmentId );
}
}
}

View File

@ -125,8 +125,8 @@ grpc::Status RiaGrpcSimulationWellService::GetSimulationWellCells( grpc::ServerC
size_t i;
size_t j;
size_t k;
size_t gridIdx = resPoint.m_gridIndex;
grids[gridIdx]->ijkFromCellIndex( resPoint.m_gridCellIndex, &i, &j, &k );
const size_t gridIdx = resPoint.gridIndex();
grids[gridIdx]->ijkFromCellIndex( resPoint.cellIndex(), &i, &j, &k );
Vec3i* ijk = new Vec3i;
ijk->set_i( i );
@ -135,9 +135,9 @@ grpc::Status RiaGrpcSimulationWellService::GetSimulationWellCells( grpc::ServerC
cellInfo->set_allocated_ijk( ijk );
cellInfo->set_grid_index( gridIdx );
cellInfo->set_is_open( resPoint.m_isOpen );
cellInfo->set_branch_id( resPoint.m_ertBranchId );
cellInfo->set_segment_id( resPoint.m_ertSegmentId );
cellInfo->set_is_open( resPoint.isOpen() );
cellInfo->set_branch_id( resPoint.branchId() );
cellInfo->set_segment_id( resPoint.segmentId() );
}
}
}