#11109 Improve visualization of MSW with valve branches

Increase default segment threshold to 4
Add an optional setting to override the default value
Use this threshold to merge short branches into parent branch
This commit is contained in:
Magne Sjaastad 2024-01-25 18:17:10 +01:00
parent 85672f5ef5
commit 7d601ac067
11 changed files with 87 additions and 39 deletions

View File

@ -166,23 +166,7 @@ void RivSimWellPipesPartMgr::buildWellPipeParts( const caf::DisplayCoordTransfor
m_wellBranches.clear(); m_wellBranches.clear();
m_flattenedBranchWellHeadOffsets.clear(); m_flattenedBranchWellHeadOffsets.clear();
auto createSimWells = []( RimSimWellInView* simWellInView ) -> std::vector<SimulationWellCellBranch> auto simWells = m_simWellInView->wellBranchesForVisualization();
{
std::vector<SimulationWellCellBranch> 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 ); const auto& [coords, wellCells] = RigSimulationWellCenterLineCalculator::extractBranchData( simWells );
auto pipeBranchesCLCoords = coords; auto pipeBranchesCLCoords = coords;

View File

@ -23,6 +23,7 @@
#include "RigEclipseCaseData.h" #include "RigEclipseCaseData.h"
#include "RigMainGrid.h" #include "RigMainGrid.h"
#include "RigSimulationWellCenterLineCalculator.h"
#include "RigWellPath.h" #include "RigWellPath.h"
#include "Rim2dIntersectionView.h" #include "Rim2dIntersectionView.h"
@ -868,11 +869,10 @@ void RimExtrudedCurveIntersection::updateSimulationWellCenterline() const
{ {
if ( m_simulationWellBranchCenterlines.empty() ) if ( m_simulationWellBranchCenterlines.empty() )
{ {
auto branches = m_simulationWell->wellPipeBranches(); auto simWells = m_simulationWell()->wellBranchesForVisualization();
for ( const auto& branch : branches ) const auto& [coords, wellCells] = RigSimulationWellCenterLineCalculator::extractBranchData( simWells );
{
m_simulationWellBranchCenterlines.push_back( branch->wellPathPoints() ); m_simulationWellBranchCenterlines = coords;
}
} }
} }
else else

View File

@ -209,4 +209,4 @@ private:
caf::PdmField<bool> m_kFilterCollectionOverride; caf::PdmField<bool> m_kFilterCollectionOverride;
caf::PdmField<QString> m_kFilterCollectionText; caf::PdmField<QString> m_kFilterCollectionText;
}; };

View File

@ -49,12 +49,14 @@
#include "RimEclipseInputPropertyCollection.h" #include "RimEclipseInputPropertyCollection.h"
#include "RimEclipseView.h" #include "RimEclipseView.h"
#include "RimFlowDiagSolution.h" #include "RimFlowDiagSolution.h"
#include "RimIntersectionCollection.h"
#include "RimMockModelSettings.h" #include "RimMockModelSettings.h"
#include "RimProject.h" #include "RimProject.h"
#include "RimReservoirCellResultsStorage.h" #include "RimReservoirCellResultsStorage.h"
#include "RimTimeStepFilter.h" #include "RimTimeStepFilter.h"
#include "RimTools.h" #include "RimTools.h"
#include "cafPdmUiCheckBoxAndTextEditor.h"
#include "cafPdmUiFilePathEditor.h" #include "cafPdmUiFilePathEditor.h"
#include "cafPdmUiPropertyViewDialog.h" #include "cafPdmUiPropertyViewDialog.h"
#include "cafProgressInfo.h" #include "cafProgressInfo.h"
@ -102,6 +104,9 @@ RimEclipseResultCase::RimEclipseResultCase()
#ifndef USE_HDF5 #ifndef USE_HDF5
m_sourSimFileName.uiCapability()->setUiHidden( true ); m_sourSimFileName.uiCapability()->setUiHidden( true );
#endif #endif
CAF_PDM_InitField( &m_mswMergeThreshold, "MswMergeThreshold", std::make_pair( false, 3 ), "MSW Short Well Merge Threshold" );
m_mswMergeThreshold.uiCapability()->setUiEditorTypeName( caf::PdmUiCheckBoxAndTextEditor::uiEditorTypeName() );
} }
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -561,6 +566,21 @@ RifReaderRftInterface* RimEclipseResultCase::rftReader()
return m_readerEclipseRft.p(); return m_readerEclipseRft.p();
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
int RimEclipseResultCase::mswMergeThreshold() const
{
// This value is used in RigMswCenterLineCalculator::calculateMswWellPipeGeometry
if ( m_mswMergeThreshold().first )
{
return m_mswMergeThreshold().second;
}
return 4;
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
@ -607,6 +627,7 @@ void RimEclipseResultCase::defineUiOrdering( QString uiConfigName, caf::PdmUiOrd
group->add( &m_activeFormationNames ); group->add( &m_activeFormationNames );
group->add( &m_flipXAxis ); group->add( &m_flipXAxis );
group->add( &m_flipYAxis ); group->add( &m_flipYAxis );
group->add( &m_mswMergeThreshold );
if ( eclipseCaseData() && eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL ) && if ( eclipseCaseData() && eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL ) &&
eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->maxTimeStepCount() > 0 ) eclipseCaseData()->results( RiaDefines::PorosityModelType::MATRIX_MODEL )->maxTimeStepCount() > 0 )
@ -627,6 +648,16 @@ void RimEclipseResultCase::fieldChangedByUi( const caf::PdmFieldHandle* changedF
loadAndUpdateSourSimData(); loadAndUpdateSourSimData();
} }
if ( changedField == &m_mswMergeThreshold )
{
for ( auto resView : reservoirViews() )
{
resView->scheduleSimWellGeometryRegen();
resView->scheduleCreateDisplayModelAndRedraw();
resView->intersectionCollection()->recomputeSimWellBranchData();
}
}
return RimEclipseCase::fieldChangedByUi( changedField, oldValue, newValue ); return RimEclipseCase::fieldChangedByUi( changedField, oldValue, newValue );
} }

