#12718 Add diameter and roughness specification for MD intervals

Implements interval-based diameter and roughness configuration for MSW completions
while maintaining backward compatibility with existing single-value approach.

- Add RimDiameterRoughnessInterval class for individual MD intervals
- Add RimDiameterRoughnessIntervalCollection for managing interval collections
- Extend RimMswCompletionParameters with interval-specific mode support
- Support both metric and field unit systems
- Provide validation and overlap detection for intervals
This commit is contained in:
Kristian Bendiksen authored and Magne Sjaastad committed 2025-08-21 08:48:43 +02:00
1 parent 79c2c792f4
commit b0483172b1
18 files changed
+1742 -16

No files matched your search

@@ -13,6 +13,8 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RicNewStimPlanModelPlotFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicImportEnsembleFractureStatisticsFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicImportValveTemplatesFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicNewDiameterRoughnessIntervalFeature.h
${CMAKE_CURRENT_LIST_DIR}/RicDeleteDiameterRoughnessIntervalFeature.h
)
set(SOURCE_GROUP_SOURCE_FILES
@@ -30,6 +32,8 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RicNewStimPlanModelPlotFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicImportEnsembleFractureStatisticsFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicImportValveTemplatesFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicNewDiameterRoughnessIntervalFeature.cpp
${CMAKE_CURRENT_LIST_DIR}/RicDeleteDiameterRoughnessIntervalFeature.cpp
)
list(APPEND COMMAND_CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
@@ -0,0 +1,168 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicDeleteDiameterRoughnessIntervalFeature.h"
#include "RimDiameterRoughnessInterval.h"
#include "RimDiameterRoughnessIntervalCollection.h"
#include "RimMswCompletionParameters.h"
#include "RimProject.h"
#include "RimWellPath.h"
#include "RimWellPathCompletionSettings.h"
#include "Riu3DMainWindowTools.h"
#include "cafSelectionManager.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicDeleteDiameterRoughnessIntervalFeature, "RicDeleteDiameterRoughnessIntervalFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicDeleteDiameterRoughnessIntervalFeature::isCommandEnabled() const
{
if ( caf::SelectionManager::instance()->selectedItemOfType<RimDiameterRoughnessInterval>( caf::SelectionManager::FIRST_LEVEL ) )
{
return true;
}
if ( auto collection = caf::SelectionManager::instance()->selectedItemOfType<RimDiameterRoughnessIntervalCollection>() )
{
return collection && !collection->intervals().empty();
}
if ( auto mswParams = caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>() )
{
if ( mswParams->diameterRoughnessIntervals() )
{
return !mswParams->diameterRoughnessIntervals()->intervals().empty();
}
}
if ( auto completionSettings = caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() )
{
if ( auto wellPath = completionSettings->firstAncestorOrThisOfType<RimWellPath>() )
{
auto mswParams = wellPath->mswCompletionParameters();
if ( mswParams && mswParams->diameterRoughnessIntervals() )
{
return !mswParams->diameterRoughnessIntervals()->intervals().empty();
}
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicDeleteDiameterRoughnessIntervalFeature::onActionTriggered( bool isChecked )
{
const auto intervals = caf::SelectionManager::instance()->objectsByType<RimDiameterRoughnessInterval>( caf::SelectionManager::FIRST_LEVEL );
RimDiameterRoughnessIntervalCollection* intervalCollection = nullptr;
if ( !intervals.empty() )
{
// Delete selected intervals
intervalCollection = intervals[0]->firstAncestorOrThisOfTypeAsserted<RimDiameterRoughnessIntervalCollection>();
for ( RimDiameterRoughnessInterval* intervalToDelete : intervals )
{
intervalCollection->removeInterval( intervalToDelete );
}
intervalCollection->updateConnectedEditors();
}
else
{
// Delete all intervals in collection
intervalCollection = caf::SelectionManager::instance()->selectedItemOfType<RimDiameterRoughnessIntervalCollection>();
if ( !intervalCollection )
{
// Handle selection of MSW completion parameters
auto mswParams = caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>();
if ( mswParams && mswParams->diameterRoughnessIntervals() )
{
intervalCollection = mswParams->diameterRoughnessIntervals();
}
else
{
// Handle selection of well path completion settings
if ( auto completionSettings = caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() )
{
if ( auto wellPath = completionSettings->firstAncestorOrThisOfType<RimWellPath>() )
{
auto mswParams = wellPath->mswCompletionParameters();
if ( mswParams && mswParams->diameterRoughnessIntervals() )
{
intervalCollection = mswParams->diameterRoughnessIntervals();
}
}
}
}
}
if ( intervalCollection )
{
intervalCollection->removeAllIntervals();
intervalCollection->updateConnectedEditors();
}
}
if ( intervalCollection )
{
if ( intervalCollection->intervals().empty() )
{
Riu3DMainWindowTools::selectAsCurrentItem( intervalCollection );
}
if ( RimProject* proj = RimProject::current() )
{
proj->scheduleCreateDisplayModelAndRedrawAllViews();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicDeleteDiameterRoughnessIntervalFeature::setupActionLook( QAction* actionToSetup )
{
const auto intervals = caf::SelectionManager::instance()->objectsByType<RimDiameterRoughnessInterval>( caf::SelectionManager::FIRST_LEVEL );
if ( !intervals.empty() )
{
if ( intervals.size() == 1 )
{
actionToSetup->setText( "Delete Interval" );
}
else
{
actionToSetup->setText( QString( "Delete %1 Intervals" ).arg( intervals.size() ) );
}
actionToSetup->setIcon( QIcon( ":/Erase.svg" ) );
applyShortcutWithHintToAction( actionToSetup, QKeySequence::Delete );
}
else if ( caf::SelectionManager::instance()->selectedItemOfType<RimDiameterRoughnessIntervalCollection>() ||
caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>() ||
caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() )
{
actionToSetup->setText( "Delete All Intervals" );
actionToSetup->setIcon( QIcon( ":/Erase.svg" ) );
applyShortcutWithHintToAction( actionToSetup, QKeySequence::Delete );
}
}
@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicDeleteDiameterRoughnessIntervalFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};
@@ -0,0 +1,112 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicNewDiameterRoughnessIntervalFeature.h"
#include "RimDiameterRoughnessInterval.h"
#include "RimDiameterRoughnessIntervalCollection.h"
#include "RimMswCompletionParameters.h"
#include "RimProject.h"
#include "RimWellPath.h"
#include "RimWellPathCompletionSettings.h"
#include "Riu3DMainWindowTools.h"
#include "cafSelectionManager.h"
#include <QAction>
CAF_CMD_SOURCE_INIT( RicNewDiameterRoughnessIntervalFeature, "RicNewDiameterRoughnessIntervalFeature" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RicNewDiameterRoughnessIntervalFeature::isCommandEnabled() const
{
return ( caf::SelectionManager::instance()->selectedItemOfType<RimDiameterRoughnessIntervalCollection>() ||
caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>() ||
caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewDiameterRoughnessIntervalFeature::onActionTriggered( bool isChecked )
{
// Try to get collection directly
RimDiameterRoughnessIntervalCollection* intervalCollection =
caf::SelectionManager::instance()->selectedItemOfType<RimDiameterRoughnessIntervalCollection>();
// If not found, try to get it from MSW completion parameters
if ( !intervalCollection )
{
if ( auto mswParams = caf::SelectionManager::instance()->selectedItemOfType<RimMswCompletionParameters>() )
{
intervalCollection = mswParams->diameterRoughnessIntervals();
}
}
// If still not found, try to get it from well path completion settings
if ( !intervalCollection )
{
if ( auto completionSettings = caf::SelectionManager::instance()->selectedItemOfType<RimWellPathCompletionSettings>() )
{
if ( auto wellPath = completionSettings->firstAncestorOrThisOfType<RimWellPath>() )
{
if ( auto mswParams = wellPath->mswCompletionParameters() )
{
intervalCollection = mswParams->diameterRoughnessIntervals();
}
}
}
}
if ( intervalCollection )
{
RimDiameterRoughnessInterval* newInterval = new RimDiameterRoughnessInterval;
// Set default values
if ( auto wellPath = intervalCollection->firstAncestorOrThisOfType<RimWellPath>() )
{
if ( auto mswParams = wellPath->mswCompletionParameters() )
{
newInterval->setStartMD( 0 );
newInterval->setEndMD( 2000 );
newInterval->setDiameter( mswParams->linerDiameter() );
newInterval->setRoughnessFactor( mswParams->roughnessFactor() );
}
}
intervalCollection->addInterval( newInterval );
intervalCollection->updateConnectedEditors();
Riu3DMainWindowTools::selectAsCurrentItem( newInterval );
if ( RimProject* project = RimProject::current() )
{
project->scheduleCreateDisplayModelAndRedrawAllViews();
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicNewDiameterRoughnessIntervalFeature::setupActionLook( QAction* actionToSetup )
{
actionToSetup->setText( "New Interval" );
}
@@ -0,0 +1,34 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafCmdFeature.h"
//==================================================================================================
///
//==================================================================================================
class RicNewDiameterRoughnessIntervalFeature : public caf::CmdFeature
{
CAF_CMD_HEADER_INIT;
protected:
bool isCommandEnabled() const override;
void onActionTriggered( bool isChecked ) override;
void setupActionLook( QAction* actionToSetup ) override;
};
@@ -736,9 +736,6 @@ void RicMswTableFormatterTools::writeWelsegsSegment( RicMswSegment*
prevOutTVD = previousSegment->outputTVD();
}
const auto linerDiameter = branch->wellPath()->mswCompletionParameters()->linerDiameter( exportInfo.unitSystem() );
const auto roughnessFactor = branch->wellPath()->mswCompletionParameters()->roughnessFactor( exportInfo.unitSystem() );
auto outletSegment = previousSegment;
for ( const auto& [subStartMD, subEndMD] : segments )
{
@@ -770,6 +767,9 @@ void RicMswTableFormatterTools::writeWelsegsSegment( RicMswSegment*
segment->setOutputTVD( midPointTVD );
segment->setSegmentNumber( *segmentNumber );
const auto linerDiameter = branch->wellPath()->mswCompletionParameters()->getDiameterAtMD( midPointMD, exportInfo.unitSystem() );
const auto roughnessFactor = branch->wellPath()->mswCompletionParameters()->getRoughnessAtMD( midPointMD, exportInfo.unitSystem() );
formatter.add( *segmentNumber ).add( *segmentNumber );
formatter.add( branch->branchNumber() );
if ( outletSegment )
@@ -32,6 +32,8 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimWellPathValve.h
${CMAKE_CURRENT_LIST_DIR}/RimMultipleValveLocations.h
${CMAKE_CURRENT_LIST_DIR}/RimWellPathAicdParameters.h
${CMAKE_CURRENT_LIST_DIR}/RimDiameterRoughnessInterval.h
${CMAKE_CURRENT_LIST_DIR}/RimDiameterRoughnessIntervalCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFractureStatistics.h
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFractureStatisticsCollection.h
)
@@ -67,6 +69,8 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimWellPathValve.cpp
${CMAKE_CURRENT_LIST_DIR}/RimMultipleValveLocations.cpp
${CMAKE_CURRENT_LIST_DIR}/RimWellPathAicdParameters.cpp
${CMAKE_CURRENT_LIST_DIR}/RimDiameterRoughnessInterval.cpp
${CMAKE_CURRENT_LIST_DIR}/RimDiameterRoughnessIntervalCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFractureStatistics.cpp
${CMAKE_CURRENT_LIST_DIR}/RimEnsembleFractureStatisticsCollection.cpp
)
@@ -0,0 +1,344 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimDiameterRoughnessInterval.h"
#include "RiaApplication.h"
#include "RiaEclipseUnitTools.h"
#include "RiaLogging.h"
#include "RimDiameterRoughnessIntervalCollection.h"
#include "RimMswCompletionParameters.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmObjectScriptingCapability.h"
#include "cafPdmUiDoubleSliderEditor.h"
#include "cafPdmUiDoubleValueEditor.h"
#include <cmath>
CAF_PDM_SOURCE_INIT( RimDiameterRoughnessInterval, "DiameterRoughnessInterval" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDiameterRoughnessInterval::RimDiameterRoughnessInterval()
{
CAF_PDM_InitScriptableObject( "Diameter Roughness Interval", ":/WellPathComponent16x16.png", "", "DiameterRoughnessInterval" );
CAF_PDM_InitScriptableField( &m_startMD, "StartMd", 0.0, "Start MD" );
CAF_PDM_InitScriptableField( &m_endMD, "EndMd", 0.0, "End MD" );
CAF_PDM_InitScriptableField( &m_diameter,
"Diameter",
RimMswCompletionParameters::defaultLinerDiameter( RiaDefines::EclipseUnitSystem::UNITS_METRIC ),
"Diameter" );
CAF_PDM_InitScriptableField( &m_roughnessFactor,
"RoughnessFactor",
RimMswCompletionParameters::defaultRoughnessFactor( RiaDefines::EclipseUnitSystem::UNITS_METRIC ),
"Roughness Factor" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDiameterRoughnessInterval::~RimDiameterRoughnessInterval()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessInterval::startMD() const
{
return m_startMD;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessInterval::endMD() const
{
return m_endMD;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessInterval::diameter() const
{
return m_diameter;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessInterval::diameter( RiaDefines::EclipseUnitSystem unitSystem ) const
{
if ( unitSystem == RiaDefines::EclipseUnitSystem::UNITS_FIELD )
{
return RiaEclipseUnitTools::meterToInch( m_diameter );
}
return m_diameter; // METRIC units - already in meters
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessInterval::roughnessFactor() const
{
return m_roughnessFactor;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessInterval::roughnessFactor( RiaDefines::EclipseUnitSystem unitSystem ) const
{
if ( unitSystem == RiaDefines::EclipseUnitSystem::UNITS_FIELD )
{
return RiaEclipseUnitTools::meterToFeet( m_roughnessFactor );
}
return m_roughnessFactor; // METRIC units - already in meters
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessInterval::setStartMD( double startMD )
{
m_startMD = startMD;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessInterval::setEndMD( double endMD )
{
m_endMD = endMD;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessInterval::setDiameter( double diameter )
{
m_diameter = diameter;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessInterval::setRoughnessFactor( double roughness )
{
m_roughnessFactor = roughness;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDiameterRoughnessInterval::isValidInterval() const
{
return m_endMD > m_startMD && m_diameter > 0.0 && m_roughnessFactor >= 0.0;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDiameterRoughnessInterval::overlaps( const RimDiameterRoughnessInterval* other ) const
{
if ( !other ) return false;
return m_endMD > other->startMD() && m_startMD < other->endMD();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDiameterRoughnessInterval::containsMD( double md ) const
{
return md >= m_startMD && md <= m_endMD;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimDiameterRoughnessInterval::diameterLabel() const
{
return QString( "%1 m" ).arg( m_diameter, 0, 'f', 3 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimDiameterRoughnessInterval::roughnessLabel() const
{
return QString( "%1 m" ).arg( m_roughnessFactor, 0, 'e', 2 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDiameterRoughnessInterval::operator<( const RimDiameterRoughnessInterval& rhs ) const
{
return m_startMD < rhs.m_startMD;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDiameterRoughnessInterval::isEnabled() const
{
return true; // Always enabled for now
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RiaDefines::WellPathComponentType RimDiameterRoughnessInterval::componentType() const
{
return RiaDefines::WellPathComponentType::CASING;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimDiameterRoughnessInterval::componentLabel() const
{
return generateDisplayLabel();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimDiameterRoughnessInterval::componentTypeLabel() const
{
return "Diameter/Roughness";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
cvf::Color3f RimDiameterRoughnessInterval::defaultComponentColor() const
{
return cvf::Color3f( 0.6f, 0.4f, 0.2f ); // Brown color for diameter/roughness intervals
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessInterval::applyOffset( double offsetMD )
{
m_startMD = m_startMD + offsetMD;
m_endMD = m_endMD + offsetMD;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessInterval::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_startMD || changedField == &m_endMD )
{
// Validate interval
if ( m_startMD >= m_endMD )
{
RiaLogging::warning( "Invalid interval: Start MD must be less than End MD" );
}
// Update overlap visual feedback in parent collection
auto* collection = firstAncestorOrThisOfType<RimDiameterRoughnessIntervalCollection>();
if ( collection )
{
collection->updateOverlapVisualFeedback();
}
}
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessInterval::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_startMD );
uiOrdering.add( &m_endMD );
uiOrdering.add( &m_diameter );
uiOrdering.add( &m_roughnessFactor );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessInterval::updateConnectedEditors()
{
// Update any connected UI editors
m_startMD.uiCapability()->updateConnectedEditors();
m_endMD.uiCapability()->updateConnectedEditors();
m_diameter.uiCapability()->updateConnectedEditors();
m_roughnessFactor.uiCapability()->updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimDiameterRoughnessInterval::generateDisplayLabel() const
{
return QString( "MD %.1f-%.1f: D=%.3fm, R=%1em" ).arg( m_startMD ).arg( m_endMD ).arg( m_diameter ).arg( m_roughnessFactor );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessInterval::defaultDiameter( RiaDefines::EclipseUnitSystem unitSystem )
{
return RimMswCompletionParameters::defaultLinerDiameter( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessInterval::defaultRoughness( RiaDefines::EclipseUnitSystem unitSystem )
{
return RimMswCompletionParameters::defaultRoughnessFactor( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessInterval::updateOverlapVisualFeedback( bool hasOverlap )
{
if ( hasOverlap )
{
// Set red color for overlapping fields
m_startMD.uiCapability()->setUiContentTextColor( Qt::red );
m_endMD.uiCapability()->setUiContentTextColor( Qt::red );
// Create tooltip with overlap information
QString tooltip = "This interval overlaps with another interval!";
m_startMD.uiCapability()->setUiToolTip( tooltip );
m_endMD.uiCapability()->setUiToolTip( tooltip );
}
else
{
// Reset color and tooltip
m_startMD.uiCapability()->setUiContentTextColor( QColor() );
m_endMD.uiCapability()->setUiContentTextColor( QColor() );
m_startMD.uiCapability()->setUiToolTip( "" );
m_endMD.uiCapability()->setUiToolTip( "" );
}
}
@@ -0,0 +1,97 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaDefines.h"
#include "RimWellPathComponentInterface.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include <QString>
class RimWellPath;
//==================================================================================================
///
/// Represents a diameter and roughness interval for a specific measured depth range
///
//==================================================================================================
class RimDiameterRoughnessInterval : public caf::PdmObject, public RimWellPathComponentInterface
{
CAF_PDM_HEADER_INIT;
public:
RimDiameterRoughnessInterval();
~RimDiameterRoughnessInterval() override;
// Getters
double startMD() const override;
double endMD() const override;
double diameter() const;
double diameter( RiaDefines::EclipseUnitSystem unitSystem ) const;
double roughnessFactor() const;
double roughnessFactor( RiaDefines::EclipseUnitSystem unitSystem ) const;
// Setters
void setStartMD( double startMD );
void setEndMD( double endMD );
void setDiameter( double diameter );
void setRoughnessFactor( double roughness );
// Validation
bool isValidInterval() const;
bool overlaps( const RimDiameterRoughnessInterval* other ) const;
bool containsMD( double md ) const;
// Display
QString diameterLabel() const;
QString roughnessLabel() const;
// Comparison for sorting
bool operator<( const RimDiameterRoughnessInterval& rhs ) const;
// Overrides from RimWellPathComponentInterface
bool isEnabled() const override;
RiaDefines::WellPathComponentType componentType() const override;
QString componentLabel() const override;
QString componentTypeLabel() const override;
cvf::Color3f defaultComponentColor() const override;
void applyOffset( double offsetMD ) override;
// Public static methods for default values
static double defaultDiameter( RiaDefines::EclipseUnitSystem unitSystem );
static double defaultRoughness( RiaDefines::EclipseUnitSystem unitSystem );
// Visual feedback for overlapping intervals
void updateOverlapVisualFeedback( bool hasOverlap );
protected:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
private:
void updateConnectedEditors();
QString generateDisplayLabel() const;
private:
caf::PdmField<double> m_startMD;
caf::PdmField<double> m_endMD;
caf::PdmField<double> m_diameter;
caf::PdmField<double> m_roughnessFactor;
};
@@ -0,0 +1,479 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimDiameterRoughnessIntervalCollection.h"
#include "RiaLogging.h"
#include "RimDiameterRoughnessInterval.h"
#include "RimMswCompletionParameters.h"
#include "cafCmdFeatureMenuBuilder.h"
#include "cafPdmUiTableViewEditor.h"
#include <algorithm>
#include <cmath>
CAF_PDM_SOURCE_INIT( RimDiameterRoughnessIntervalCollection, "DiameterRoughnessIntervalCollection" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDiameterRoughnessIntervalCollection::RimDiameterRoughnessIntervalCollection()
{
CAF_PDM_InitObject( "Diameter Roughness Intervals", ":/WellPathComponent16x16.png" );
CAF_PDM_InitFieldNoDefault( &m_intervals, "Intervals", "Intervals" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDiameterRoughnessIntervalCollection::~RimDiameterRoughnessIntervalCollection()
{
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimDiameterRoughnessInterval*> RimDiameterRoughnessIntervalCollection::intervals() const
{
return m_intervals.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::addInterval( RimDiameterRoughnessInterval* interval )
{
if ( interval )
{
m_intervals.push_back( interval );
sortIntervalsByMD();
updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::removeInterval( RimDiameterRoughnessInterval* interval )
{
if ( interval )
{
m_intervals.removeChild( interval );
delete interval;
updateConnectedEditors();
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::removeAllIntervals()
{
m_intervals.deleteChildren();
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDiameterRoughnessInterval*
RimDiameterRoughnessIntervalCollection::createInterval( double startMD, double endMD, double diameter, double roughness )
{
auto* interval = new RimDiameterRoughnessInterval();
interval->setStartMD( startMD );
interval->setEndMD( endMD );
interval->setDiameter( diameter );
interval->setRoughnessFactor( roughness );
addInterval( interval );
return interval;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDiameterRoughnessInterval* RimDiameterRoughnessIntervalCollection::createDefaultInterval()
{
auto* interval = new RimDiameterRoughnessInterval();
addInterval( interval );
return interval;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessIntervalCollection::getDiameterAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const
{
auto* interval = findIntervalAtMD( md );
if ( interval )
{
return interval->diameter( unitSystem );
}
// Return default if no interval found
return RimMswCompletionParameters::defaultLinerDiameter( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimDiameterRoughnessIntervalCollection::getRoughnessAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const
{
auto* interval = findIntervalAtMD( md );
if ( interval )
{
return interval->roughnessFactor( unitSystem );
}
// Return default if no interval found
return RimMswCompletionParameters::defaultRoughnessFactor( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDiameterRoughnessInterval* RimDiameterRoughnessIntervalCollection::findIntervalAtMD( double md ) const
{
for ( auto* interval : intervals() )
{
if ( interval && interval->containsMD( md ) )
{
return interval;
}
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDiameterRoughnessIntervalCollection::hasValidIntervals() const
{
if ( isEmpty() ) return false;
for ( auto* interval : intervals() )
{
if ( !interval || !interval->isValidInterval() )
{
return false;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDiameterRoughnessIntervalCollection::hasOverlappingIntervals() const
{
auto intervalList = intervals();
for ( size_t i = 0; i < intervalList.size(); ++i )
{
for ( size_t j = i + 1; j < intervalList.size(); ++j )
{
if ( intervalList[i]->overlaps( intervalList[j] ) )
{
return true;
}
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDiameterRoughnessIntervalCollection::coversFullRange( double startMD, double endMD ) const
{
if ( isEmpty() ) return false;
auto intervalList = intervals();
std::sort( intervalList.begin(),
intervalList.end(),
[]( const RimDiameterRoughnessInterval* a, const RimDiameterRoughnessInterval* b ) { return a->startMD() < b->startMD(); } );
double currentPos = startMD;
for ( auto* interval : intervalList )
{
if ( interval->startMD() > currentPos + 1e-6 ) // Allow small gap tolerance
{
return false; // Gap found
}
currentPos = std::max( currentPos, interval->endMD() );
}
return currentPos >= endMD - 1e-6; // Allow small tolerance
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QString> RimDiameterRoughnessIntervalCollection::validateIntervals() const
{
std::vector<QString> issues;
if ( isEmpty() )
{
issues.push_back( "No intervals defined" );
return issues;
}
auto intervalList = intervals();
// Check for invalid intervals
for ( auto* interval : intervalList )
{
if ( !interval->isValidInterval() )
{
issues.push_back( QString( "Invalid interval: MD %.1f-%.1f" ).arg( interval->startMD() ).arg( interval->endMD() ) );
}
}
// Check for overlaps
for ( size_t i = 0; i < intervalList.size(); ++i )
{
for ( size_t j = i + 1; j < intervalList.size(); ++j )
{
if ( intervalList[i]->overlaps( intervalList[j] ) )
{
issues.push_back( QString( "Overlapping intervals: MD %.1f-%.1f and MD %.1f-%.1f" )
.arg( intervalList[i]->startMD() )
.arg( intervalList[i]->endMD() )
.arg( intervalList[j]->startMD() )
.arg( intervalList[j]->endMD() ) );
}
}
}
return issues;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::sortIntervalsByMD()
{
auto intervalList = intervals();
std::sort( intervalList.begin(),
intervalList.end(),
[]( const RimDiameterRoughnessInterval* a, const RimDiameterRoughnessInterval* b ) { return *a < *b; } );
// Rebuild the collection in sorted order
m_intervals.clearWithoutDelete();
for ( auto* interval : intervalList )
{
m_intervals.push_back( interval );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::mergeAdjacentIntervals()
{
sortIntervalsByMD();
auto intervalList = intervals();
std::vector<RimDiameterRoughnessInterval*> mergedIntervals;
for ( auto* interval : intervalList )
{
if ( mergedIntervals.empty() )
{
mergedIntervals.push_back( interval );
continue;
}
auto* lastInterval = mergedIntervals.back();
// Check if intervals are adjacent and have same properties
if ( std::abs( lastInterval->endMD() - interval->startMD() ) < 1e-6 &&
std::abs( lastInterval->diameter() - interval->diameter() ) < 1e-6 &&
std::abs( lastInterval->roughnessFactor() - interval->roughnessFactor() ) < 1e-6 )
{
// Merge intervals
lastInterval->setEndMD( interval->endMD() );
delete interval;
}
else
{
mergedIntervals.push_back( interval );
}
}
// Rebuild collection with merged intervals
m_intervals.clearWithoutDelete();
for ( auto* interval : mergedIntervals )
{
m_intervals.push_back( interval );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimDiameterRoughnessIntervalCollection::isEmpty() const
{
return m_intervals.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
size_t RimDiameterRoughnessIntervalCollection::count() const
{
return m_intervals.size();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::updateConnectedEditors()
{
m_intervals.uiCapability()->updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmChildArrayField<RimDiameterRoughnessInterval*>& RimDiameterRoughnessIntervalCollection::intervalsField()
{
return m_intervals;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::updateOverlapVisualFeedback()
{
auto intervalList = intervals();
// First, reset all intervals to no overlap
for ( auto* interval : intervalList )
{
interval->updateOverlapVisualFeedback( false );
}
// Then check for overlaps and update visual feedback
for ( size_t i = 0; i < intervalList.size(); ++i )
{
bool hasOverlap = false;
for ( size_t j = 0; j < intervalList.size(); ++j )
{
if ( i != j && intervalList[i]->overlaps( intervalList[j] ) )
{
hasOverlap = true;
break;
}
}
if ( hasOverlap )
{
intervalList[i]->updateOverlapVisualFeedback( true );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::fieldChangedByUi( const caf::PdmFieldHandle* changedField,
const QVariant& oldValue,
const QVariant& newValue )
{
if ( changedField == &m_intervals )
{
sortIntervalsByMD();
updateOverlapVisualFeedback();
}
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
uiOrdering.add( &m_intervals );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::defineEditorAttribute( const caf::PdmFieldHandle* field,
QString uiConfigName,
caf::PdmUiEditorAttribute* attribute )
{
if ( field == &m_intervals )
{
auto tvAttribute = dynamic_cast<caf::PdmUiTableViewEditorAttribute*>( attribute );
if ( tvAttribute )
{
tvAttribute->resizePolicy = caf::PdmUiTableViewEditorAttribute::RESIZE_TO_FILL_CONTAINER;
tvAttribute->alwaysEnforceResizePolicy = true;
tvAttribute->minimumHeight = 300;
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::onChildDeleted( caf::PdmChildArrayFieldHandle* childArray,
std::vector<caf::PdmObjectHandle*>& referringObjects )
{
updateConnectedEditors();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu,
QMenu* menu,
QWidget* fieldEditorWidget )
{
caf::CmdFeatureMenuBuilder menuBuilder;
menuBuilder << "RicNewDiameterRoughnessIntervalFeature";
menuBuilder << "Separator";
menuBuilder << "RicDeleteDiameterRoughnessIntervalFeature";
menuBuilder.appendToMenu( menu );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimDiameterRoughnessIntervalCollection::insertInterval( RimDiameterRoughnessInterval* insertBefore, RimDiameterRoughnessInterval* interval )
{
if ( !interval ) return;
size_t index = m_intervals.indexOf( insertBefore );
if ( index < m_intervals.size() )
m_intervals.insert( index, interval );
else
m_intervals.push_back( interval );
sortIntervalsByMD();
updateConnectedEditors();
}
@@ -0,0 +1,89 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "RiaDefines.h"
#include "cafPdmChildArrayField.h"
#include "cafPdmObject.h"
#include <vector>
class RimDiameterRoughnessInterval;
//==================================================================================================
///
/// Collection to manage diameter and roughness intervals for measured depth ranges
///
//==================================================================================================
class RimDiameterRoughnessIntervalCollection : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
public:
RimDiameterRoughnessIntervalCollection();
~RimDiameterRoughnessIntervalCollection() override;
// Collection management
std::vector<RimDiameterRoughnessInterval*> intervals() const;
void addInterval( RimDiameterRoughnessInterval* interval );
void insertInterval( RimDiameterRoughnessInterval* insertBefore, RimDiameterRoughnessInterval* interval );
void removeInterval( RimDiameterRoughnessInterval* interval );
void removeAllIntervals();
// Interval creation
RimDiameterRoughnessInterval* createInterval( double startMD, double endMD, double diameter, double roughness );
RimDiameterRoughnessInterval* createDefaultInterval();
// Lookup methods
double getDiameterAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const;
double getRoughnessAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const;
RimDiameterRoughnessInterval* findIntervalAtMD( double md ) const;
// Validation
bool hasValidIntervals() const;
bool hasOverlappingIntervals() const;
bool coversFullRange( double startMD, double endMD ) const;
std::vector<QString> validateIntervals() const;
// Sorting and organization
void sortIntervalsByMD();
void mergeAdjacentIntervals();
// Utility
bool isEmpty() const;
size_t count() const;
void updateConnectedEditors();
// Accessor for UI integration
caf::PdmChildArrayField<RimDiameterRoughnessInterval*>& intervalsField();
// Visual feedback for overlapping intervals
void updateOverlapVisualFeedback();
protected:
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget ) override;
void defineEditorAttribute( const caf::PdmFieldHandle* field, QString uiConfigName, caf::PdmUiEditorAttribute* attribute ) override;
private:
void onChildDeleted( caf::PdmChildArrayFieldHandle* childArray, std::vector<caf::PdmObjectHandle*>& referringObjects ) override;
caf::PdmChildArrayField<RimDiameterRoughnessInterval*> m_intervals;
};
@@ -19,12 +19,15 @@
#include "RimMswCompletionParameters.h"
#include "RiaEclipseUnitTools.h"
#include "RimDiameterRoughnessIntervalCollection.h"
#include "RimWellPath.h"
#include "cafCmdFeatureMenuBuilder.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmObjectScriptingCapability.h"
#include "cafPdmUiObjectEditorHandle.h"
#include "cafPdmUiTableViewEditor.h"
#include <limits>
@@ -54,6 +57,14 @@ void RimMswCompletionParameters::LengthAndDepthEnum::setUp()
addItem( RimMswCompletionParameters::LengthAndDepthType::ABS, "ABS", "Absolute" );
setDefault( RimMswCompletionParameters::LengthAndDepthType::ABS );
}
template <>
void RimMswCompletionParameters::DiameterRoughnessModeEnum::setUp()
{
addItem( RimMswCompletionParameters::DiameterRoughnessMode::UNIFORM, "Uniform", "Uniform" );
addItem( RimMswCompletionParameters::DiameterRoughnessMode::INTERVALS, "Intervals", "Intervals" );
setDefault( RimMswCompletionParameters::DiameterRoughnessMode::UNIFORM );
}
} // namespace caf
CAF_PDM_SOURCE_INIT( RimMswCompletionParameters, "RimMswCompletionParameters" );
@@ -85,6 +96,17 @@ RimMswCompletionParameters::RimMswCompletionParameters()
RimMswCompletionParameters::defaultRoughnessFactor( unitSystem ),
"Roughness Factor" );
// New interval-based fields
CAF_PDM_InitScriptableFieldNoDefault( &m_diameterRoughnessMode, "DiameterRoughnessMode", "Diameter Roughness Mode" );
CAF_PDM_InitFieldNoDefault( &m_diameterRoughnessIntervals, "DiameterRoughnessIntervals", "Diameter Roughness Intervals" );
m_diameterRoughnessIntervals = new RimDiameterRoughnessIntervalCollection();
m_diameterRoughnessIntervals->intervalsField().uiCapability()->setUiEditorTypeName( caf::PdmUiTableViewEditor::uiEditorTypeName() );
m_diameterRoughnessIntervals->intervalsField().uiCapability()->setUiLabelPosition( caf::PdmUiItemInfo::TOP );
m_diameterRoughnessIntervals->intervalsField().uiCapability()->setCustomContextMenuEnabled( true );
// Enable custom context menu on this object as well
setCustomContextMenuEnabled( true );
CAF_PDM_InitScriptableFieldNoDefault( &m_pressureDrop, "PressureDrop", "Pressure Drop" );
CAF_PDM_InitScriptableFieldNoDefault( &m_lengthAndDepth, "LengthAndDepth", "Length and Depth" );
@@ -213,6 +235,66 @@ double RimMswCompletionParameters::roughnessFactor() const
return m_roughnessFactor();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimMswCompletionParameters::DiameterRoughnessMode RimMswCompletionParameters::diameterRoughnessMode() const
{
return m_diameterRoughnessMode();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimMswCompletionParameters::setDiameterRoughnessMode( DiameterRoughnessMode mode )
{
m_diameterRoughnessMode = mode;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimMswCompletionParameters::isUsingIntervalSpecificValues() const
{
return m_diameterRoughnessMode() == DiameterRoughnessMode::INTERVALS;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimMswCompletionParameters::getDiameterAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const
{
if ( isUsingIntervalSpecificValues() && m_diameterRoughnessIntervals() )
{
return m_diameterRoughnessIntervals()->getDiameterAtMD( md, unitSystem );
}
// Fall back to single value
return linerDiameter( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimMswCompletionParameters::getRoughnessAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const
{
if ( isUsingIntervalSpecificValues() && m_diameterRoughnessIntervals() )
{
return m_diameterRoughnessIntervals()->getRoughnessAtMD( md, unitSystem );
}
// Fall back to single value
return roughnessFactor( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimDiameterRoughnessIntervalCollection* RimMswCompletionParameters::diameterRoughnessIntervals() const
{
return m_diameterRoughnessIntervals();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@@ -314,6 +396,11 @@ void RimMswCompletionParameters::fieldChangedByUi( const caf::PdmFieldHandle* ch
m_maxSegmentLength.uiCapability()->setUiHidden( !m_enforceMaxSegmentLength() );
caf::PdmUiObjectEditorHandle::updateUiAllObjectEditors();
}
if ( changedField == &m_diameterRoughnessMode )
{
updateAllRequiredEditors();
}
}
//--------------------------------------------------------------------------------------------------
@@ -341,8 +428,26 @@ void RimMswCompletionParameters::defineUiOrdering( QString uiConfigName, caf::Pd
uiOrdering.add( &m_refMD );
m_refMD.uiCapability()->setUiHidden( m_refMDType == ReferenceMDType::AUTO_REFERENCE_MD );
uiOrdering.add( &m_linerDiameter );
uiOrdering.add( &m_roughnessFactor );
// Diameter and Roughness section
auto* diameterRoughnessGroup = uiOrdering.addNewGroup( "Diameter and Roughness" );
diameterRoughnessGroup->add( &m_diameterRoughnessMode );
bool usingIntervals = m_diameterRoughnessMode() == DiameterRoughnessMode::INTERVALS;
if ( usingIntervals )
{
diameterRoughnessGroup->add( &m_diameterRoughnessIntervals->intervalsField() );
m_linerDiameter.uiCapability()->setUiHidden( true );
m_roughnessFactor.uiCapability()->setUiHidden( true );
}
else
{
diameterRoughnessGroup->add( &m_linerDiameter );
diameterRoughnessGroup->add( &m_roughnessFactor );
m_linerDiameter.uiCapability()->setUiHidden( false );
m_roughnessFactor.uiCapability()->setUiHidden( false );
}
uiOrdering.add( &m_pressureDrop );
uiOrdering.add( &m_lengthAndDepth );
uiOrdering.add( &m_enforceMaxSegmentLength );
@@ -352,11 +457,31 @@ void RimMswCompletionParameters::defineUiOrdering( QString uiConfigName, caf::Pd
{
uiOrdering.add( &m_customValuesForLateral );
uiOrdering.add( &m_linerDiameter );
uiOrdering.add( &m_roughnessFactor );
// Diameter and Roughness section for laterals
auto* diameterRoughnessGroup = uiOrdering.addNewGroup( "Diameter and Roughness" );
diameterRoughnessGroup->add( &m_diameterRoughnessMode );
m_linerDiameter.uiCapability()->setUiReadOnly( !m_customValuesForLateral() );
m_linerDiameter.uiCapability()->setUiReadOnly( !m_customValuesForLateral() );
bool usingIntervals = m_diameterRoughnessMode() == DiameterRoughnessMode::INTERVALS;
if ( usingIntervals )
{
diameterRoughnessGroup->add( &m_diameterRoughnessIntervals );
m_linerDiameter.uiCapability()->setUiHidden( true );
m_roughnessFactor.uiCapability()->setUiHidden( true );
}
else
{
diameterRoughnessGroup->add( &m_linerDiameter );
diameterRoughnessGroup->add( &m_roughnessFactor );
m_linerDiameter.uiCapability()->setUiHidden( false );
m_roughnessFactor.uiCapability()->setUiHidden( false );
}
bool isReadOnly = !m_customValuesForLateral();
m_linerDiameter.uiCapability()->setUiReadOnly( isReadOnly );
m_roughnessFactor.uiCapability()->setUiReadOnly( isReadOnly );
m_diameterRoughnessMode.uiCapability()->setUiReadOnly( isReadOnly );
m_diameterRoughnessIntervals.uiCapability()->setUiReadOnly( isReadOnly );
}
}
@@ -404,3 +529,20 @@ void RimMswCompletionParameters::updateFromTopLevelWell( const RimMswCompletionP
m_roughnessFactor = rhs.m_roughnessFactor();
*/
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimMswCompletionParameters::defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget )
{
if ( fieldNeedingMenu == &m_diameterRoughnessIntervals )
{
caf::CmdFeatureMenuBuilder menuBuilder;
menuBuilder << "RicNewDiameterRoughnessIntervalFeature";
menuBuilder << "Separator";
menuBuilder << "RicDeleteDiameterRoughnessIntervalFeature";
menuBuilder.appendToMenu( menu );
}
}
@@ -19,10 +19,13 @@
#include "RiaDefines.h"
#include "cafPdmChildField.h"
#include "cafPdmField.h"
#include "cafPdmObject.h"
#include "cafPdmUiGroup.h"
class RimDiameterRoughnessIntervalCollection;
class RimMswCompletionParameters : public caf::PdmObject
{
CAF_PDM_HEADER_INIT;
@@ -47,9 +50,16 @@ public:
INC
};
using ReferenceMDEnum = caf::AppEnum<ReferenceMDType>;
using PressureDropEnum = caf::AppEnum<PressureDropType>;
using LengthAndDepthEnum = caf::AppEnum<LengthAndDepthType>;
enum class DiameterRoughnessMode
{
UNIFORM,
INTERVALS
};
using ReferenceMDEnum = caf::AppEnum<ReferenceMDType>;
using PressureDropEnum = caf::AppEnum<PressureDropType>;
using LengthAndDepthEnum = caf::AppEnum<LengthAndDepthType>;
using DiameterRoughnessModeEnum = caf::AppEnum<DiameterRoughnessMode>;
RimMswCompletionParameters();
~RimMswCompletionParameters() override;
@@ -73,19 +83,30 @@ public:
void setPressureDrop( PressureDropType pressureDropType );
void setLengthAndDepth( LengthAndDepthType lengthAndDepthType );
// New interval-based methods
DiameterRoughnessMode diameterRoughnessMode() const;
void setDiameterRoughnessMode( DiameterRoughnessMode mode );
bool isUsingIntervalSpecificValues() const;
double getDiameterAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const;
double getRoughnessAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const;
RimDiameterRoughnessIntervalCollection* diameterRoughnessIntervals() const;
void setUnitSystemSpecificDefaults();
void updateFromTopLevelWell( const RimMswCompletionParameters* topLevelWellParameters );
// Public static methods for default values - used by interval classes
static double defaultLinerDiameter( RiaDefines::EclipseUnitSystem unitSystem );
static double defaultRoughnessFactor( RiaDefines::EclipseUnitSystem unitSystem );
void fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) override;
protected:
void defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) override;
void initAfterRead() override;
private:
static double defaultLinerDiameter( RiaDefines::EclipseUnitSystem unitSystem );
static double defaultRoughnessFactor( RiaDefines::EclipseUnitSystem unitSystem );
void defineCustomContextMenu( const caf::PdmFieldHandle* fieldNeedingMenu, QMenu* menu, QWidget* fieldEditorWidget ) override;
private:
caf::PdmField<ReferenceMDEnum> m_refMDType;
@@ -95,6 +116,10 @@ private:
caf::PdmField<double> m_linerDiameter;
caf::PdmField<double> m_roughnessFactor;
// New interval-based fields
caf::PdmField<DiameterRoughnessModeEnum> m_diameterRoughnessMode;
caf::PdmChildField<RimDiameterRoughnessIntervalCollection*> m_diameterRoughnessIntervals;
caf::PdmField<PressureDropEnum> m_pressureDrop;
caf::PdmField<LengthAndDepthEnum> m_lengthAndDepth;
@@ -33,6 +33,7 @@ set(SOURCE_GROUP_HEADER_FILES
${CMAKE_CURRENT_LIST_DIR}/RimcRegularSurface.h
${CMAKE_CURRENT_LIST_DIR}/RimcPerforationInterval.h
${CMAKE_CURRENT_LIST_DIR}/RimcValveTemplateCollection.h
${CMAKE_CURRENT_LIST_DIR}/RimcWellPathCompletionSettings.h
)
set(SOURCE_GROUP_SOURCE_FILES
@@ -70,6 +71,7 @@ set(SOURCE_GROUP_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/RimcRegularSurface.cpp
${CMAKE_CURRENT_LIST_DIR}/RimcPerforationInterval.cpp
${CMAKE_CURRENT_LIST_DIR}/RimcValveTemplateCollection.cpp
${CMAKE_CURRENT_LIST_DIR}/RimcWellPathCompletionSettings.cpp
)
list(APPEND CODE_HEADER_FILES ${SOURCE_GROUP_HEADER_FILES})
@@ -0,0 +1,90 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RimcWellPathCompletionSettings.h"
#include "RimDiameterRoughnessInterval.h"
#include "RimDiameterRoughnessIntervalCollection.h"
#include "RimMswCompletionParameters.h"
#include "RimWellPathCompletionSettings.h"
#include "cafPdmFieldScriptingCapability.h"
CAF_PDM_OBJECT_METHOD_SOURCE_INIT( RimWellPathCompletionSettings,
RimcWellPathCompletionSettings_addDiameterRoughnessInterval,
"AddDiameterRoughnessInterval" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimcWellPathCompletionSettings_addDiameterRoughnessInterval::RimcWellPathCompletionSettings_addDiameterRoughnessInterval( caf::PdmObjectHandle* self )
: caf::PdmObjectCreationMethod( self )
{
CAF_PDM_InitObject( "Add Diameter Roughness Interval" );
CAF_PDM_InitScriptableField( &m_startMD, "StartMd", 0.0, "Start Measured Depth" );
CAF_PDM_InitScriptableField( &m_endMD, "EndMd", 100.0, "End Measured Depth" );
CAF_PDM_InitScriptableField( &m_diameter, "Diameter", 0.152, "Diameter" );
CAF_PDM_InitScriptableField( &m_roughnessFactor, "RoughnessFactor", 1.0e-5, "Roughness Factor" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::expected<caf::PdmObjectHandle*, QString> RimcWellPathCompletionSettings_addDiameterRoughnessInterval::execute()
{
auto completionSettings = self<RimWellPathCompletionSettings>();
if ( !completionSettings )
{
return std::unexpected( QString( "Completion settings is null. Cannot add diameter roughness interval." ) );
}
auto mswParams = completionSettings->mswCompletionParameters();
if ( !mswParams )
{
return std::unexpected( QString( "MSW completion parameters is null. Cannot add diameter roughness interval." ) );
}
auto intervalCollection = mswParams->diameterRoughnessIntervals();
if ( !intervalCollection )
{
return std::unexpected( QString( "Diameter roughness interval collection is null. Cannot add interval." ) );
}
// Ensure we're in interval-specific mode
mswParams->setDiameterRoughnessMode( RimMswCompletionParameters::DiameterRoughnessMode::INTERVALS );
// Create new interval
auto* newInterval = intervalCollection->createInterval( m_startMD(), m_endMD(), m_diameter(), m_roughnessFactor() );
if ( !newInterval )
{
return std::unexpected( QString( "Failed to create diameter roughness interval." ) );
}
completionSettings->updateAllRequiredEditors();
return newInterval;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RimcWellPathCompletionSettings_addDiameterRoughnessInterval::classKeywordReturnedType() const
{
return RimDiameterRoughnessInterval::classKeywordStatic();
}
@@ -0,0 +1,45 @@
/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2025 Equinor ASA
//
// ResInsight is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#pragma once
#include "cafPdmField.h"
#include "cafPdmObjectHandle.h"
#include "cafPdmObjectMethod.h"
#include <QString>
//==================================================================================================
///
//==================================================================================================
class RimcWellPathCompletionSettings_addDiameterRoughnessInterval : public caf::PdmObjectCreationMethod
{
CAF_PDM_HEADER_INIT;
public:
RimcWellPathCompletionSettings_addDiameterRoughnessInterval( caf::PdmObjectHandle* self );
std::expected<caf::PdmObjectHandle*, QString> execute() override;
QString classKeywordReturnedType() const override;
private:
caf::PdmField<double> m_startMD;
caf::PdmField<double> m_endMD;
caf::PdmField<double> m_diameter;
caf::PdmField<double> m_roughnessFactor;
};
@@ -68,6 +68,17 @@ completions_settings.group_name_for_export = "msj"
completions_settings.well_type_for_export = "GAS"
completions_settings.update() # Commit updates back to ResInsight
# Add diameter roughness intervals for interval-specific configuration
interval1 = completions_settings.add_diameter_roughness_interval(
start_md=3200, end_md=3300, diameter=0.18, roughness_factor=1.5e-5
)
interval2 = completions_settings.add_diameter_roughness_interval(
start_md=3300, end_md=3400, diameter=0.16, roughness_factor=2.0e-5
)
print(
f"Added diameter roughness intervals: {interval1.start_md}-{interval1.end_md}m and {interval2.start_md}-{interval2.end_md}m"
)
# Optionally update the MSW settings
msw_settings = well_path.msw_settings()
msw_settings.custom_values_for_lateral = False
@@ -0,0 +1,46 @@
import rips
def test_diameter_roughness_intervals(rips_instance, initialize_test):
"""Test the new diameter roughness intervals Python GRPC interface"""
# Create a test well
well_path_coll = rips_instance.project.well_path_collection()
well_path = well_path_coll.add_new_object(rips.ModeledWellPath)
well_path.name = "Test Well for Diameter Intervals"
completions_settings = well_path.completion_settings()
assert completions_settings is not None, "Completion settings should not be None"
# Test our new method - create first interval
interval1 = completions_settings.add_diameter_roughness_interval(
start_md=100, end_md=200, diameter=0.15, roughness_factor=1e-5
)
# Assertions to verify the first interval
assert interval1 is not None, "First interval should not be None"
assert interval1.start_md == 100
assert interval1.end_md == 200
assert interval1.diameter == 0.15
assert interval1.roughness_factor == 1e-5
# Test creating a second interval with different values
interval2 = completions_settings.add_diameter_roughness_interval(
start_md=200, end_md=300, diameter=0.12, roughness_factor=2e-5
)
# Assertions to verify the second interval
assert interval2 is not None, "Second interval should not be None"
assert interval2.start_md == 200
assert interval2.end_md == 300
assert interval2.diameter == 0.12
assert interval2.roughness_factor == 2e-5
# Test default values
interval3 = completions_settings.add_diameter_roughness_interval()
assert interval3 is not None, "Third interval with defaults should not be None"
assert interval3.start_md == 0.0
assert interval3.end_md == 100.0
assert interval3.diameter == 0.152
assert interval3.roughness_factor == 1e-5