#14646 MSW: Report a grid cell only once across COMPSEGS branches

A grid cell has a single COMPDAT connection and must be connected to exactly one segment, but the geometry-based export emitted one COMPSEGS row per branch intersecting the cell. Restore the well-global bookkeeping the removed tree path had: tag each branch with its origin and let the branch carrying most flow claim a shared cell, perforations before fishbones before fractures.
This commit is contained in:
Magne Sjaastad committed 2026-08-31 10:28:41 +02:00
1 parent 377751eb68
commit d085f6ce74
4 files changed
+126 -10

No files matched your search

@@ -848,7 +848,7 @@ std::vector<RigMswBranch> buildFractureBranches( RimEclipseCase*
seg.description = fracture->name().toStdString();
seg.intersections = std::move( compsegs );
result.push_back( RigMswBranch{ fracBranch, std::nullopt, { std::move( seg ) } } );
result.push_back( RigMswBranch{ fracBranch, std::nullopt, { std::move( seg ) }, RigMswBranchSource::Fracture } );
}
return result;
@@ -993,7 +993,7 @@ std::vector<RigMswBranch> buildFishbonesBranches( const RimEclipseCase*
fishbonesContext.icdSegments.push_back( { icdSegNum, std::move( icdGlobalCellIndices ) } );
result.push_back( RigMswBranch{ icdBranch, std::nullopt, { std::move( icdSeg ) } } );
result.push_back( RigMswBranch{ icdBranch, std::nullopt, { std::move( icdSeg ) }, RigMswBranchSource::Fishbones } );
// Lateral sub-segments
for ( size_t lateralIndex : lateralIndices )
@@ -1099,7 +1099,7 @@ std::vector<RigMswBranch> buildFishbonesBranches( const RimEclipseCase*
fishbonesContext.laterals.push_back( std::move( lateralContext ) );
result.push_back( RigMswBranch{ latBranch, std::nullopt, std::move( latSegs ) } );
result.push_back( RigMswBranch{ latBranch, std::nullopt, std::move( latSegs ), RigMswBranchSource::Fishbones } );
}
}
}
@@ -41,6 +41,9 @@
#include "cafAssert.h"
#include <algorithm>
#include <numeric>
#include <set>
#include <tuple>
namespace RicWellPathExportMswGeometryPath
{
@@ -504,7 +507,13 @@ RigMswTableData collectTableData( const RigMswWellExportData& exportData, RiaDef
tableData.setWelsegsHeader( exportData.header );
// Collected while the segments are visited, and added to the table data ordered by branch number.
std::vector<CompsegsRow> compsegsRows;
// The branch source is kept alongside the row to resolve cells claimed by several branches.
struct CollectedCompsegsRow
{
CompsegsRow row;
RigMswBranchSource source;
};
std::vector<CollectedCompsegsRow> compsegsRows;
auto emitSegment = [&]( const RigMswBranch& branch, const RigMswSegment& seg )
{
@@ -533,7 +542,7 @@ RigMswTableData collectTableData( const RigMswWellExportData& exportData, RiaDef
compRow.distanceStart = inter.distanceStart;
compRow.distanceEnd = inter.distanceEnd;
compRow.gridName = inter.gridName;
compsegsRows.push_back( compRow );
compsegsRows.push_back( { compRow, branch.source } );
}
// WSEGVALV row
@@ -554,14 +563,37 @@ RigMswTableData collectTableData( const RigMswWellExportData& exportData, RiaDef
tableData.addMswBranch( branch );
}
// A grid cell has a single COMPDAT connection and must be connected to exactly one segment. When
// several branches intersect the same cell, the branch carrying most flow claims it: perforations
// first, then fishbones, then fractures. Visit the rows in that order and drop the later claims.
std::vector<size_t> claimOrder( compsegsRows.size() );
std::iota( claimOrder.begin(), claimOrder.end(), size_t( 0 ) );
std::stable_sort( claimOrder.begin(),
claimOrder.end(),
[&]( size_t lhs, size_t rhs ) { return compsegsRows[lhs].source < compsegsRows[rhs].source; } );
std::set<std::tuple<std::string, size_t, size_t, size_t>> connectedCells;
std::vector<bool> isCellOwner( compsegsRows.size(), false );
for ( size_t index : claimOrder )
{
const auto& row = compsegsRows[index].row;
isCellOwner[index] = connectedCells.emplace( row.gridName, row.i, row.j, row.k ).second;
}
// COMPSEGS is ordered by branch number. WELSEGS keeps the order the branches are listed in, where
// the completion branches follow the lateral they are connected to and thus are not sorted by
// branch number. The sort is stable, so the rows of a branch keep their order along the well path.
std::stable_sort( compsegsRows.begin(),
compsegsRows.end(),
std::vector<CompsegsRow> ownedRows;
for ( size_t index = 0; index < compsegsRows.size(); ++index )
{
if ( isCellOwner[index] ) ownedRows.push_back( compsegsRows[index].row );
}
std::stable_sort( ownedRows.begin(),
ownedRows.end(),
[]( const CompsegsRow& lhs, const CompsegsRow& rhs ) { return lhs.branch < rhs.branch; } );
for ( const auto& compsegsRow : compsegsRows )
for ( const auto& compsegsRow : ownedRows )
{
tableData.addCompsegsRow( compsegsRow );
}