View File

@ -73,6 +73,10 @@ public:
RifReaderRftInterface* rftReader(); RifReaderRftInterface* rftReader();
// A multi segment well can have multiple well paths. Valves can be modeled using short branches. This threshold defines the limit for
// merging branches into the upstream branch.
int mswMergeThreshold() const;
protected: protected:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override; void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override; void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
@ -95,6 +99,8 @@ private:
caf::PdmChildArrayField<RimFlowDiagSolution*> m_flowDiagSolutions; caf::PdmChildArrayField<RimFlowDiagSolution*> m_flowDiagSolutions;
caf::PdmField<caf::FilePath> m_sourSimFileName; caf::PdmField<caf::FilePath> m_sourSimFileName;
caf::PdmField<std::pair<bool, int>> m_mswMergeThreshold;
bool m_gridAndWellDataIsReadFromFile; bool m_gridAndWellDataIsReadFromFile;
bool m_activeCellInfoIsReadFromFile; bool m_activeCellInfoIsReadFromFile;
bool m_useOpmRftReader; bool m_useOpmRftReader;

View File

@ -26,6 +26,7 @@
#include "RigCell.h" #include "RigCell.h"
#include "RigEclipseCaseData.h" #include "RigEclipseCaseData.h"
#include "RigMainGrid.h" #include "RigMainGrid.h"
#include "RigMswCenterLineCalculator.h"
#include "RigSimWellData.h" #include "RigSimWellData.h"
#include "RigSimulationWellCenterLineCalculator.h" #include "RigSimulationWellCenterLineCalculator.h"
#include "RigWellResultFrame.h" #include "RigWellResultFrame.h"
@ -188,6 +189,21 @@ std::vector<const RigWellPath*> RimSimWellInView::wellPipeBranches() const
return std::vector<const RigWellPath*>(); return std::vector<const RigWellPath*>();
} }
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<SimulationWellCellBranch> RimSimWellInView::wellBranchesForVisualization() const
{
const RigSimWellData* simWellData = this->simWellData();
if ( simWellData && simWellData->isMultiSegmentWell() )
{
return RigMswCenterLineCalculator::calculateMswWellPipeGeometry( this );
}
return RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( this );
}
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// frameIndex = -1 will use the static well frame /// frameIndex = -1 will use the static well frame
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------

View File

@ -23,6 +23,7 @@
#include "Rim3dPropertiesInterface.h" #include "Rim3dPropertiesInterface.h"
#include "RigWellDiskData.h" #include "RigWellDiskData.h"
#include "RigWellResultBranch.h"
#include "cafAppEnum.h" #include "cafAppEnum.h"
#include "cafPdmChildField.h" #include "cafPdmChildField.h"
@ -76,6 +77,8 @@ public:
std::vector<const RigWellPath*> wellPipeBranches() const; std::vector<const RigWellPath*> wellPipeBranches() const;
std::vector<SimulationWellCellBranch> wellBranchesForVisualization() const;
void wellHeadTopBottomPosition( int frameIndex, cvf::Vec3d* top, cvf::Vec3d* bottom ); void wellHeadTopBottomPosition( int frameIndex, cvf::Vec3d* top, cvf::Vec3d* bottom );
double pipeRadius(); double pipeRadius();
int pipeCrossSectionVertexCount(); int pipeCrossSectionVertexCount();

