///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2018- 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 // for more details. // ///////////////////////////////////////////////////////////////////////////////// #include "RimMultipleValveLocations.h" #include "RigWellPath.h" #include "RimFishbonesMultipleSubs.h" #include "RimPerforationInterval.h" #include "RimWellPath.h" #include "RimWellPathValve.h" #include "cafPdmUiDoubleValueEditor.h" #include "cafPdmUiListEditor.h" #include CAF_PDM_SOURCE_INIT( RimMultipleValveLocations, "RimMultipleValveLocations" ); namespace caf { template <> void AppEnum::setUp() { addItem( RimMultipleValveLocations::VALVE_COUNT, "VALVE_COUNT", "Start/End/Number" ); addItem( RimMultipleValveLocations::VALVE_SPACING, "VALVE_SPACING", "Start/End/Spacing" ); addItem( RimMultipleValveLocations::VALVE_CUSTOM, "VALVE_CUSTOM", "User Specification" ); setDefault( RimMultipleValveLocations::VALVE_COUNT ); } } // namespace caf //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RimMultipleValveLocations::RimMultipleValveLocations() { CAF_PDM_InitObject( "RimMultipleValveLocations", ":/FishBoneGroup16x16.png", "", "" ); CAF_PDM_InitField( &m_locationType, "LocationMode", caf::AppEnum( VALVE_COUNT ), "Location Defined By", "", "", "" ); CAF_PDM_InitField( &m_rangeStart, "RangeStart", 100.0, "Start MD [m]", "", "", "" ); m_rangeStart.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_rangeEnd, "RangeEnd", 250.0, "End MD [m]", "", "", "" ); m_rangeEnd.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); CAF_PDM_InitFieldNoDefault( &m_rangeValveSpacing, "ValveSpacing", "Spacing [m]", "", "", "" ); m_rangeValveSpacing.uiCapability()->setUiEditorTypeName( caf::PdmUiDoubleValueEditor::uiEditorTypeName() ); CAF_PDM_InitField( &m_rangeValveCount, "RangeValveCount", 13, "Number of Valves", "", "", "" ); CAF_PDM_InitFieldNoDefault( &m_locationOfValves, "LocationOfValves", "Measured Depths [m]", "", "", "" ); m_locationOfValves.uiCapability()->setUiEditorTypeName( caf::PdmUiListEditor::uiEditorTypeName() ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimMultipleValveLocations::perforationIntervalUpdated() { double existingRangeStart = m_rangeStart(); double existingRangeEnd = m_rangeEnd(); m_rangeStart = cvf::Math::clamp( m_rangeStart(), perforationStartMD(), perforationEndMD() ); m_rangeEnd = cvf::Math::clamp( m_rangeEnd(), perforationStartMD(), perforationEndMD() ); if ( existingRangeStart != m_rangeStart() || existingRangeEnd != m_rangeEnd() ) { computeRangesAndLocations(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimMultipleValveLocations::measuredDepth( size_t valveIndex ) const { CVF_ASSERT( valveIndex < m_locationOfValves().size() ); return m_locationOfValves()[valveIndex]; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimMultipleValveLocations::rangeStart() const { return m_rangeStart; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimMultipleValveLocations::rangeEnd() const { return m_rangeEnd; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const std::vector& RimMultipleValveLocations::valveLocations() const { return m_locationOfValves(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimMultipleValveLocations::setLocationType( LocationType locationType ) { m_locationType = locationType; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimMultipleValveLocations::computeRangesAndLocations() { if ( m_locationType == VALVE_COUNT ) { int divisor = 1; if ( m_rangeValveCount > 2 ) divisor = m_rangeValveCount - 1; m_rangeValveSpacing = std::abs( m_rangeStart - m_rangeEnd ) / divisor; if ( m_rangeValveSpacing < minimumSpacingMeters() ) { m_rangeValveSpacing = minimumSpacingMeters(); m_rangeValveCount = rangeCountFromSpacing(); } } else if ( m_locationType == VALVE_SPACING ) { m_rangeValveCount = rangeCountFromSpacing(); } if ( m_locationType == VALVE_COUNT || m_locationType == VALVE_SPACING ) { std::vector validMeasuredDepths; { RimWellPath* wellPath = nullptr; this->firstAncestorOrThisOfTypeAsserted( wellPath ); RigWellPath* rigWellPathGeo = wellPath->wellPathGeometry(); if ( rigWellPathGeo && rigWellPathGeo->m_measuredDepths.size() > 1 ) { double firstWellPathMD = rigWellPathGeo->m_measuredDepths.front(); double lastWellPathMD = rigWellPathGeo->m_measuredDepths.back(); double overlapStart = std::max( firstWellPathMD, m_rangeStart() ); double overlapEnd = std::min( lastWellPathMD, m_rangeEnd() ); double overlap = std::max( 0.0, overlapEnd - overlapStart ); if ( overlap ) { for ( auto md : locationsFromStartSpacingAndCount( overlapStart, m_rangeValveSpacing, m_rangeValveCount ) ) { validMeasuredDepths.push_back( md ); } } } } m_locationOfValves = validMeasuredDepths; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimMultipleValveLocations::initFields( LocationType locationType, double rangeStart, double rangeEnd, double valveSpacing, int valveCount, const std::vector& locationOfValves ) { if ( locationType != VALVE_UNDEFINED ) { m_locationType = locationType; } if ( rangeStart != std::numeric_limits::infinity() ) { m_rangeStart = rangeStart; } if ( rangeEnd != std::numeric_limits::infinity() ) { m_rangeEnd = rangeEnd; } if ( valveSpacing != std::numeric_limits::infinity() ) { m_rangeValveSpacing = valveSpacing; } if ( valveCount != -1 ) { m_rangeValveCount = valveCount; } if ( !locationOfValves.empty() ) { m_locationOfValves = locationOfValves; } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimMultipleValveLocations::defineUiOrdering( QString uiConfigName, caf::PdmUiOrdering& uiOrdering ) { { RimWellPath* wellPath; firstAncestorOrThisOfType( wellPath ); if ( wellPath ) { if ( wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_METRIC ) { m_locationOfValves.uiCapability()->setUiName( "Measured Depths [m]" ); m_rangeStart.uiCapability()->setUiName( "Start MD [m]" ); m_rangeEnd.uiCapability()->setUiName( "End MD [m]" ); m_rangeValveSpacing.uiCapability()->setUiName( "Spacing [m]" ); } else if ( wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_FIELD ) { m_locationOfValves.uiCapability()->setUiName( "Measured Depths [ft]" ); m_rangeStart.uiCapability()->setUiName( "Start MD [ft]" ); m_rangeEnd.uiCapability()->setUiName( "End MD [ft]" ); m_rangeValveSpacing.uiCapability()->setUiName( "Spacing [ft]" ); } } } { uiOrdering.add( &m_locationType ); if ( m_locationType() != VALVE_CUSTOM ) { uiOrdering.add( &m_rangeStart ); uiOrdering.add( &m_rangeEnd ); if ( m_locationType() == VALVE_COUNT ) { uiOrdering.add( &m_rangeValveCount ); uiOrdering.add( &m_rangeValveSpacing ); } else if ( m_locationType() == VALVE_SPACING ) { uiOrdering.add( &m_rangeValveSpacing ); uiOrdering.add( &m_rangeValveCount ); } } uiOrdering.add( &m_locationOfValves ); } if ( m_locationType() == VALVE_CUSTOM ) { m_locationOfValves.uiCapability()->setUiReadOnly( false ); m_rangeValveSpacing.uiCapability()->setUiReadOnly( true ); m_rangeValveCount.uiCapability()->setUiReadOnly( true ); m_rangeStart.uiCapability()->setUiReadOnly( true ); m_rangeEnd.uiCapability()->setUiReadOnly( true ); } else { m_locationOfValves.uiCapability()->setUiReadOnly( true ); m_rangeValveSpacing.uiCapability()->setUiReadOnly( false ); m_rangeValveCount.uiCapability()->setUiReadOnly( false ); m_rangeStart.uiCapability()->setUiReadOnly( false ); m_rangeEnd.uiCapability()->setUiReadOnly( false ); if ( m_locationType() == VALVE_COUNT ) { m_rangeValveSpacing.uiCapability()->setUiReadOnly( true ); m_rangeValveCount.uiCapability()->setUiReadOnly( false ); } else { m_rangeValveSpacing.uiCapability()->setUiReadOnly( false ); m_rangeValveCount.uiCapability()->setUiReadOnly( true ); } } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RimMultipleValveLocations::fieldChangedByUi( const caf::PdmFieldHandle* changedField, const QVariant& oldValue, const QVariant& newValue ) { bool recomputeLocations = false; if ( changedField == &m_locationType ) { if ( m_locationType == VALVE_COUNT || m_locationType == VALVE_SPACING ) { recomputeLocations = true; } } if ( changedField == &m_rangeStart || changedField == &m_rangeEnd || changedField == &m_rangeValveCount || changedField == &m_rangeValveSpacing ) { recomputeLocations = true; m_rangeStart = cvf::Math::clamp( m_rangeStart(), perforationStartMD(), perforationEndMD() ); m_rangeEnd = cvf::Math::clamp( m_rangeEnd(), perforationStartMD(), perforationEndMD() ); } if ( changedField == &m_rangeValveSpacing ) { double minimumDistanceMeter = minimumSpacingMeters(); RimWellPath* wellPath = nullptr; this->firstAncestorOrThisOfTypeAsserted( wellPath ); if ( wellPath->unitSystem() == RiaEclipseUnitTools::UNITS_FIELD ) { double minimumDistanceFeet = RiaEclipseUnitTools::meterToFeet( minimumDistanceMeter ); m_rangeValveSpacing = cvf::Math::clamp( m_rangeValveSpacing(), minimumDistanceFeet, std::max( m_rangeValveSpacing(), minimumDistanceFeet ) ); } else { m_rangeValveSpacing = cvf::Math::clamp( m_rangeValveSpacing(), minimumDistanceMeter, std::max( m_rangeValveSpacing(), minimumDistanceMeter ) ); } } if ( recomputeLocations ) { computeRangesAndLocations(); } RimWellPathComponentInterface* parentCompletion = nullptr; this->firstAncestorOrThisOfType( parentCompletion ); caf::PdmObject* pdmParent = dynamic_cast( parentCompletion ); if ( recomputeLocations || changedField == &m_locationOfValves ) { if ( parentCompletion ) { RimFishbonesMultipleSubs* fishbones = dynamic_cast( parentCompletion ); RimWellPathValve* valve = dynamic_cast( parentCompletion ); if ( fishbones ) { fishbones->recomputeLateralLocations(); } else if ( valve ) { valve->multipleValveGeometryUpdated(); } } } if ( pdmParent ) { pdmParent->updateConnectedEditors(); } } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RimMultipleValveLocations::rangeCountFromSpacing() const { int rangeCount = ( std::fabs( m_rangeStart - m_rangeEnd ) / m_rangeValveSpacing ) + 1; if ( rangeCount < 1 ) { rangeCount = 1; } return rangeCount; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimMultipleValveLocations::minimumSpacingMeters() const { // Minimum distance between fishbones is 13.0m // Use 10.0m to allow for some flexibility return 10.0; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimMultipleValveLocations::perforationStartMD() const { const RimPerforationInterval* perfInterval = nullptr; this->firstAncestorOrThisOfType( perfInterval ); if ( perfInterval ) { return perfInterval->startMD(); } return 0.0; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RimMultipleValveLocations::perforationEndMD() const { const RimPerforationInterval* perfInterval = nullptr; this->firstAncestorOrThisOfType( perfInterval ); if ( perfInterval ) { return perfInterval->endMD(); } RimWellPath* wellPath = nullptr; this->firstAncestorOrThisOfTypeAsserted( wellPath ); RigWellPath* rigWellPathGeo = wellPath->wellPathGeometry(); if ( rigWellPathGeo && !rigWellPathGeo->m_measuredDepths.empty() ) { double lastWellPathMD = rigWellPathGeo->m_measuredDepths.back(); return lastWellPathMD; } return std::numeric_limits::infinity(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RimMultipleValveLocations::locationsFromStartSpacingAndCount( double start, double spacing, size_t count ) { std::vector measuredDepths; for ( size_t i = 0; i < count; i++ ) { measuredDepths.push_back( start + spacing * i ); } return measuredDepths; }