Files
ResInsight/ApplicationLibCode/ProjectDataModel/Completions/RimSegmentCollection.cpp
T
Magne Sjaastad 6e8e658f6d #14980: Remove global max segment length from segment collection
The global max segment length no longer exists, so segment subdivision is defined only by the segment intervals.
2026-10-19 21:13:13 +02:00

607 lines
28 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2026- 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 "RimSegmentCollection.h"
#include "RiaEclipseUnitTools.h"
#include "RimCustomSegmentInterval.h"
#include "RimCustomSegmentIntervalCollection.h"
#include "RimDiameterRoughnessInterval.h"
#include "RimDiameterRoughnessIntervalCollection.h"
#include "RimMswCompletionParameters.h"
#include "RimSegmentInterval.h"
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
#include "cafCmdFeatureMenuBuilder.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmObjectScriptingCapability.h"
#include "cafPdmUiObjectEditorHandle.h"
#include "cafPdmUiTreeOrdering.h"
#include <algorithm>
#include <cmath>
#include <limits>
namespace caf
{
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <>
void RimSegmentCollection::ReferenceMDEnum::setUp()
{
addItem( RimSegmentCollection::ReferenceMDType::AUTO_REFERENCE_MD, "GridEntryPoint", "Grid Entry Point", { "GridIntersectionRefMD" } );
addItem( RimSegmentCollection::ReferenceMDType::MANUAL_REFERENCE_MD, "UserDefined", "User Defined", { "ManualRefMD" } );
setDefault( RimSegmentCollection::ReferenceMDType::AUTO_REFERENCE_MD );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
template <>
void RimSegmentCollection::CompsegsSegmentNumberEnum::setUp()
{
addItem( RimSegmentCollection::CompsegsSegmentNumberType::ASSIGNED_BY_SIMULATOR, "AssignedBySimulator", "Assigned by Simulator (1*)" );
addItem( RimSegmentCollection::CompsegsSegmentNumberType::EXPORTED, "Exported", "Exported" );
setDefault( RimSegmentCollection::CompsegsSegmentNumberType::ASSIGNED_BY_SIMULATOR );
}
} // namespace caf
CAF_PDM_SOURCE_INIT( RimSegmentCollection, "SegmentCollection" );
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSegmentCollection::RimSegmentCollection()
{
CAF_PDM_InitScriptableObject( "Segments", ":/Segment.svg", "", "SegmentCollection" );
CAF_PDM_InitScriptableFieldWithScriptKeywordNoDefault( &m_refMDType, "RefMDType", "ReferenceMdType", "Reference MD Type" );
CAF_PDM_InitScriptableFieldWithScriptKeyword( &m_refMD, "RefMD", "UserDefinedReferenceMd", 0.0, "User Defined Reference MD" );
CAF_PDM_InitScriptableField( &m_customValuesForLateral, "CustomValuesForLateral", false, "Custom Values for Lateral" );
const auto unitSystem = RiaDefines::EclipseUnitSystem::UNITS_METRIC;
CAF_PDM_InitScriptableField( &m_linerDiameter, "LinerDiameter", defaultLinerDiameter( unitSystem ), "Liner Inner Diameter" );
CAF_PDM_InitScriptableField( &m_roughnessFactor, "RoughnessFactor", defaultRoughnessFactor( unitSystem ), "Roughness Factor" );
CAF_PDM_InitScriptableFieldNoDefault( &m_segmentIntervals, "Intervals", "Segment Intervals" );
CAF_PDM_InitScriptableField( &m_singleSegmentBeforeFirstPerforation,
"SingleSegmentBeforeFirstPerforation",
false,
"Single Segment Before First Perforation" );
CAF_PDM_InitScriptableField( &m_singleSegmentAfterLastPerforation,
"SingleSegmentAfterLastPerforation",
false,
"Single Segment After Last Perforation" );
CAF_PDM_InitScriptableFieldNoDefault( &m_compsegsSegmentNumber, "CompsegsSegmentNumber", "COMPSEGS Segment Number (ISEG)" );
m_compsegsSegmentNumber.uiCapability()->setUiToolTip(
"Export the segment each COMPSEGS connection belongs to, or leave it to the simulator to assign the segment" );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSegmentCollection::ReferenceMDType RimSegmentCollection::referenceMDType() const
{
return m_refMDType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::manualReferenceMD() const
{
if ( m_refMDType == ReferenceMDType::AUTO_REFERENCE_MD ) return std::numeric_limits<double>::infinity();
return m_refMD();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::linerDiameter( RiaDefines::EclipseUnitSystem unitSystem ) const
{
auto* wellPath = firstAncestorOrThisOfTypeAsserted<RimWellPath>();
double diameter = m_linerDiameter();
if ( !wellPath->isTopLevelWellPath() && !m_customValuesForLateral() )
{
if ( const auto* topLevelWell = wellPath->topLevelWellPath() )
{
diameter = topLevelWell->segmentCollection()->linerDiameter();
}
}
if ( wellPath->unitSystem() == RiaDefines::EclipseUnitSystem::UNITS_FIELD && unitSystem == RiaDefines::EclipseUnitSystem::UNITS_METRIC )
return RiaEclipseUnitTools::feetToMeter( diameter );
if ( wellPath->unitSystem() == RiaDefines::EclipseUnitSystem::UNITS_METRIC && unitSystem == RiaDefines::EclipseUnitSystem::UNITS_FIELD )
return RiaEclipseUnitTools::meterToFeet( diameter );
return diameter;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::linerDiameter() const
{
return m_linerDiameter();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::roughnessFactor( RiaDefines::EclipseUnitSystem unitSystem ) const
{
auto* wellPath = firstAncestorOrThisOfTypeAsserted<RimWellPath>();
double roughness = m_roughnessFactor();
if ( !wellPath->isTopLevelWellPath() && !m_customValuesForLateral() )
{
if ( const auto* topLevelWell = wellPath->topLevelWellPath() )
{
roughness = topLevelWell->segmentCollection()->roughnessFactor();
}
}
if ( wellPath->unitSystem() == RiaDefines::EclipseUnitSystem::UNITS_FIELD && unitSystem == RiaDefines::EclipseUnitSystem::UNITS_METRIC )
return RiaEclipseUnitTools::feetToMeter( roughness );
if ( wellPath->unitSystem() == RiaDefines::EclipseUnitSystem::UNITS_METRIC && unitSystem == RiaDefines::EclipseUnitSystem::UNITS_FIELD )
return RiaEclipseUnitTools::meterToFeet( roughness );
return roughness;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::roughnessFactor() const
{
return m_roughnessFactor();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::setSingleSegmentBeforeFirstPerforation( bool enable )
{
m_singleSegmentBeforeFirstPerforation = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::setSingleSegmentAfterLastPerforation( bool enable )
{
m_singleSegmentAfterLastPerforation = enable;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSegmentCollection::singleSegmentBeforeFirstPerforation() const
{
return m_singleSegmentBeforeFirstPerforation();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSegmentCollection::singleSegmentAfterLastPerforation() const
{
return m_singleSegmentAfterLastPerforation();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSegmentCollection::exportCompsegsSegmentNumber() const
{
return m_compsegsSegmentNumber() == CompsegsSegmentNumberType::EXPORTED;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::setCompsegsSegmentNumber( CompsegsSegmentNumberType segmentNumberType )
{
m_compsegsSegmentNumber = segmentNumberType;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::setReferenceMDType( ReferenceMDType refType )
{
m_refMDType = refType;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::setManualReferenceMD( double manualRefMD )
{
m_refMD = manualRefMD;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::setLinerDiameter( double diameter )
{
m_linerDiameter = diameter;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::setRoughnessFactor( double roughnessFactor )
{
m_roughnessFactor = roughnessFactor;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSegmentInterval* RimSegmentCollection::findIntervalAtMD( double md, const std::optional<QDateTime>& exportDate ) const
{
for ( auto* interval : intervals() )
{
if ( interval && interval->containsMD( md ) && ( !exportDate.has_value() || interval->isActiveOnDate( *exportDate ) ) )
return interval;
}
return nullptr;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::getDiameterAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const
{
if ( auto* interval = findIntervalAtMD( md, std::nullopt ) ) return interval->diameter( unitSystem );
return linerDiameter( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::getRoughnessAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem ) const
{
if ( auto* interval = findIntervalAtMD( md, std::nullopt ) ) return interval->roughnessFactor( unitSystem );
return roughnessFactor( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::getDiameterAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem, const QDateTime& exportDate ) const
{
if ( auto* interval = findIntervalAtMD( md, exportDate ) ) return interval->diameter( unitSystem );
return linerDiameter( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::getRoughnessAtMD( double md, RiaDefines::EclipseUnitSystem unitSystem, const QDateTime& exportDate ) const
{
if ( auto* interval = findIntervalAtMD( md, exportDate ) ) return interval->roughnessFactor( unitSystem );
return roughnessFactor( unitSystem );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimSegmentInterval*> RimSegmentCollection::intervals() const
{
return m_segmentIntervals.childrenByType();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
caf::PdmChildArrayField<RimSegmentInterval*>& RimSegmentCollection::intervalsField()
{
return m_segmentIntervals;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RimSegmentInterval* RimSegmentCollection::createInterval( double startMD, double endMD, double diameter, double roughness )
{
auto* interval = new RimSegmentInterval;
interval->setStartMD( startMD );
interval->setEndMD( endMD );
interval->setDiameter( diameter );
interval->setRoughnessFactor( roughness );
addInterval( interval );
return interval;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::addInterval( RimSegmentInterval* interval )
{
m_segmentIntervals.push_back( interval );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::removeInterval( RimSegmentInterval* interval )
{
m_segmentIntervals.removeChild( interval );
delete interval;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::removeAllIntervals()
{
m_segmentIntervals.deleteChildren();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSegmentCollection::hasIntervals() const
{
return !m_segmentIntervals.empty();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::updateOverlapVisualFeedback()
{
auto segmentIntervals = intervals();
for ( auto* interval : segmentIntervals )
{
bool hasOverlap = std::ranges::any_of( segmentIntervals,
[interval]( const RimSegmentInterval* other )
{ return interval != other && interval->overlaps( other ); } );
interval->updateOverlapVisualFeedback( hasOverlap );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<std::pair<double, double>> RimSegmentCollection::getSegmentIntervals() const
{
std::vector<std::pair<double, double>> result;
for ( auto* interval : intervals() )
{
if ( interval && interval->isValidInterval() ) result.emplace_back( interval->startMD(), interval->endMD() );
}
return result;
}
//--------------------------------------------------------------------------------------------------
/// Valid intervals with a fixed, min or max segment length rule, active on the export date if given
//--------------------------------------------------------------------------------------------------
std::vector<const RimSegmentInterval*> RimSegmentCollection::segmentationIntervals( const std::optional<QDateTime>& exportDate ) const
{
std::vector<const RimSegmentInterval*> result;
for ( auto* interval : intervals() )
{
if ( !interval || !interval->isValidInterval() ) continue;
if ( exportDate.has_value() && !interval->isActiveOnDate( *exportDate ) ) continue;
if ( interval->fixedSegmentLength().has_value() || interval->minSegmentLength().has_value() || interval->maxSegmentLength().has_value() )
result.push_back( interval );
}
return result;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool RimSegmentCollection::hasCustomSegmentIntervals() const
{
return hasIntervals();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::setUnitSystemSpecificDefaults()
{
auto* wellPath = firstAncestorOrThisOfTypeAsserted<RimWellPath>();
m_linerDiameter = defaultLinerDiameter( wellPath->unitSystem() );
m_roughnessFactor = defaultRoughnessFactor( wellPath->unitSystem() );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::updateFromTopLevelWell( const RimSegmentCollection* topLevelWellParameters )
{
m_refMDType = topLevelWellParameters->m_refMDType();
m_refMD = topLevelWellParameters->m_refMD();
m_compsegsSegmentNumber = topLevelWellParameters->m_compsegsSegmentNumber();
m_singleSegmentBeforeFirstPerforation = topLevelWellParameters->m_singleSegmentBeforeFirstPerforation();
m_singleSegmentAfterLastPerforation = topLevelWellParameters->m_singleSegmentAfterLastPerforation();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::importLegacyData( const RimMswCompletionParameters* legacyParameters )
{
if ( !legacyParameters ) return;
const bool hasLegacyData = legacyParameters->referenceMDType() != RimMswCompletionParameters::ReferenceMDType::AUTO_REFERENCE_MD ||
legacyParameters->storedReferenceMD() != 0.0 || legacyParameters->customValuesForLateral() ||
legacyParameters->linerDiameter() != defaultLinerDiameter( RiaDefines::EclipseUnitSystem::UNITS_METRIC ) ||
legacyParameters->roughnessFactor() != defaultRoughnessFactor( RiaDefines::EclipseUnitSystem::UNITS_METRIC ) ||
legacyParameters->diameterRoughnessMode() != RimMswCompletionParameters::DiameterRoughnessMode::UNIFORM ||
!legacyParameters->diameterRoughnessIntervals()->intervals().empty() ||
!legacyParameters->customSegmentIntervals()->intervals().empty();
if ( !hasLegacyData ) return;
m_refMDType = static_cast<ReferenceMDType>( static_cast<int>( legacyParameters->referenceMDType() ) );
m_refMD = legacyParameters->storedReferenceMD();
m_customValuesForLateral = legacyParameters->customValuesForLateral();
m_linerDiameter = legacyParameters->linerDiameter();
m_roughnessFactor = legacyParameters->roughnessFactor();
removeAllIntervals();
if ( legacyParameters->diameterRoughnessMode() == RimMswCompletionParameters::DiameterRoughnessMode::INTERVALS )
{
for ( auto* oldInterval : legacyParameters->diameterRoughnessIntervals()->intervals() )
{
auto* interval =
createInterval( oldInterval->startMD(), oldInterval->endMD(), oldInterval->diameter(), oldInterval->roughnessFactor() );
interval->enableCustomStartDate( oldInterval->useCustomStartDate() );
interval->setCustomStartDate( oldInterval->customStartDate() );
}
}
constexpr double boundTolerance = 1.0e-6;
for ( auto* oldInterval : legacyParameters->customSegmentIntervals()->intervals() )
{
const auto currentIntervals = intervals();
const auto matchingInterval =
std::ranges::find_if( currentIntervals,
[oldInterval]( const RimSegmentInterval* interval )
{
return std::abs( interval->startMD() - oldInterval->startMD() ) <= boundTolerance &&
std::abs( interval->endMD() - oldInterval->endMD() ) <= boundTolerance;
} );
if ( matchingInterval == currentIntervals.end() )
{
createInterval( oldInterval->startMD(), oldInterval->endMD(), legacyParameters->linerDiameter(), legacyParameters->roughnessFactor() );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::defaultLinerDiameter( RiaDefines::EclipseUnitSystem unitSystem )
{
return unitSystem == RiaDefines::EclipseUnitSystem::UNITS_METRIC ? 0.152 : 0.5;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
double RimSegmentCollection::defaultRoughnessFactor( RiaDefines::EclipseUnitSystem unitSystem )
{
return unitSystem == RiaDefines::EclipseUnitSystem::UNITS_METRIC ? 1.0e-5 : 3.28e-5;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue )
{
if ( changedField == &m_refMDType ) updateAllRequiredEditors();
updateMswSegments();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::childFieldChangedByUi( const caf::PdmFieldHandle* changedChildField )
{
updateMswSegments();
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::updateMswSegments()
{
if ( auto* wellPathCollection = RimWellPathCollection::instance() )
{
wellPathCollection->updateMswSegmentsForObject( this );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::appendMenuItems( caf::CmdFeatureMenuBuilder& menuBuilder ) const
{
menuBuilder << "RicCreateSegmentIntervalFeature";
if ( hasIntervals() ) menuBuilder << "RicDeleteSegmentIntervalFeature";
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering )
{
auto* wellPath = firstAncestorOrThisOfTypeAsserted<RimWellPath>();
const bool isMetric = wellPath->unitSystem() == RiaDefines::EclipseUnitSystem::UNITS_METRIC;
m_linerDiameter.uiCapability()->setUiName( isMetric ? "Liner Inner Diameter [m]" : "Liner Inner Diameter [ft]" );
m_roughnessFactor.uiCapability()->setUiName( isMetric ? "Roughness Factor [m]" : "Roughness Factor [ft]" );
if ( wellPath->isTopLevelWellPath() )
{
uiOrdering.add( &m_refMDType );
uiOrdering.add( &m_refMD );
m_refMD.uiCapability()->setUiHidden( m_refMDType == ReferenceMDType::AUTO_REFERENCE_MD );
}
else
{
uiOrdering.add( &m_customValuesForLateral );
}
auto* diameterGroup = uiOrdering.addNewGroup( "Diameter and Roughness" );
diameterGroup->add( &m_linerDiameter );
diameterGroup->add( &m_roughnessFactor );
if ( wellPath->isTopLevelWellPath() )
{
uiOrdering.add( &m_compsegsSegmentNumber );
auto* segmentationGroup = uiOrdering.addNewGroup( "Segmentation" );
segmentationGroup->add( &m_singleSegmentBeforeFirstPerforation );
segmentationGroup->add( &m_singleSegmentAfterLastPerforation );
}
const bool readOnly = !wellPath->isTopLevelWellPath() && !m_customValuesForLateral();
m_linerDiameter.uiCapability()->setUiReadOnly( readOnly );
m_roughnessFactor.uiCapability()->setUiReadOnly( readOnly );
m_segmentIntervals.uiCapability()->setUiReadOnly( readOnly );
uiOrdering.skipRemainingFields( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::defineUiTreeOrdering( caf::PdmUiTreeOrdering& uiTreeOrdering, QString uiConfigName )
{
for ( auto* interval : intervals() )
uiTreeOrdering.add( interval );
uiTreeOrdering.skipRemainingChildren( true );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RimSegmentCollection::initAfterRead()
{
if ( m_linerDiameter() == std::numeric_limits<double>::infinity() && m_roughnessFactor() == std::numeric_limits<double>::infinity() )
setUnitSystemSpecificDefaults();
}