View File

@ -28,6 +28,7 @@
#include "RigWellResultFrame.h" #include "RigWellResultFrame.h"
#include "RimEclipseCase.h" #include "RimEclipseCase.h"
#include "RimEclipseResultCase.h"
#include "RimEclipseView.h" #include "RimEclipseView.h"
#include "RimSimWellInView.h" #include "RimSimWellInView.h"
#include "RimSimWellInViewCollection.h" #include "RimSimWellInViewCollection.h"
@ -37,7 +38,7 @@
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::vector<SimulationWellCellBranch> RigMswCenterLineCalculator::calculateMswWellPipeGeometry( RimSimWellInView* rimWell ) std::vector<SimulationWellCellBranch> RigMswCenterLineCalculator::calculateMswWellPipeGeometry( const RimSimWellInView* rimWell )
{ {
CVF_ASSERT( rimWell ); CVF_ASSERT( rimWell );
@ -50,7 +51,13 @@ std::vector<SimulationWellCellBranch> RigMswCenterLineCalculator::calculateMswWe
auto eclipseCaseData = eclipseView->eclipseCase()->eclipseCaseData(); auto eclipseCaseData = eclipseView->eclipseCase()->eclipseCaseData();
int timeStepIndex = eclipseView->currentTimeStep(); int timeStepIndex = eclipseView->currentTimeStep();
return calculateMswWellPipeGeometryForTimeStep( eclipseCaseData, simWellData, timeStepIndex ); int shortBranchMergeThreshold = 4;
if ( auto eclipseResultCase = dynamic_cast<RimEclipseResultCase*>( eclipseView->eclipseCase() ) )
{
shortBranchMergeThreshold = eclipseResultCase->mswMergeThreshold();
}
return calculateMswWellPipeGeometryForTimeStep( eclipseCaseData, simWellData, timeStepIndex, shortBranchMergeThreshold );
} }
return {}; return {};
@ -62,10 +69,9 @@ std::vector<SimulationWellCellBranch> RigMswCenterLineCalculator::calculateMswWe
std::vector<SimulationWellCellBranch> std::vector<SimulationWellCellBranch>
RigMswCenterLineCalculator::calculateMswWellPipeGeometryForTimeStep( const RigEclipseCaseData* eclipseCaseData, RigMswCenterLineCalculator::calculateMswWellPipeGeometryForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* wellResults, const RigSimWellData* wellResults,
int timeStepIndex ) int timeStepIndex,
int shortBranchMergeThreshold )
{ {
if ( timeStepIndex >= 0 && !wellResults->hasAnyValidCells( timeStepIndex ) ) return {};
const RigWellResultFrame* wellFramePtr = nullptr; const RigWellResultFrame* wellFramePtr = nullptr;
if ( timeStepIndex < 0 ) if ( timeStepIndex < 0 )
@ -80,7 +86,7 @@ std::vector<SimulationWellCellBranch>
const RigWellResultFrame& wellFrame = *wellFramePtr; const RigWellResultFrame& wellFrame = *wellFramePtr;
const std::vector<RigWellResultBranch> resultBranches = wellFrame.wellResultBranches(); const std::vector<RigWellResultBranch> resultBranches = wellFrame.wellResultBranches();
std::vector<WellBranch> wellBranches = mergeShortBranchesIntoLongBranches( resultBranches ); std::vector<WellBranch> wellBranches = mergeShortBranchesIntoLongBranches( resultBranches, shortBranchMergeThreshold );
// Connect outlet segment of branches to parent branch // Connect outlet segment of branches to parent branch
@ -290,7 +296,8 @@ SimulationWellCellBranch
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::vector<RigMswCenterLineCalculator::WellBranch> std::vector<RigMswCenterLineCalculator::WellBranch>
RigMswCenterLineCalculator::mergeShortBranchesIntoLongBranches( const std::vector<RigWellResultBranch>& resBranches ) RigMswCenterLineCalculator::mergeShortBranchesIntoLongBranches( const std::vector<RigWellResultBranch>& resBranches,
int shortBranchMergeThreshold )
{ {
std::vector<WellBranch> longWellBranches; std::vector<WellBranch> longWellBranches;
std::vector<WellBranch> shortWellBranches; std::vector<WellBranch> shortWellBranches;
@ -314,8 +321,7 @@ std::vector<RigMswCenterLineCalculator::WellBranch>
} }
} }
const int resultPointThreshold = 3; if ( static_cast<int>( resultBranch.branchResultPoints().size() ) > shortBranchMergeThreshold )
if ( resultBranch.branchResultPoints().size() > resultPointThreshold )
{ {
longWellBranches.push_back( branch ); longWellBranches.push_back( branch );
} }

