From 12a0040473cb411d447f84613578cccfc4029343 Mon Sep 17 00:00:00 2001 From: Magne Sjaastad Date: Fri, 21 Jun 2013 16:20:11 +0200 Subject: [PATCH] Added well branch number and segment number to result info view p4#: 21968 --- .../FileInterface/RifReaderEclipseOutput.cpp | 362 ++++++++++++------ .../RivWellPipesPartMgr.cpp | 272 +++++++------ .../ProjectDataModel/RimReservoirView.cpp | 28 ++ ApplicationCode/ProjectDataModel/RimWell.cpp | 15 +- .../ReservoirDataModel/RigCaseData.cpp | 9 +- .../RigSingleWellResultsData.h | 36 +- 6 files changed, 439 insertions(+), 283 deletions(-) diff --git a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp index e053f7da12..f5ba9162e6 100644 --- a/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp +++ b/ApplicationCode/FileInterface/RifReaderEclipseOutput.cpp @@ -707,6 +707,38 @@ bool RifReaderEclipseOutput::dynamicResult(const QString& result, PorosityModelR return true; } + + +// Helper structure to handle the metadata for connections in segments +struct SegmentData +{ + SegmentData(const well_conn_collection_type* connections) : + m_branchId(-1), + m_segmentId(-1), + m_gridIndex(cvf::UNDEFINED_SIZE_T), + m_connections(connections) + {} + + int m_branchId; + int m_segmentId; + size_t m_gridIndex; + const well_conn_collection_type* m_connections; +}; + +void getSegmentDataByBranchId(const std::list& segments, std::vector& branchSegments, int branchId) +{ + std::list::const_iterator it; + + for (it = segments.begin(); it != segments.end(); it++) + { + if (it->m_branchId == branchId) + { + branchSegments.push_back(*it); + } + } +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -823,6 +855,10 @@ void RifReaderEclipseOutput::readWellCells(const ecl_grid_type* mainEclGrid) wellResFrame.m_wellHead.m_gridCellIndex = grids[gridNr]->cellIndexFromIJK(cellI, cellJ, cellK); wellResFrame.m_wellHead.m_gridIndex = gridNr; } + else + { + CVF_ASSERT(0); + } std::string gridName; @@ -836,125 +872,106 @@ void RifReaderEclipseOutput::readWellCells(const ecl_grid_type* mainEclGrid) gridName = rigGrid->gridName(); } + + + std::list segmentList; + std::vector outletBranchSegmentList; // Keep a list of branch outlet segments to avoid traversal twice + + int branchCount = 0; if (well_state_is_MSW(ert_well_state)) { - well_branch_collection_type* branches = well_state_get_branches(ert_well_state); - - wellResFrame.m_wellResultBranches.resize(well_branch_collection_get_size(branches)); + wellResults->setMultiSegmentWell(true); + well_branch_collection_type* branches = well_state_get_branches(ert_well_state); + + branchCount = well_branch_collection_get_size(branches); for (int branchIdx = 0; branchIdx < well_branch_collection_get_size(branches); branchIdx++) { - RigWellResultBranch& rigWellResultBranch = wellResFrame.m_wellResultBranches[branchIdx]; - rigWellResultBranch.m_branchIndex = branchIdx; - wellResults->setMultiSegmentWell(true); - - const well_segment_type* branchBottomSegment = well_branch_collection_iget_start_segment(branches, branchIdx); - CVF_ASSERT(branchBottomSegment); + const well_segment_type* segment = well_branch_collection_iget_start_segment(branches, branchIdx); + int branchId = well_segment_get_branch_id(segment); - std::vector ertBranchSegments; // Segment closest to well head first in this vector - - rigWellResultBranch.m_ertBranchId = well_segment_get_branch_id(branchBottomSegment); - - - // Find outlet segment in next branch - // Start from bottom, and iterate over segments until next branch is detected - - int outletErtBranchId = rigWellResultBranch.m_ertBranchId; - const well_segment_type* outletSegmentInNextBranch = branchBottomSegment; - while (outletSegmentInNextBranch && outletErtBranchId == rigWellResultBranch.m_ertBranchId) + while (segment && branchId == well_segment_get_branch_id(segment)) { - // Insert at front, as we want the segments to be ordered starting closest to the well head - ertBranchSegments.insert(ertBranchSegments.begin(), outletSegmentInNextBranch); - - outletSegmentInNextBranch = well_segment_get_outlet(outletSegmentInNextBranch); - if (outletSegmentInNextBranch) + SegmentData segmentData(NULL); + segmentData.m_branchId = branchId; + segmentData.m_segmentId = well_segment_get_id(segment); + segmentData.m_gridIndex = gridNr; + + if (well_segment_has_grid_connections(segment, gridName.data())) { - outletErtBranchId = well_segment_get_branch_id(outletSegmentInNextBranch); + const well_conn_collection_type* connections = well_segment_get_connections(segment, gridName.data()); + segmentData.m_connections = connections; } - } + + // Insert in front, as the segments are accessed starting from grid cell closes to well head + segmentList.push_front(segmentData); - if (outletSegmentInNextBranch) - { - rigWellResultBranch.m_connectionDepthOnOutletBranch = well_segment_get_depth(outletSegmentInNextBranch); - - // No connections present in segment this branch is connected to - // Store intersection data used for visualization in RivWellPipesPartMgr - rigWellResultBranch.m_outletErtBranchId = outletErtBranchId; - } - - // Get first segment with connections in order to find grid cell index to connect the branch to - while(outletSegmentInNextBranch && !well_segment_has_grid_connections(outletSegmentInNextBranch, gridName.data())) - { - outletSegmentInNextBranch = well_segment_get_outlet(outletSegmentInNextBranch); - - // There are no connections in the directly connected outlet segment. - rigWellResultBranch.m_useBranchHeadAsCenterLineIntersectionTop = true; - } - - if (outletSegmentInNextBranch) - { - const well_conn_collection_type* connections = well_segment_get_connections(outletSegmentInNextBranch, gridName.data()); - CVF_ASSERT(connections); - size_t existingConnCount = rigWellResultBranch.m_wellCells.size(); - int connectionCount = well_conn_collection_get_size(connections); - CVF_ASSERT(connectionCount > 0); - - // Get last connection from the outlet segment - well_conn_type* ert_connection = well_conn_collection_iget(connections, connectionCount - 1); - int cellI = well_conn_get_i( ert_connection ); - int cellJ = well_conn_get_j( ert_connection ); - int cellK = well_conn_get_k( ert_connection ); - - // If a well is defined in fracture region, the K-value is from (cellCountK - 1) -> cellCountK*2 - 1 - // Adjust K so index is always in valid grid region - if (cellK >= static_cast(grids[gridNr]->cellCountK())) + if (well_segment_get_outlet_id(segment) == -1) { - cellK -= static_cast(grids[gridNr]->cellCountK()); + break; } - rigWellResultBranch.m_branchHead.m_gridIndex = gridNr; - rigWellResultBranch.m_branchHead.m_gridCellIndex = grids[gridNr]->cellIndexFromIJK(cellI , cellJ , cellK); - rigWellResultBranch.m_branchHead.m_isOpen = well_conn_open(ert_connection); - CVF_ASSERT(rigWellResultBranch.m_branchHead.m_gridCellIndex != cvf::UNDEFINED_SIZE_T); + segment = well_segment_get_outlet(segment); + } + outletBranchSegmentList.push_back(segment); + } + } + else + { + branchCount = 1; + + const well_conn_collection_type* connections = well_state_get_grid_connections(ert_well_state, gridName.data()); + SegmentData segmentData(connections); + segmentData.m_gridIndex = gridNr; + segmentList.push_front(segmentData); + } + + size_t currentGridBranchStartIndex = wellResFrame.m_wellResultBranches.size(); + wellResFrame.m_wellResultBranches.resize(currentGridBranchStartIndex + branchCount); + + + // Import all well result cells for all connections + for (int branchIdx = 0; branchIdx < branchCount; branchIdx++) + { + RigWellResultBranch& wellResultBranch = wellResFrame.m_wellResultBranches[currentGridBranchStartIndex + branchIdx]; + wellResultBranch.m_branchIndex = branchIdx; + wellResultBranch.m_ertBranchId = branchIdx; + + std::vector branchSegments; + getSegmentDataByBranchId(segmentList, branchSegments, branchIdx); + + for (size_t segmentIdx = 0; segmentIdx < branchSegments.size(); segmentIdx++) + { + SegmentData& connData = branchSegments[segmentIdx]; + + if (!connData.m_connections) + { + size_t existingCellCount = wellResultBranch.m_wellCells.size(); + wellResultBranch.m_wellCells.resize(existingCellCount + 1); + + RigWellResultCell& data = wellResultBranch.m_wellCells[existingCellCount]; + + data.m_ertBranchId = connData.m_branchId; + data.m_ertSegmentId = connData.m_segmentId; } else { - // Use well head as branch head - rigWellResultBranch.m_branchHead = wellResFrame.m_wellHead; - CVF_ASSERT(rigWellResultBranch.m_branchHead.m_gridCellIndex != cvf::UNDEFINED_SIZE_T); + int connectionCount = well_conn_collection_get_size(connData.m_connections); - - // TODO: Possibly add branch ID for the main branch the well head is a part of - } - - CVF_ASSERT(rigWellResultBranch.m_branchHead.m_gridCellIndex != cvf::UNDEFINED_SIZE_T); - - - for (size_t i = 0; i < ertBranchSegments.size(); i++) - { - outletSegmentInNextBranch = ertBranchSegments[i]; - - const well_conn_collection_type* connections = well_segment_get_connections(outletSegmentInNextBranch , gridName.data()); - if (!connections) continue; - - size_t existingConnCount = rigWellResultBranch.m_wellCells.size(); - int connectionCount = well_conn_collection_get_size(connections); - if (connectionCount > 0) - { - rigWellResultBranch.m_wellCells.resize(existingConnCount + connectionCount); - } + size_t existingCellCount = wellResultBranch.m_wellCells.size(); + wellResultBranch.m_wellCells.resize(existingCellCount + connectionCount); for (int connIdx = 0; connIdx < connectionCount; connIdx++) { - well_conn_type* ert_connection = well_conn_collection_iget(connections, connIdx); + well_conn_type* ert_connection = well_conn_collection_iget(connData.m_connections, connIdx); + CVF_ASSERT(ert_connection); - RigWellResultCell& data = rigWellResultBranch.m_wellCells[existingConnCount + connIdx]; + RigWellResultCell& data = wellResultBranch.m_wellCells[existingCellCount + connIdx]; int cellI = well_conn_get_i( ert_connection ); int cellJ = well_conn_get_j( ert_connection ); int cellK = well_conn_get_k( ert_connection ); - bool open = well_conn_open( ert_connection ); - int segmentId = well_conn_get_segment( ert_connection ); + bool isCellOpen = well_conn_open( ert_connection ); // If a well is defined in fracture region, the K-value is from (cellCountK - 1) -> cellCountK*2 - 1 // Adjust K so index is always in valid grid region @@ -964,57 +981,148 @@ void RifReaderEclipseOutput::readWellCells(const ecl_grid_type* mainEclGrid) } data.m_gridIndex = gridNr; - data.m_gridCellIndex = grids[gridNr]->cellIndexFromIJK(cellI , cellJ , cellK); - data.m_isOpen = open; + data.m_gridCellIndex = grids[gridNr]->cellIndexFromIJK(cellI, cellJ, cellK); + + data.m_isOpen = isCellOpen; + + data.m_ertBranchId = connData.m_branchId; + data.m_ertSegmentId = connData.m_segmentId; } } } } - else + + + if (well_state_is_MSW(ert_well_state)) { - const well_conn_collection_type* connections = well_state_get_grid_connections(ert_well_state, gridName.data()); - if (connections) + for (int branchIdx = 0; branchIdx < branchCount; branchIdx++) { - size_t branchIdx = wellResFrame.m_wellResultBranches.size(); - wellResFrame.m_wellResultBranches.resize(branchIdx + 1); + RigWellResultBranch& wellResultBranch = wellResFrame.m_wellResultBranches[currentGridBranchStartIndex + branchIdx]; - RigWellResultBranch& wellSegment = wellResFrame.m_wellResultBranches[branchIdx]; - wellSegment.m_branchIndex = branchIdx; - - int connectionCount = well_conn_collection_get_size(connections); - size_t existingConnCount = wellSegment.m_wellCells.size(); - wellSegment.m_wellCells.resize(existingConnCount + connectionCount); - - for (int connIdx = 0; connIdx < connectionCount; connIdx++) + const well_segment_type* outletBranchSegment = outletBranchSegmentList[branchIdx]; + if (outletBranchSegment) { - well_conn_type* ert_connection = well_conn_collection_iget(connections, connIdx); + int outletErtBranchId = well_segment_get_branch_id(outletBranchSegment); + + RigWellResultBranch& outletResultBranch = wellResFrame.m_wellResultBranches[currentGridBranchStartIndex + outletErtBranchId]; - RigWellResultCell& data = wellSegment.m_wellCells[existingConnCount + connIdx]; - int cellI = well_conn_get_i( ert_connection ); - int cellJ = well_conn_get_j( ert_connection ); - int cellK = well_conn_get_k( ert_connection ); - bool isCellOpen = well_conn_open( ert_connection ); - - // TODO: Are these available for this type of well? - int segmentId = well_conn_get_segment( ert_connection ); - - // If a well is defined in fracture region, the K-value is from (cellCountK - 1) -> cellCountK*2 - 1 - // Adjust K so index is always in valid grid region - if (cellK >= static_cast(grids[gridNr]->cellCountK())) + int outletErtSegmentId = well_segment_get_branch_id(outletBranchSegment); + size_t lastCellIndexForSegmentId = cvf::UNDEFINED_SIZE_T; + for (size_t outletCellIdx = 0; outletCellIdx < outletResultBranch.m_wellCells.size(); outletCellIdx++) { - cellK -= static_cast(grids[gridNr]->cellCountK()); + if (outletResultBranch.m_wellCells[outletCellIdx].m_ertSegmentId == outletErtSegmentId) + { + lastCellIndexForSegmentId = outletCellIdx; + } } - data.m_gridIndex = gridNr; - data.m_gridCellIndex = grids[gridNr]->cellIndexFromIJK(cellI , cellJ , cellK); + CVF_ASSERT(lastCellIndexForSegmentId != cvf::UNDEFINED_SIZE_T); - data.m_isOpen = isCellOpen; + if (lastCellIndexForSegmentId != cvf::UNDEFINED_SIZE_T) + { + if (outletResultBranch.m_wellCells[lastCellIndexForSegmentId].hasGridConnections()) + { + wellResultBranch.m_branchHead = outletResultBranch.m_wellCells[lastCellIndexForSegmentId]; + } + else + { + // There are no connections on outlet branch segment + // Add center coordinate of first connected well cell + + RigWellResultCell& outletCell = outletResultBranch.m_wellCells[lastCellIndexForSegmentId]; + + size_t firstCellWithGridConnection = cvf::UNDEFINED_SIZE_T; + for (size_t j = 0; j < wellResultBranch.m_wellCells.size(); j++) + { + if (wellResultBranch.m_wellCells[j].hasGridConnections()) + { + firstCellWithGridConnection = j; + break; + } + } + + if (firstCellWithGridConnection != cvf::UNDEFINED_SIZE_T) + { + const RigCell& cell = m_eclipseCase->cellFromWellResultCell(wellResultBranch.m_wellCells[firstCellWithGridConnection]); + cvf::Vec3d coordToAdd = cell.center(); + + size_t currentCellIndex = lastCellIndexForSegmentId; + RigWellResultCell& currCell = outletResultBranch.m_wellCells[currentCellIndex]; + + while (currentCellIndex != cvf::UNDEFINED_SIZE_T && !currCell.hasGridConnections()) + { + size_t coordCount = currCell.m_connectedBranchCount; + if (coordCount == 0) + { + currCell.m_interpolatedCenter = coordToAdd; + } + else + { + cvf::Vec3d tmp = currCell.m_interpolatedCenter * coordCount / static_cast(coordCount + 1); + cvf::Vec3d toBeAdded = coordToAdd / static_cast(coordCount + 1); + + currCell.m_interpolatedCenter = tmp + toBeAdded; + } + + currCell.m_connectedBranchCount++; + + if (currentCellIndex == 0) + { + currentCellIndex = cvf::UNDEFINED_SIZE_T; + + // Find the branch the outlet is connected to, and continue update of + // segments until a segment with a grid connection is found + RigWellResultCell& branchHead = outletResultBranch.m_branchHead; + if (branchHead.m_ertBranchId == -1 || currCell.m_ertBranchId == branchHead.m_ertBranchId) + { + continue; + } + + for (int outletBranchIdx = 0; outletBranchIdx < branchCount; outletBranchIdx++) + { + if (wellResFrame.m_wellResultBranches[currentGridBranchStartIndex + outletBranchIdx].m_ertBranchId == branchHead.m_ertBranchId) + { + outletResultBranch = wellResFrame.m_wellResultBranches[currentGridBranchStartIndex + outletBranchIdx]; + + for (int outletBranchCellIdx = 0; outletBranchCellIdx < outletResultBranch.m_wellCells.size(); outletBranchCellIdx++) + { + if (outletResultBranch.m_wellCells[outletBranchCellIdx].m_ertSegmentId == branchHead.m_ertSegmentId) + { + currentCellIndex = outletBranchCellIdx; + } + } + } + } + } + else + { + currentCellIndex--; + } + + if(currentCellIndex >= 0 && currentCellIndex < outletResultBranch.m_wellCells.size()) + { + currCell = outletResultBranch.m_wellCells[currentCellIndex]; + } + } + } + + wellResultBranch.m_branchHead = outletCell; + } + } } - } + else + { + // No branch head is assigned, use well head as fall back + wellResultBranch.m_branchHead = wellResFrame.m_wellHead; + } + + CVF_ASSERT(wellResultBranch.m_branchHead.hasConnections()); + } } } } + wellResults->computeMappingFromResultTimeIndicesToWellTimeIndices(m_timeSteps); wells.push_back(wellResults.p()); diff --git a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp index 1cfe6f9f5c..c6a22373a8 100644 --- a/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp +++ b/ApplicationCode/ModelVisualization/RivWellPipesPartMgr.cpp @@ -171,6 +171,32 @@ bool isIdentical(const RigWellResultCell* a, const RigWellResultCell* b) return true; } + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +const RigWellResultCell* findOutletWellResultCell(const RigWellResultCell& branchHead, const std::vector& wellResultBranches, RigCaseData* rigCaseData) +{ + CVF_ASSERT(rigCaseData); + + for (size_t i = 0; i < wellResultBranches.size(); i++) + { + if (wellResultBranches[i].m_ertBranchId == branchHead.m_ertBranchId) + { + for (size_t cellIdx = 0; cellIdx < wellResultBranches[i].m_wellCells.size(); cellIdx++) + { + if (wellResultBranches[i].m_wellCells[cellIdx].m_ertSegmentId == branchHead.m_ertSegmentId) + { + return &(wellResultBranches[i].m_wellCells[cellIdx]); + } + } + } + } + + return NULL; +} + + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -251,39 +277,59 @@ void RivWellPipesPartMgr::calculateWellPipeCenterline( std::vector< std::vector if (resBranches[brIdx].m_wellCells.size() == 0) continue; // Skip empty branches. Do not know why they exist, but they make problems. + prevResCell = NULL; + + + // Find the start the MSW well-branch centerline. Normal wells are started "once" at wellhead in the code above + if (wellResults->isMultiSegmentWell()) { pipeBranchesCLCoords.push_back(std::vector()); pipeBranchesCellIds.push_back(std::vector ()); - if (resBranches[brIdx].m_useBranchHeadAsCenterLineIntersectionTop) + if (brIdx == 0) { - // Intersection evaluation is done when all center lines are computed, - // as the center lines are used to compute the intersections + // The first branch contains segment number 1, and this is the only segment connected to well head + // See Eclipse documentation for the keyword WELSEGS + prevResCell = whResCell; - // Insert well head if this is branch head, as we have all information we need - if (isIdentical(&resBranches[brIdx].m_branchHead, whResCell)) - { - prevResCell = whResCell; + pipeBranchesCLCoords.back().push_back(whStartPos); + pipeBranchesCellIds.back().push_back(*prevResCell); - pipeBranchesCLCoords.back().push_back(whStartPos); - pipeBranchesCellIds.back().push_back(*prevResCell); - - pipeBranchesCLCoords.back().push_back(whIntermediate); - pipeBranchesCellIds.back().push_back(*prevResCell); - } + pipeBranchesCLCoords.back().push_back(whIntermediate); + pipeBranchesCellIds.back().push_back(*prevResCell); } else { - // Create a new branch and use branch head as previous result cell + if (resBranches[brIdx].m_branchHead.hasGridConnections()) + { + // Create a new branch and use branch head as previous result cell - prevResCell = &(resBranches[brIdx].m_branchHead); + prevResCell = &(resBranches[brIdx].m_branchHead); - const RigCell& whCell = rigReservoir->cellFromWellResultCell(resBranches[brIdx].m_branchHead); - cvf::Vec3d branchHeadStartPos = whCell.faceCenter(cvf::StructGridInterface::NEG_K); + const RigCell& cell = rigReservoir->cellFromWellResultCell(resBranches[brIdx].m_branchHead); + cvf::Vec3d branchHeadStartPos = cell.faceCenter(cvf::StructGridInterface::NEG_K); - pipeBranchesCLCoords.back().push_back(branchHeadStartPos); - pipeBranchesCellIds.back().push_back(*prevResCell); + pipeBranchesCLCoords.back().push_back(branchHeadStartPos); + pipeBranchesCellIds.back().push_back(*prevResCell); + } + else + { + // Find outlet well result cell + const RigWellResultCell* outletCell = findOutletWellResultCell(resBranches[brIdx].m_branchHead, resBranches, rigReservoir); + CVF_ASSERT(outletCell); + if (outletCell) + { + cvf::Vec3d interpolatedCoord = outletCell->m_interpolatedCenter; + + CVF_ASSERT(interpolatedCoord != cvf::Vec3d::UNDEFINED); + if (interpolatedCoord != cvf::Vec3d::UNDEFINED) + { + pipeBranchesCLCoords.back().push_back(interpolatedCoord); + pipeBranchesCellIds.back().push_back(RigWellResultCell()); + } + } + } } } @@ -296,55 +342,89 @@ void RivWellPipesPartMgr::calculateWellPipeCenterline( std::vector< std::vector std::vector& branchCellIds = pipeBranchesCellIds.back(); const RigWellResultCell& resCell = resBranchCells[cIdx]; + + if (!resCell.hasConnections()) + { + continue; + } + + if (resCell.hasBranchConnections()) + { + // Use the interpolated value of branch head + cvf::Vec3d interpolatedCoord = resCell.m_interpolatedCenter; + + CVF_ASSERT(interpolatedCoord != cvf::Vec3d::UNDEFINED); + if (interpolatedCoord != cvf::Vec3d::UNDEFINED) + { + pipeBranchesCLCoords.back().push_back(interpolatedCoord); + pipeBranchesCellIds.back().push_back(RigWellResultCell()); + } + + // Set previous result cell to NULL + prevResCell = NULL; + + continue; + } + const RigCell& cell = rigReservoir->cellFromWellResultCell(resCell); // Check if this and the previous cells has shared faces cvf::StructGridInterface::FaceType sharedFace; - if (resBranches[brIdx].m_useBranchHeadAsCenterLineIntersectionTop && cIdx == 0) - { - // Insert cell center of first cell - // Intersection point to connect to is inserted further down in this function - branchCLCoords.push_back(cell.center()); - branchCellIds.push_back(resCell); - } - else if (rigReservoir->findSharedSourceFace(sharedFace, resCell, *prevResCell)) + if (prevResCell && rigReservoir->findSharedSourceFace(sharedFace, resCell, *prevResCell)) { branchCLCoords.push_back(cell.faceCenter(sharedFace)); branchCellIds.push_back(resCell); } else { - // This and the previous cell does not share a face. We need to go out of the previous cell, before entering this. - const RigCell& prevCell = rigReservoir->cellFromWellResultCell(*prevResCell); - cvf::Vec3d centerPrevCell = prevCell.center(); + cvf::Vec3d previousCoord; + + if (prevResCell) + { + // This and the previous cell does not share a face. We need to go out of the previous cell, before entering this. + const RigCell& prevCell = rigReservoir->cellFromWellResultCell(*prevResCell); + previousCoord = prevCell.center(); + } + else + { + previousCoord = pipeBranchesCLCoords.back().back(); + } + cvf::Vec3d centerThisCell = cell.center(); // First make sure this cell is not starting a new "display" branch - if ( !isAutoDetectBranches + if ( wellResults->isMultiSegmentWell() + || !isAutoDetectBranches || (prevResCell == whResCell) - || (centerThisCell-centerPrevCell).lengthSquared() <= (centerThisCell - whStartPos).lengthSquared() + || (centerThisCell-previousCoord).lengthSquared() <= (centerThisCell - whStartPos).lengthSquared() ) { // Not starting a "display" branch // Create ray and intersect with cells cvf::Ray rayToThisCell; - rayToThisCell.setOrigin(centerPrevCell); - rayToThisCell.setDirection((centerThisCell - centerPrevCell).getNormalized()); + rayToThisCell.setOrigin(previousCoord); + rayToThisCell.setDirection((centerThisCell - previousCoord).getNormalized()); - cvf::Vec3d outOfPrevCell(centerPrevCell); cvf::Vec3d intoThisCell(centerThisCell); + cell.firstIntersectionPoint(rayToThisCell, &intoThisCell); - bool intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); - //CVF_ASSERT(intersectionOk); - intersectionOk = cell.firstIntersectionPoint(rayToThisCell, &intoThisCell); - //CVF_ASSERT(intersectionOk); - if ((intoThisCell - outOfPrevCell).lengthSquared() > 1e-3) + if (prevResCell) { - branchCLCoords.push_back(outOfPrevCell); - branchCellIds.push_back(*prevResCell); + cvf::Vec3d outOfPrevCell(previousCoord); + + const RigCell& prevCell = rigReservoir->cellFromWellResultCell(*prevResCell); + bool intersectionOk = prevCell.firstIntersectionPoint(rayToThisCell, &outOfPrevCell); + //CVF_ASSERT(intersectionOk); + //CVF_ASSERT(intersectionOk); + if ((intoThisCell - outOfPrevCell).lengthSquared() > 1e-3) + { + branchCLCoords.push_back(outOfPrevCell); + branchCellIds.push_back(*prevResCell); + } } + branchCLCoords.push_back(intoThisCell); branchCellIds.push_back(resCell); } @@ -356,7 +436,7 @@ void RivWellPipesPartMgr::calculateWellPipeCenterline( std::vector< std::vector // thus we interpret it as a new branch. // First finish the current branch - branchCLCoords.push_back(branchCLCoords.back() + 1.5*(centerPrevCell - branchCLCoords.back()) ); + branchCLCoords.push_back(branchCLCoords.back() + 1.5*(previousCoord - branchCLCoords.back()) ); // Create new display branch pipeBranchesCLCoords.push_back(std::vector()); @@ -380,7 +460,7 @@ void RivWellPipesPartMgr::calculateWellPipeCenterline( std::vector< std::vector prevResCell = &resCell; } - if (wellResults->isMultiSegmentWell()) + if (prevResCell && wellResults->isMultiSegmentWell()) { // All MSW branches are completed using the point 0.5 past the center of last cell const RigCell& prevCell = rigReservoir->cellFromWellResultCell(*prevResCell); @@ -389,7 +469,7 @@ void RivWellPipesPartMgr::calculateWellPipeCenterline( std::vector< std::vector } } - if (!wellResults->isMultiSegmentWell()) + if (prevResCell && !wellResults->isMultiSegmentWell()) { // For the last cell, add the point 0.5 past the center of that cell const RigCell& prevCell = rigReservoir->cellFromWellResultCell(*prevResCell); @@ -397,101 +477,6 @@ void RivWellPipesPartMgr::calculateWellPipeCenterline( std::vector< std::vector pipeBranchesCLCoords.back().push_back(pipeBranchesCLCoords.back().back() + 1.5*(centerPrevCell - pipeBranchesCLCoords.back().back()) ); } - if (wellResults->isMultiSegmentWell()) - { - // Compute intersection points for multi segment wells connected to segments of other branches - for (size_t brIdx = 0; brIdx < resBranches.size(); brIdx++) - { - const RigWellResultBranch& branchToConnect = resBranches[brIdx]; - - if (branchToConnect.m_useBranchHeadAsCenterLineIntersectionTop) - { - // Find intersection grid cell in branch to connect to - - cvf::Vec3d intersectionPoint = cvf::Vec3d::UNDEFINED; - - int outletErtBranchId = branchToConnect.m_outletErtBranchId; - - for (size_t outletBranchIdx = 0; outletBranchIdx < resBranches.size(); outletBranchIdx++) - { - if (resBranches[outletBranchIdx].m_ertBranchId == outletErtBranchId) - { - RigWellResultCell outletResultCell = resBranches[outletBranchIdx].m_branchHead; - - // Find generated pipe branch this cell resides in - for (size_t i = 0; i < pipeBranchesCellIds.size(); i++) - { - for (size_t j = 0; j < pipeBranchesCellIds[i].size(); j++) - { - const RigWellResultCell& candidate = pipeBranchesCellIds[i][j]; - if (isIdentical(&candidate, &outletResultCell)) - { - // Find the coordinate pair at the intersection between two cell IDs - while (j + 1 < pipeBranchesCellIds[i].size() && isIdentical(&pipeBranchesCellIds[i][j + 1], &outletResultCell)) - { - j++; - } - - if (j + 1 >= pipeBranchesCLCoords[i].size()) - { - // Use the last point in the center line - intersectionPoint = pipeBranchesCLCoords[i][j]; - } - else - { - cvf::Vec3d lineStart = pipeBranchesCLCoords[i][j]; - cvf::Vec3d lineEnd = pipeBranchesCLCoords[i][j + 1]; - - cvf::Plane depthPlane; - depthPlane.setFromPointAndNormal(cvf::Vec3d(0.0, 0.0, -branchToConnect.m_connectionDepthOnOutletBranch), cvf::Vec3d::Z_AXIS); - cvf::Vec3d linePlaneIntersect; - if (depthPlane.intersect(lineStart, lineEnd, &linePlaneIntersect)) - { - intersectionPoint = linePlaneIntersect; - } - } - } - } - } - } - } - - if (!intersectionPoint.isUndefined()) - { - // Find generated pipe branch this cell resides in - // and insert intersection point at start of list - - bool foundBranchToInsertInto = false; - - size_t i = 0; - while(!foundBranchToInsertInto && i < pipeBranchesCellIds.size()) - { - size_t j = 0; - while(!foundBranchToInsertInto && j < pipeBranchesCellIds[i].size()) - { - const RigWellResultCell& candidate = pipeBranchesCellIds[i][j]; - if (isIdentical(&candidate, &branchToConnect.m_wellCells[0])) - { - pipeBranchesCellIds[i].insert(pipeBranchesCellIds[i].begin(), candidate); - pipeBranchesCLCoords[i].insert(pipeBranchesCLCoords[i].begin(), intersectionPoint); - - foundBranchToInsertInto = true; - } - - j++; - } - - i++; - } - } - else - { - // Could not detect intersection, use well head as fall back? - // Currently, if nothing is found, the end of the branch closest to well head is not connected to main branch - } - } - } - } } CVF_ASSERT(pipeBranchesCellIds.size() == pipeBranchesCLCoords.size()); @@ -556,7 +541,12 @@ void RivWellPipesPartMgr::updatePipeResultColor(size_t frameIndex) for (size_t wcIdx = 0; wcIdx < cellIds.size(); ++wcIdx) { // we need a faster lookup, I guess - const RigWellResultCell* wResCell = wResFrame.findResultCell(cellIds[wcIdx].m_gridIndex, cellIds[wcIdx].m_gridCellIndex); + const RigWellResultCell* wResCell = NULL; + + if (cellIds[wcIdx].hasGridConnections()) + { + wResCell = wResFrame.findResultCell(cellIds[wcIdx].m_gridIndex, cellIds[wcIdx].m_gridCellIndex); + } if (wResCell == NULL) { diff --git a/ApplicationCode/ProjectDataModel/RimReservoirView.cpp b/ApplicationCode/ProjectDataModel/RimReservoirView.cpp index 6402bce527..afd54086ed 100644 --- a/ApplicationCode/ProjectDataModel/RimReservoirView.cpp +++ b/ApplicationCode/ProjectDataModel/RimReservoirView.cpp @@ -1025,6 +1025,29 @@ void RimReservoirView::appendCellResultInfo(size_t gridIndex, size_t cellIndex, } } } + + cvf::Collection wellResults = m_reservoir->reservoirData()->wellResults(); + for (size_t i = 0; i < wellResults.size(); i++) + { + RigSingleWellResultsData* singleWellResultData = wellResults.at(i); + + if (m_currentTimeStep < singleWellResultData->firstResultTimeStep()) + { + continue; + } + + const RigWellResultFrame& wellResultFrame = singleWellResultData->wellResultFrame(m_currentTimeStep); + const RigWellResultCell* wellResultCell = wellResultFrame.findResultCell(gridIndex, cellIndex); + if (wellResultCell) + { + resultInfoText->append(QString("(0-based) Branch Id : %1 Segment Id %2\n").arg(wellResultCell->m_ertBranchId).arg(wellResultCell->m_ertSegmentId)); + if (wellResultCell->hasBranchConnections()) + { + resultInfoText->append(QString("Branch Connection Count : %1\n").arg(wellResultCell->m_connectedBranchCount)); + resultInfoText->append(QString("Center coord : %1 %2 %3\n").arg(wellResultCell->m_interpolatedCenter.x()).arg(wellResultCell->m_interpolatedCenter.y()).arg(wellResultCell->m_interpolatedCenter.z())); + } + } + } } } @@ -1381,6 +1404,11 @@ void RimReservoirView::calculateVisibleWellCellsIncFence(cvf::UByteArray* visibl { if (wsResCells[cIdx].m_gridIndex == grid->gridIndex()) { + if (!wsResCells[cIdx].hasGridConnections()) + { + continue; + } + size_t gridCellIndex = wsResCells[cIdx].m_gridCellIndex; (*visibleCells)[gridCellIndex] = true; diff --git a/ApplicationCode/ProjectDataModel/RimWell.cpp b/ApplicationCode/ProjectDataModel/RimWell.cpp index 8d7b53366b..ccbeaef416 100644 --- a/ApplicationCode/ProjectDataModel/RimWell.cpp +++ b/ApplicationCode/ProjectDataModel/RimWell.cpp @@ -196,13 +196,16 @@ bool RimWell::calculateWellPipeVisibility(size_t frameIndex) const std::vector& wsResCells = wellResSegments[wsIdx].m_wellCells; for (size_t cIdx = 0; cIdx < wsResCells.size(); ++ cIdx) { - gridIndex = wsResCells[cIdx].m_gridIndex; - gridCellIndex = wsResCells[cIdx].m_gridCellIndex; - - cvf::cref cellVisibility = rvMan->cellVisibility(visGridParts[gpIdx], gridIndex, frameIndex); - if ((*cellVisibility)[gridCellIndex]) + if (wsResCells[cIdx].hasGridConnections()) { - return true; + gridIndex = wsResCells[cIdx].m_gridIndex; + gridCellIndex = wsResCells[cIdx].m_gridCellIndex; + + cvf::cref cellVisibility = rvMan->cellVisibility(visGridParts[gpIdx], gridIndex, frameIndex); + if ((*cellVisibility)[gridCellIndex]) + { + return true; + } } } } diff --git a/ApplicationCode/ReservoirDataModel/RigCaseData.cpp b/ApplicationCode/ReservoirDataModel/RigCaseData.cpp index 9183a153b3..4f6eebc983 100644 --- a/ApplicationCode/ReservoirDataModel/RigCaseData.cpp +++ b/ApplicationCode/ReservoirDataModel/RigCaseData.cpp @@ -178,10 +178,11 @@ void RigCaseData::computeWellCellsPrGrid() gridIndex = wellSegment.m_wellCells[cdIdx].m_gridIndex; gridCellIndex = wellSegment.m_wellCells[cdIdx].m_gridCellIndex; - CVF_ASSERT(gridIndex < m_wellCellsInGrid.size() && gridCellIndex < m_wellCellsInGrid[gridIndex]->size()); - - m_wellCellsInGrid[gridIndex]->set(gridCellIndex, true); - m_gridCellToWellIndex[gridIndex]->set(gridCellIndex, static_cast(wIdx)); + if(gridIndex < m_wellCellsInGrid.size() && gridCellIndex < m_wellCellsInGrid[gridIndex]->size()) + { + m_wellCellsInGrid[gridIndex]->set(gridCellIndex, true); + m_gridCellToWellIndex[gridIndex]->set(gridCellIndex, static_cast(wIdx)); + } } } } diff --git a/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.h b/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.h index db4af82e95..d5d918748b 100644 --- a/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.h +++ b/ApplicationCode/ReservoirDataModel/RigSingleWellResultsData.h @@ -25,27 +25,53 @@ #include "RimDefines.h" #include #include +#include "cvfVector3.h" struct RigWellResultCell { RigWellResultCell() : m_gridIndex(cvf::UNDEFINED_SIZE_T), m_gridCellIndex(cvf::UNDEFINED_SIZE_T), - m_isOpen(false) + m_isOpen(false), + m_ertBranchId(-1), + m_ertSegmentId(-1), + m_interpolatedCenter(cvf::Vec3d::UNDEFINED), + m_connectedBranchCount(0) { } + bool hasBranchConnections() const + { + return m_connectedBranchCount != 0; + } + + bool hasGridConnections() const + { + return m_gridCellIndex != cvf::UNDEFINED_SIZE_T; + } + + bool hasConnections() const + { + return hasGridConnections() || hasBranchConnections(); + } + + size_t m_gridIndex; size_t m_gridCellIndex; //< 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; + + cvf::Vec3d m_interpolatedCenter; + size_t m_connectedBranchCount; }; struct RigWellResultBranch { RigWellResultBranch() : m_branchIndex(cvf::UNDEFINED_SIZE_T), - m_ertBranchId(-1), - m_useBranchHeadAsCenterLineIntersectionTop(false) + m_ertBranchId(-1) {} size_t m_branchIndex; @@ -57,8 +83,6 @@ struct RigWellResultBranch // For standard wells, this is always well head. RigWellResultCell m_branchHead; - bool m_useBranchHeadAsCenterLineIntersectionTop; - // If the outlet segment does not have any connections, it is not possible to populate branch head // Instead, use the intersection segment outlet branch index and the depth of this segment to identify intersection point // when computing centerline coords in RivWellPipesPartMgr @@ -79,6 +103,8 @@ public: const RigWellResultCell* findResultCell(size_t gridIndex, size_t gridCellIndex) const { + CVF_ASSERT(gridIndex != cvf::UNDEFINED_SIZE_T && gridCellIndex != cvf::UNDEFINED_SIZE_T); + if (m_wellHead.m_gridCellIndex == gridCellIndex && m_wellHead.m_gridIndex == gridIndex ) { return &m_wellHead;