diff --git a/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp b/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp index 3418af8888..09123be527 100644 --- a/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp +++ b/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.cpp @@ -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( 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>::iterator posContribIt; posContribIt = segmentIdToPositionContrib.find( ertSegmentId ); @@ -1973,7 +1982,7 @@ void RifReaderEclipseOutput::readWellCells( const ecl_grid_type* mainEclGrid, bo std::vector 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( 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 ) ) { diff --git a/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h b/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h index dba580e322..066d002831 100644 --- a/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h +++ b/ApplicationLibCode/FileInterface/RifReaderEclipseOutput.h @@ -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* faults ); diff --git a/ApplicationLibCode/ModelVisualization/RivSimWellPipesPartMgr.cpp b/ApplicationLibCode/ModelVisualization/RivSimWellPipesPartMgr.cpp index dc24bb89de..9daa02aa1f 100644 --- a/ApplicationLibCode/ModelVisualization/RivSimWellPipesPartMgr.cpp +++ b/ApplicationLibCode/ModelVisualization/RivSimWellPipesPartMgr.cpp @@ -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> pipeBranchesCellIds; - m_simWellInView->calculateWellPipeStaticCenterLine( m_pipeBranchesCLCoords, pipeBranchesCellIds ); + auto createSimWells = []( RimSimWellInView* simWellInView ) -> std::vector { + std::vector 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> 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 ) { diff --git a/ApplicationLibCode/ModelVisualization/RivWellSpheresPartMgr.cpp b/ApplicationLibCode/ModelVisualization/RivWellSpheresPartMgr.cpp index ba968f40a0..c46beeba10 100644 --- a/ApplicationLibCode/ModelVisualization/RivWellSpheresPartMgr.cpp +++ b/ApplicationLibCode/ModelVisualization/RivWellSpheresPartMgr.cpp @@ -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 ) { diff --git a/ApplicationLibCode/ProjectDataModel/Completions/RimSimWellFracture.cpp b/ApplicationLibCode/ProjectDataModel/Completions/RimSimWellFracture.cpp index b6ce39bdb3..320dbd6da6 100644 --- a/ApplicationLibCode/ProjectDataModel/Completions/RimSimWellFracture.cpp +++ b/ApplicationLibCode/ProjectDataModel/Completions/RimSimWellFracture.cpp @@ -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> pipeBranchesCLCoords; - std::vector> 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 ); } diff --git a/ApplicationLibCode/ProjectDataModel/Flow/RimFlowDiagSolution.cpp b/ApplicationLibCode/ProjectDataModel/Flow/RimFlowDiagSolution.cpp index 69b09b2206..72a0bfac59 100644 --- a/ApplicationLibCode/ProjectDataModel/Flow/RimFlowDiagSolution.cpp +++ b/ApplicationLibCode/ProjectDataModel/Flow/RimFlowDiagSolution.cpp @@ -191,11 +191,11 @@ std::map> 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( activeCellInfo->cellResultIndex( reservoirCellIndex ) ); diff --git a/ApplicationLibCode/ProjectDataModel/Flow/RimWellAllocationOverTimePlot.cpp b/ApplicationLibCode/ProjectDataModel/Flow/RimWellAllocationOverTimePlot.cpp index d572b7d3a0..0d0e3c5097 100644 --- a/ApplicationLibCode/ProjectDataModel/Flow/RimWellAllocationOverTimePlot.cpp +++ b/ApplicationLibCode/ProjectDataModel/Flow/RimWellAllocationOverTimePlot.cpp @@ -454,18 +454,16 @@ RimWellAllocationOverTimeCollection RimWellAllocationOverTimePlot::createWellAll continue; } - std::vector> pipeBranchesCLCoords; - std::vector> pipeBranchesCellIds; std::map*> 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() ) { diff --git a/ApplicationLibCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp b/ApplicationLibCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp index fd4c4b9183..92c54bead0 100644 --- a/ApplicationLibCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp +++ b/ApplicationLibCode/ProjectDataModel/Flow/RimWellAllocationPlot.cpp @@ -246,16 +246,12 @@ void RimWellAllocationPlot::updateFromWell() if ( !simWellData ) return; // Set up the Accumulated Well Flow Calculator - std::vector> pipeBranchesCLCoords; - std::vector> 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*> tracerFractionCellValues = RimWellAllocationTools::findOrCreateRelevantTracerCellFractions( simWellData, m_flowDiagSolution, m_timeStep ); diff --git a/ApplicationLibCode/ProjectDataModel/Flow/RimWellPltPlot.cpp b/ApplicationLibCode/ProjectDataModel/Flow/RimWellPltPlot.cpp index 2ea0431a99..7ae4f67ac8 100644 --- a/ApplicationLibCode/ProjectDataModel/Flow/RimWellPltPlot.cpp +++ b/ApplicationLibCode/ProjectDataModel/Flow/RimWellPltPlot.cpp @@ -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& 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 ); } diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseCase.cpp b/ApplicationLibCode/ProjectDataModel/RimEclipseCase.cpp index 92119698ee..d1009398f1 100644 --- a/ApplicationLibCode/ProjectDataModel/RimEclipseCase.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimEclipseCase.cpp @@ -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() ); diff --git a/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp b/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp index d7fb9d0d7f..6e85b80872 100644 --- a/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimEclipseView.cpp @@ -1685,14 +1685,14 @@ void RimEclipseView::calculateVisibleWellCellsIncFence( cvf::UByteArray* visible const std::vector& 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 diff --git a/ApplicationLibCode/ProjectDataModel/RimSimWellInView.cpp b/ApplicationLibCode/ProjectDataModel/RimSimWellInView.cpp index d655077700..c349973b34 100644 --- a/ApplicationLibCode/ProjectDataModel/RimSimWellInView.cpp +++ b/ApplicationLibCode/ProjectDataModel/RimSimWellInView.cpp @@ -192,15 +192,6 @@ std::vector RimSimWellInView::wellPipeBranches() const return std::vector(); } -//-------------------------------------------------------------------------------------------------- -/// -//-------------------------------------------------------------------------------------------------- -void RimSimWellInView::calculateWellPipeStaticCenterLine( std::vector>& pipeBranchesCLCoords, - std::vector>& 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> pipeBranchesCLCoords; - std::vector> pipeBranchesCellIds; - - auto noConst = const_cast( this ); - RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( noConst, pipeBranchesCLCoords, pipeBranchesCellIds ); + auto noConst = const_cast( 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() ); } } diff --git a/ApplicationLibCode/ProjectDataModel/RimSimWellInView.h b/ApplicationLibCode/ProjectDataModel/RimSimWellInView.h index 17f6d47005..8007bedabb 100644 --- a/ApplicationLibCode/ProjectDataModel/RimSimWellInView.h +++ b/ApplicationLibCode/ProjectDataModel/RimSimWellInView.h @@ -76,9 +76,6 @@ public: std::vector wellPipeBranches() const; - void calculateWellPipeStaticCenterLine( std::vector>& pipeBranchesCLCoords, - std::vector>& pipeBranchesCellIds ); - void wellHeadTopBottomPosition( int frameIndex, cvf::Vec3d* top, cvf::Vec3d* bottom ); double pipeRadius(); int pipeCrossSectionVertexCount(); diff --git a/ApplicationLibCode/ProjectDataModel/Streamlines/RimStreamlineInViewCollection.cpp b/ApplicationLibCode/ProjectDataModel/Streamlines/RimStreamlineInViewCollection.cpp index ef570785b1..1705613d30 100644 --- a/ApplicationLibCode/ProjectDataModel/Streamlines/RimStreamlineInViewCollection.cpp +++ b/ApplicationLibCode/ProjectDataModel/Streamlines/RimStreamlineInViewCollection.cpp @@ -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( swdata->m_wellName, cell ) ); diff --git a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake index 64a9c69ae9..1eea926592 100644 --- a/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake +++ b/ApplicationLibCode/ReservoirDataModel/CMakeLists_files.cmake @@ -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}) diff --git a/ApplicationLibCode/ReservoirDataModel/RigAccWellFlowCalculator.cpp b/ApplicationLibCode/ReservoirDataModel/RigAccWellFlowCalculator.cpp index 8dd7d14f7a..9300210ea0 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigAccWellFlowCalculator.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigAccWellFlowCalculator.cpp @@ -711,9 +711,9 @@ std::vector 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 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 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 ); } diff --git a/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseData.cpp b/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseData.cpp index 75842710c5..0cf5b17899 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseData.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigEclipseCaseData.cpp @@ -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 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 if ( m_simWellBranchCache.find( simWellSeachItem ) == m_simWellBranchCache.end() ) { - std::vector> pipeBranchesCLCoords; - std::vector> 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() ) ); - 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 newWellPath = new RigWellPath( wellMdCalculator.wellPathPoints(), wellMdCalculator.measuredDepths() ); diff --git a/ApplicationLibCode/ReservoirDataModel/RigMswCenterLineCalculator.cpp b/ApplicationLibCode/ReservoirDataModel/RigMswCenterLineCalculator.cpp new file mode 100644 index 0000000000..588035be11 --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigMswCenterLineCalculator.cpp @@ -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 +// 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 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 + 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& resultBranches = wellFrame.m_wellResultBranches; + + std::vector 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 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 simWellBranches; + for ( const auto& wellBranch : wellBranches ) + { + std::vector cellCenterCoords; + std::vector 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 branchCoords, + const std::vector& resultPoints, + const RigEclipseCaseData* eclipseCaseData ) +{ + std::vector adjustedCoords; + std::vector 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::mergeShortBranchesIntoLongBranches( const std::vector& resBranches ) +{ + std::vector longWellBranches; + std::vector 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; +} diff --git a/ApplicationLibCode/ReservoirDataModel/RigMswCenterLineCalculator.h b/ApplicationLibCode/ReservoirDataModel/RigMswCenterLineCalculator.h new file mode 100644 index 0000000000..148daecc03 --- /dev/null +++ b/ApplicationLibCode/ReservoirDataModel/RigMswCenterLineCalculator.h @@ -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 +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "RigWellResultPoint.h" + +#include "cvfVector3.h" + +#include +#include + +class RigEclipseCaseData; +class RimSimWellInView; +class RigSimWellData; + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +class RigMswCenterLineCalculator +{ +public: + static std::vector calculateMswWellPipeGeometry( RimSimWellInView* rimWell ); + +private: + struct OutputSegment + { + int outputSegmentId = -1; + int outputSegmentBranchId = -1; + }; + + struct WellBranch + { + int m_branchId = -1; + + std::map, OutputSegment> m_gridCellsConnectedToSegments; + std::map>> m_segmentsWithGridCells; + + bool containsGridCell( const std::pair& 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 calculateMswWellPipeGeometryForTimeStep( const RigEclipseCaseData* eclipseCaseData, + const RigSimWellData* simWellData, + int timeStepIndex ); + + static SimulationWellCellBranch addCoordsAtCellFaceIntersectionsAndCreateBranch( const std::vector branchCoords, + const std::vector& resultPoints, + const RigEclipseCaseData* eclipseCaseData ); + + static std::vector mergeShortBranchesIntoLongBranches( const std::vector& resBranches ); +}; diff --git a/ApplicationLibCode/ReservoirDataModel/RigReservoirBuilderMock.cpp b/ApplicationLibCode/ReservoirDataModel/RigReservoirBuilderMock.cpp index 4ba7f465ba..c5247bf69f 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigReservoirBuilderMock.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigReservoirBuilderMock.cpp @@ -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 ); } diff --git a/ApplicationLibCode/ReservoirDataModel/RigSimWellData.cpp b/ApplicationLibCode/ReservoirDataModel/RigSimWellData.cpp index a589672539..8fefb33744 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigSimWellData.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigSimWellData.cpp @@ -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] ); } diff --git a/ApplicationLibCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp b/ApplicationLibCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp index ccbdea531c..b1118a2020 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.cpp @@ -19,6 +19,8 @@ #include "RigSimulationWellCenterLineCalculator.h" +#include "RiaLogging.h" + #include "RigCell.h" #include "RigCellFaceGeometryTools.h" #include "RigEclipseCaseData.h" @@ -38,6 +40,79 @@ #include #include +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +std::vector RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( RimSimWellInView* rimWell ) +{ + std::vector> pipeBranchesCLCoords; + std::vector> pipeBranchesCellIds; + + calculateWellPipeStaticCenterline( rimWell, pipeBranchesCLCoords, pipeBranchesCellIds ); + + std::vector 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 + RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData, + const RigSimWellData* simWellData, + int timeStepIndex, + bool isAutoDetectBranches, + bool useAllCellCenters ) +{ + std::vector> pipeBranchesCLCoords; + std::vector> pipeBranchesCellIds; + + calculateWellPipeCenterlineForTimeStep( eclipseCaseData, + simWellData, + timeStepIndex, + isAutoDetectBranches, + useAllCellCenters, + pipeBranchesCLCoords, + pipeBranchesCellIds ); + + std::vector 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>> + RigSimulationWellCenterLineCalculator::extractBranchData( const std::vector simulationBranch ) +{ + std::vector> pipeBranchesCLCoords; + std::vector> 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>& pipeBranchesCLCoords, - std::vector>& pipeBranchesCellIds ) +void RigSimulationWellCenterLineCalculator::calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData, + const RigSimWellData* wellResults, + int timeStepIndex, + bool isAutoDetectBranches, + bool useAllCellCenters, + std::vector>& pipeBranchesCLCoords, + std::vector>& 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 diff --git a/ApplicationLibCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.h b/ApplicationLibCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.h index 7e4b166724..6730d66966 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.h +++ b/ApplicationLibCode/ReservoirDataModel/RigSimulationWellCenterLineCalculator.h @@ -19,8 +19,11 @@ #pragma once +#include "RigWellResultPoint.h" + #include "cvfVector3.h" +#include #include class RigEclipseCaseData; @@ -36,19 +39,38 @@ class RigWellResultFrame; class RigSimulationWellCenterLineCalculator { public: + static std::vector calculateWellPipeStaticCenterline( RimSimWellInView* rimWell ); + + static std::vector calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData, + const RigSimWellData* simWellData, + int timeStepIndex, + bool isAutoDetectBranches, + bool useAllCellCenters ); + + static std::pair>, std::vector>> + extractBranchData( const std::vector simulationBranch ); + +private: static void calculateWellPipeStaticCenterline( RimSimWellInView* rimWell, std::vector>& pipeBranchesCLCoords, std::vector>& pipeBranchesCellIds ); - static void calculateWellPipeCenterlineFromWellFrame( const RigEclipseCaseData* eclipseCaseData, - const RigSimWellData* simWellData, - int timeStepIndex, - bool isAutoDetectBranches, - bool useAllCellCenters, - std::vector>& pipeBranchesCLCoords, - std::vector>& pipeBranchesCellIds ); + static void calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData, + const RigSimWellData* simWellData, + int timeStepIndex, + bool isAutoDetectBranches, + bool useAllCellCenters, + std::vector>& pipeBranchesCLCoords, + std::vector>& pipeBranchesCellIds ); + + static std::vector calculateMswWellPipeGeometryForTimeStep( const RigEclipseCaseData* eclipseCaseData, + const RigSimWellData* simWellData, + int timeStepIndex ); + + static SimulationWellCellBranch addSegmentsToCellFaces( const std::vector branchCoords, + const std::vector& resultPoints, + const RigEclipseCaseData* eclipseCaseData ); -private: static bool hasAnyValidDataCells( const RigWellResultBranch& branch ); static void finishPipeCenterLine( std::vector>& pipeBranchesCLCoords, const cvf::Vec3d& lastCellCenter ); diff --git a/ApplicationLibCode/ReservoirDataModel/RigWellResultPoint.cpp b/ApplicationLibCode/ReservoirDataModel/RigWellResultPoint.cpp index 5630412b4a..88ad81d687 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigWellResultPoint.cpp +++ b/ApplicationLibCode/ReservoirDataModel/RigWellResultPoint.cpp @@ -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; +} diff --git a/ApplicationLibCode/ReservoirDataModel/RigWellResultPoint.h b/ApplicationLibCode/ReservoirDataModel/RigWellResultPoint.h index c718ea445d..74d11d698a 100644 --- a/ApplicationLibCode/ReservoirDataModel/RigWellResultPoint.h +++ b/ApplicationLibCode/ReservoirDataModel/RigWellResultPoint.h @@ -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 m_wellResultBranches; }; + +using SimulationWellCellBranch = std::pair, std::vector>; diff --git a/ApplicationLibCode/SocketInterface/RiaWellDataCommands.cpp b/ApplicationLibCode/SocketInterface/RiaWellDataCommands.cpp index c8e722d187..682745e491 100644 --- a/ApplicationLibCode/SocketInterface/RiaWellDataCommands.cpp +++ b/ApplicationLibCode/SocketInterface/RiaWellDataCommands.cpp @@ -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( i + 1 ) ); // NB: 1-based index in Octave cellJs.push_back( static_cast( j + 1 ) ); // NB: 1-based index in Octave diff --git a/ApplicationLibCode/UserInterface/RiuResultTextBuilder.cpp b/ApplicationLibCode/UserInterface/RiuResultTextBuilder.cpp index 9a32b2a3d1..acf05b44e6 100644 --- a/ApplicationLibCode/UserInterface/RiuResultTextBuilder.cpp +++ b/ApplicationLibCode/UserInterface/RiuResultTextBuilder.cpp @@ -1155,24 +1155,34 @@ QString RiuResultTextBuilder::wellResultText() if ( m_eclResDef->eclipseCase() && m_eclResDef->eclipseCase()->eclipseCaseData() ) { cvf::Collection 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 ); } } } diff --git a/GrpcInterface/RiaGrpcSimulationWellService.cpp b/GrpcInterface/RiaGrpcSimulationWellService.cpp index b04303466f..b15bc5a1eb 100644 --- a/GrpcInterface/RiaGrpcSimulationWellService.cpp +++ b/GrpcInterface/RiaGrpcSimulationWellService.cpp @@ -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() ); } } }