View File

@ -35,7 +35,7 @@ class RigSimWellData;
class RigMswCenterLineCalculator class RigMswCenterLineCalculator
{ {
public: public:
static std::vector<SimulationWellCellBranch> calculateMswWellPipeGeometry( RimSimWellInView* rimWell ); static std::vector<SimulationWellCellBranch> calculateMswWellPipeGeometry( const RimSimWellInView* rimWell );
private: private:
struct OutputSegment struct OutputSegment
@ -69,11 +69,13 @@ private:
private: private:
static std::vector<SimulationWellCellBranch> calculateMswWellPipeGeometryForTimeStep( const RigEclipseCaseData* eclipseCaseData, static std::vector<SimulationWellCellBranch> calculateMswWellPipeGeometryForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* simWellData, const RigSimWellData* simWellData,
int timeStepIndex ); int timeStepIndex,
int shortBranchMergeThreshold );
static SimulationWellCellBranch addCoordsAtCellFaceIntersectionsAndCreateBranch( const std::vector<cvf::Vec3d> branchCoords, static SimulationWellCellBranch addCoordsAtCellFaceIntersectionsAndCreateBranch( const std::vector<cvf::Vec3d> branchCoords,
const std::vector<RigWellResultPoint>& resultPoints, const std::vector<RigWellResultPoint>& resultPoints,
const RigEclipseCaseData* eclipseCaseData ); const RigEclipseCaseData* eclipseCaseData );
static std::vector<WellBranch> mergeShortBranchesIntoLongBranches( const std::vector<RigWellResultBranch>& resBranches ); static std::vector<WellBranch> mergeShortBranchesIntoLongBranches( const std::vector<RigWellResultBranch>& resBranches,
int shortBranchMergeThreshold );
}; };

View File

@ -43,7 +43,7 @@
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
/// ///
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
std::vector<SimulationWellCellBranch> RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( RimSimWellInView* rimWell ) std::vector<SimulationWellCellBranch> RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( const RimSimWellInView* rimWell )
{ {
std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords; std::vector<std::vector<cvf::Vec3d>> pipeBranchesCLCoords;
std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds; std::vector<std::vector<RigWellResultPoint>> pipeBranchesCellIds;
@ -118,7 +118,7 @@ std::pair<std::vector<std::vector<cvf::Vec3d>>, std::vector<std::vector<RigWellR
/// The returned CellIds is one less than the number of centerline points, /// 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 /// and are describing the lines between the points, starting with the first line
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
void RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( RimSimWellInView* rimWell, void RigSimulationWellCenterLineCalculator::calculateWellPipeStaticCenterline( const RimSimWellInView* rimWell,
std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords, std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds ) std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds )
{ {

View File

@ -37,7 +37,7 @@ class RigWellResultFrame;
class RigSimulationWellCenterLineCalculator class RigSimulationWellCenterLineCalculator
{ {
public: public:
static std::vector<SimulationWellCellBranch> calculateWellPipeStaticCenterline( RimSimWellInView* rimWell ); static std::vector<SimulationWellCellBranch> calculateWellPipeStaticCenterline( const RimSimWellInView* rimWell );
static std::vector<SimulationWellCellBranch> calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData, static std::vector<SimulationWellCellBranch> calculateWellPipeCenterlineForTimeStep( const RigEclipseCaseData* eclipseCaseData,
const RigSimWellData* simWellData, const RigSimWellData* simWellData,
@ -49,7 +49,7 @@ public:
extractBranchData( const std::vector<SimulationWellCellBranch> simulationBranch ); extractBranchData( const std::vector<SimulationWellCellBranch> simulationBranch );
private: private:
static void calculateWellPipeStaticCenterline( RimSimWellInView* rimWell, static void calculateWellPipeStaticCenterline( const RimSimWellInView* rimWell,
std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords, std::vector<std::vector<cvf::Vec3d>>& pipeBranchesCLCoords,
std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds ); std::vector<std::vector<RigWellResultPoint>>& pipeBranchesCellIds );