mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 07:00:17 -05:00
#14241 MSW: Fix dual-porosity perforation COMPSEGS over-reporting
The geometry-based MSW export emitted a COMPSEGS row for every cell a perforation overlaps in the whole-well geometric intersection. In dual-porosity models this splits a perforation across matrix cells at cell boundaries, producing extra connections that do not match the COMPDAT export. Restrict main-bore perforation COMPSEGS to the cells the perforation actually connects to, computed by clipping the well path to the perforation MD range and re-intersecting the grid, mirroring generatePerforationsCompdatValues. For single-porosity models the cell sets are identical, so this is a no-op.
This commit is contained in:
1 parent
3c5c160b93
commit
f4a7d2cb4a
1 file changed
+42
+42
@@ -46,8 +46,12 @@
|
||||
#include "RiaLogging.h"
|
||||
#include "RiaQStringFormatter.h"
|
||||
|
||||
#include "Well/RigWellPath.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace RicMswBranchBuilder
|
||||
{
|
||||
@@ -174,6 +178,39 @@ RigMswBranch buildMainBoreBranch( const RimWellPath*
|
||||
emittedCountPerInterval[perf] = 0;
|
||||
}
|
||||
|
||||
// For each perforation interval, determine the set of grid cells the perforation actually
|
||||
// connects to. This mirrors the standard COMPDAT export (generatePerforationsCompdatValues):
|
||||
// the well path is clipped to the perforation MD range and re-intersected with the grid.
|
||||
// COMPSEGS rows are then emitted only for cells in this set.
|
||||
//
|
||||
// This matters for dual-porosity models, where the whole-well geometric intersection
|
||||
// (filteredIntersections) may split a perforation across several matrix cells at cell
|
||||
// boundaries, while the clipped perforation intersection collapses it to the cells that
|
||||
// carry the connection. Restricting to the latter keeps the MSW COMPSEGS consistent with
|
||||
// the COMPDAT connections. For single-porosity models the two sets are identical, so this
|
||||
// is a no-op.
|
||||
std::map<const RimPerforationInterval*, std::set<size_t>> perforationCompletionCells;
|
||||
if ( const auto* wellPathGeometry = wellPath->wellPathGeometry() )
|
||||
{
|
||||
for ( const auto* perf : perforationIntervals )
|
||||
{
|
||||
const auto [clipCoords, clipMds] = wellPathGeometry->clippedPointSubset( perf->startMD(), perf->endMD() );
|
||||
|
||||
const auto perfCells = RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( eclipseCase->eclipseCaseData(),
|
||||
wellPath->name(),
|
||||
clipCoords,
|
||||
clipMds );
|
||||
|
||||
std::set<size_t>& cellSet = perforationCompletionCells[perf];
|
||||
for ( const auto& perfCell : perfCells )
|
||||
{
|
||||
const bool cellIsActive = !activeCellInfo || perfCell.globCellIndex >= mainGrid->totalCellCount() ||
|
||||
activeCellInfo->isActive( ReservoirCellIndex( perfCell.globCellIndex ) );
|
||||
if ( cellIsActive ) cellSet.insert( perfCell.globCellIndex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ( const auto& cellInfo : filteredIntersections )
|
||||
{
|
||||
const double cellLength = std::fabs( cellInfo.endMD - cellInfo.startMD );
|
||||
@@ -198,6 +235,11 @@ RigMswBranch buildMainBoreBranch( const RimWellPath*
|
||||
if ( activeCellInfo && cellInfo.globCellIndex < mainGrid->totalCellCount() &&
|
||||
!activeCellInfo->isActive( ReservoirCellIndex( cellInfo.globCellIndex ) ) )
|
||||
continue;
|
||||
|
||||
// Skip cells the perforation does not actually connect to (see perforationCompletionCells above).
|
||||
const auto& completionCells = perforationCompletionCells[perf];
|
||||
if ( !completionCells.empty() && !completionCells.count( cellInfo.globCellIndex ) ) continue;
|
||||
|
||||
overlapCountPerInterval[perf]++;
|
||||
auto& filterEval = filterEvaluators.at( perf );
|
||||
if ( !filterEval.includesGlobalCell( cellInfo.globCellIndex ) ) continue;
|
||||
|
||||
Reference in new issue
Block a user