#14804: Address review comments on segment placement, ISEG gRPC, min/max validation

This commit is contained in:
Magne Sjaastad committed 2026-10-12 19:12:08 +02:00
1 parent d8f346e9ab
commit 97d132685b
8 files changed
+49 -16

No files matched your search

+1 -1
View File
@@ -111,7 +111,6 @@
<file>Parallel.svg</file>
<file>PerforationInterval16x16.png</file>
<file>PerforationIntervals16x16.png</file>
<file>Segment.svg</file>
<file>Perspective.svg</file>
<file>PlotWindow.svg</file>
<file>Plus.png</file>
@@ -134,6 +133,7 @@
<file>RulerPoly.svg</file>
<file>Save.svg</file>
<file>SaveAs.svg</file>
<file>Segment.svg</file>
<file>SnapShot.svg</file>
<file>SnapShotSave.svg</file>
<file>SnapShotSaveViews.svg</file>
@@ -199,7 +199,7 @@ std::optional<RigMswCellIntersection>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double segmentMidpointMD( const std::vector<CellSegmentEntry>& cellSegMap, int segmentNumber )
double segmentNodeMD( const std::vector<CellSegmentEntry>& cellSegMap, int segmentNumber )
{
for ( const auto& entry : cellSegMap )
{
@@ -487,7 +487,8 @@ RigMswBranch buildMainBoreBranch( const RimWellPath*
std::vector<double> nodes = RicMswTableDataTools::placeSegmentNodes( heelMD,
candidateNodes,
segmentationSettings.intervals,
cellPieces.empty() ? heelMD : cellPieces.back().second );
cellPieces.empty() ? heelMD : cellPieces.back().second,
cellPieces.empty() ? heelMD : cellPieces.front().first );
if ( !cellPieces.empty() && !perforationIntervals.empty() &&
( segmentationSettings.singleSegmentBeforeFirstPerforation || segmentationSettings.singleSegmentAfterLastPerforation ) )
@@ -496,6 +497,7 @@ RigMswBranch buildMainBoreBranch( const RimWellPath*
double lastPerforationMD = -std::numeric_limits<double>::infinity();
for ( const auto* perf : perforationIntervals )
{
if ( exportDate && !perf->isActiveOnDate( *exportDate ) ) continue;
firstPerforationMD = std::min( firstPerforationMD, perf->startMD() );
lastPerforationMD = std::max( lastPerforationMD, perf->endMD() );
}
@@ -686,7 +688,7 @@ std::vector<RigMswBranch> buildValveBranches( const RimWellPath*
{
const int cellBranch = ++branchNumber;
const int outletSeg = findContainingSegmentForMD( cellSegMap, entry.ci.distanceStart );
const double valveMD = segmentMidpointMD( cellSegMap, outletSeg );
const double valveMD = segmentNodeMD( cellSegMap, outletSeg );
const double valveEndMD = valveMD + RicMswTableDataTools::valveSegmentLength;
const double startTVD = RicMswTableDataTools::tvdFromMeasuredDepth( wellPath, valveMD );
const double endTVD = RicMswTableDataTools::tvdFromMeasuredDepth( wellPath, valveEndMD );
@@ -770,7 +772,7 @@ std::vector<RigMswBranch> buildValveBranches( const RimWellPath*
{
const int cellBranch = ++branchNumber;
const int outletSeg = findContainingSegmentForMD( cellSegMap, entry.ci.distanceStart );
const double valveMD = segmentMidpointMD( cellSegMap, outletSeg );
const double valveMD = segmentNodeMD( cellSegMap, outletSeg );
const double valveEndMD = valveMD + RicMswTableDataTools::valveSegmentLength;
const double startTVD = RicMswTableDataTools::tvdFromMeasuredDepth( wellPath, valveMD );
const double endTVD = RicMswTableDataTools::tvdFromMeasuredDepth( wellPath, valveEndMD );
@@ -188,7 +188,8 @@ const RicMswTableDataTools::SegmentationInterval* intervalAtMD( const std::vecto
std::vector<double> RicMswTableDataTools::placeSegmentNodes( double outletMD,
const std::vector<double>& allCandidateNodes,
const std::vector<SegmentationInterval>& intervals,
double lastMD )
double lastMD,
double firstMD )
{
if ( intervals.empty() ) return allCandidateNodes;
@@ -209,7 +210,7 @@ std::vector<double> RicMswTableDataTools::placeSegmentNodes( double
const double endMD = std::min( interval.endMD, lastMD );
for ( int k = 0;; ++k )
{
const double segmentStart = std::max( interval.startMD + k * length, outletMD );
const double segmentStart = std::max( { interval.startMD + k * length, outletMD, firstMD } );
const double segmentEnd = std::min( interval.startMD + ( k + 1 ) * length, endMD );
if ( interval.startMD + k * length >= endMD - tolerance ) break;
if ( segmentEnd - segmentStart > tolerance ) candidateNodes.push_back( 0.5 * ( segmentStart + segmentEnd ) );
@@ -260,15 +261,16 @@ std::vector<double> RicMswTableDataTools::placeSegmentNodes( double
const auto* interval = intervalAtMD( intervals, nodeMD );
if ( interval && interval->maxLength.has_value() )
{
const double maxLength = *interval->maxLength;
const double gap = nodeMD - previousMD;
const double maxLength = *interval->maxLength;
const double splitStart = std::max( previousMD, interval->startMD );
const double gap = nodeMD - splitStart;
if ( gap > maxLength + tolerance )
{
const int segmentCount = static_cast<int>( std::ceil( ( gap - tolerance ) / maxLength ) );
const double spacing = gap / segmentCount;
for ( int k = 1; k < segmentCount; ++k )
{
nodes.push_back( previousMD + k * spacing );
nodes.push_back( splitStart + k * spacing );
}
}
}
@@ -71,15 +71,16 @@ SegmentationSettings segmentationSettings( const RimSegmentCollection* segmentCo
//--------------------------------------------------------------------------------------------------
/// Place the segment nodes of a branch. Candidate nodes are the cell (piece) centres in MD order.
/// Inside a fixed length interval, the candidates are replaced by nodes at the centre of segments of
/// the fixed length, starting at the interval start and limited to [outletMD, lastMD]. Inside a min
/// length interval, candidates closer than the min length to the previous node are dropped. Inside a
/// max length interval, evenly spaced nodes are inserted until no spacing exceeds the max length.
/// The spacing of the first node is measured from the outlet node.
/// the fixed length, starting at the interval start and limited to [max(outletMD, firstMD), lastMD].
/// Inside a min length interval, candidates closer than the min length to the previous node are
/// dropped. Inside a max length interval, evenly spaced nodes are inserted until no spacing exceeds
/// the max length; the spacing is measured from the previous node, but never from before the interval start.
//--------------------------------------------------------------------------------------------------
std::vector<double> placeSegmentNodes( double outletMD,
const std::vector<double>& candidateNodes,
const std::vector<SegmentationInterval>& intervals,
double lastMD = std::numeric_limits<double>::infinity() );
double lastMD = std::numeric_limits<double>::infinity(),
double firstMD = -std::numeric_limits<double>::infinity() );
//--------------------------------------------------------------------------------------------------
/// Replace the nodes in [regionStartMD, firstPerforationMD) and/or (lastPerforationMD, regionEndMD]
@@ -393,7 +393,6 @@ void RimSegmentInterval::fieldChangedByUi( const caf::PdmFieldHandle* changedFie
if ( changedField == &m_fixedSegmentLength || changedField == &m_minSegmentLength || changedField == &m_maxSegmentLength )
{
updateUiName();
uiCapability()->updateConnectedEditors();
}
updateConnectedEditors();
@@ -479,6 +478,15 @@ void RimSegmentInterval::enforceSegmentationRules( const caf::PdmFieldHandle* ac
else
{
m_fixedSegmentLength = std::make_pair( false, m_fixedSegmentLength().second );
// Min length must not exceed max length, the field just edited wins
if ( m_minSegmentLength().first && m_maxSegmentLength().first && m_minSegmentLength().second > m_maxSegmentLength().second )
{
if ( activeField == &m_minSegmentLength )
m_maxSegmentLength = std::make_pair( true, m_minSegmentLength().second );
else
m_minSegmentLength = std::make_pair( true, m_maxSegmentLength().second );
}
}
}
@@ -235,6 +235,20 @@ TEST( RicMswBranchBuilder, PlaceSegmentNodes_FixedLength )
RicMswTableDataTools::placeSegmentNodes( 0.0, centres( exampleCells ), { { 0.0, 50.0, std::nullopt, std::nullopt, 20.0 } }, 45.0 ) );
}
TEST( RicMswBranchBuilder, PlaceSegmentNodes_MaxLengthNotBeforeIntervalStart )
{
// Heel at 0, interval [1000,1100], first candidate at 1050: no nodes are added before the interval
const auto nodes = RicMswTableDataTools::placeSegmentNodes( 0.0, { 1050.0 }, { { 1000.0, 1100.0, std::nullopt, 25.0 } } );
expectNodes( { 1025.0, 1050.0 }, nodes );
}
TEST( RicMswBranchBuilder, PlaceSegmentNodes_FixedLengthNotBeforeFirstCell )
{
const auto nodes =
RicMswTableDataTools::placeSegmentNodes( 0.0, { 1050.0 }, { { 1000.0, 1100.0, std::nullopt, std::nullopt, 20.0 } }, 1100.0, 1040.0 );
expectNodes( { 1050.0, 1070.0, 1090.0 }, nodes );
}
TEST( RicMswBranchBuilder, CollapseNodesOutsidePerforations )
{
const std::vector<double> nodes = { 5.0, 12.0, 22.0, 31.5, 46.5, 55.0 };
@@ -94,6 +94,7 @@ message SimulatorCompsegsEntry {
double distance_start = 5;
double distance_end = 6;
optional string grid_name = 7;
optional int32 segment_number = 8;
}
message SimulatorWsegvalvEntry {
@@ -193,6 +193,11 @@ void RiaWellPathDataToGrpcConverter::copyCompsegsToGrpc( const RigMswTableData&
{
grpcCompData->set_grid_name( compsegsRow.gridName );
}
if ( compsegsRow.segmentNumber.has_value() )
{
grpcCompData->set_segment_number( *compsegsRow.segmentNumber );
}
}
}