///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2021- 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 "RicMswBranch.h" #include "RicMswCompletions.h" #include "RicMswSegment.h" #include "RimWellPath.h" #include //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RicMswBranch::RicMswBranch( const QString& label, const RimWellPath* wellPath, double initialMD, double initialTVD ) : RicMswItem( label ) , m_initialMD( initialMD ) , m_initialTVD( initialTVD ) , m_branchNumber( -1 ) , m_wellPath( wellPath ) { } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicMswBranch::addSegment( std::unique_ptr segment ) { m_segments.push_back( std::move( segment ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicMswBranch::insertAfterSegment( const RicMswSegment* insertAfter, std::unique_ptr insertItem ) { auto it = std::find_if( m_segments.begin(), m_segments.end(), [insertAfter]( auto& item ) { return item.get() == insertAfter; } ); m_segments.insert( it, std::move( insertItem ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicMswBranch::sortSegments() { std::stable_sort( m_segments.begin(), m_segments.end(), []( const std::unique_ptr& lhs, const std::unique_ptr& rhs ) { return *lhs < *rhs; } ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- const RimWellPath* RicMswBranch::wellPath() const { return m_wellPath; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RicMswBranch::startMD() const { return m_initialMD; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RicMswBranch::startTVD() const { return m_initialTVD; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RicMswBranch::endMD() const { if ( !m_segments.empty() ) { return m_segments.back()->endMD(); } return m_initialMD; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- double RicMswBranch::endTVD() const { if ( !m_segments.empty() ) { return m_segments.back()->endTVD(); } return m_initialTVD; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- int RicMswBranch::branchNumber() const { return m_branchNumber; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicMswBranch::setBranchNumber( int branchNumber ) { m_branchNumber = branchNumber; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicMswBranch::segments() const { std::vector allSegments; for ( const auto& segment : m_segments ) { allSegments.push_back( segment.get() ); } return allSegments; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicMswBranch::segments() { std::vector allSegments; for ( auto& segment : m_segments ) { allSegments.push_back( segment.get() ); } return allSegments; } //-------------------------------------------------------------------------------------------------- /// TODO: Marked as obsolete, delete if lowerMD variant works as expected //-------------------------------------------------------------------------------------------------- RicMswSegment* RicMswBranch::findClosestSegmentByMidpoint_obsolete( double measuredDepthLocation ) { if ( measuredDepthLocation < startMD() ) { return segmentCount() > 0 ? segments().front() : nullptr; } if ( measuredDepthLocation > endMD() ) { return segmentCount() > 0 ? segments().back() : nullptr; } RicMswSegment* closestSegment = nullptr; double smallestDistance = std::numeric_limits::infinity(); for ( auto seg : segments() ) { // WELSEGS is reported as the midpoint of the segment double midpointMD = 0.5 * ( seg->startMD() + seg->endMD() ); double candidateDistance = std::abs( midpointMD - measuredDepthLocation ); if ( candidateDistance < smallestDistance ) { closestSegment = seg; smallestDistance = candidateDistance; } } return closestSegment; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- RicMswSegment* RicMswBranch::findClosestSegmentWithLowerMD( double measuredDepthLocation ) { if ( measuredDepthLocation < startMD() ) { return segmentCount() > 0 ? segments().front() : nullptr; } if ( measuredDepthLocation > endMD() ) { return segmentCount() > 0 ? segments().back() : nullptr; } if ( segmentCount() > 0 ) { RicMswSegment* closestSegment = nullptr; double smallestDistance = std::numeric_limits::infinity(); for ( auto seg : segments() ) { // WELSEGS is reported as the midpoint of the segment double midpointMD = 0.5 * ( seg->startMD() + seg->endMD() ); // Use a signed difference to find the closest segment below the measured depth location double candidateDistance = measuredDepthLocation - midpointMD; if ( closestSegment == nullptr ) { closestSegment = seg; smallestDistance = std::fabs( candidateDistance ); } else if ( candidateDistance > 0.0 && candidateDistance < smallestDistance ) { closestSegment = seg; smallestDistance = std::fabs( candidateDistance ); } } return closestSegment; } return nullptr; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- size_t RicMswBranch::segmentCount() const { return m_segments.size(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicMswBranch::branches() const { std::vector branches; for ( const auto& branch : m_branches ) { branches.push_back( branch.get() ); } return branches; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicMswBranch::branches() { std::vector branches; for ( auto& branch : m_branches ) { branches.push_back( branch.get() ); } return branches; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- void RicMswBranch::addChildBranch( std::unique_ptr branch ) { m_branches.push_back( std::move( branch ) ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RicMswBranch::allSegmentsRecursively() { std::vector allSegments; { std::vector branchSegments = segments(); allSegments.insert( allSegments.begin(), branchSegments.begin(), branchSegments.end() ); for ( auto seg : branchSegments ) { for ( auto completion : seg->completions() ) { std::vector completionSegments = completion->allSegmentsRecursively(); allSegments.insert( allSegments.begin(), completionSegments.begin(), completionSegments.end() ); } } for ( auto subBranch : branches() ) { auto subBranchSegments = subBranch->allSegmentsRecursively(); allSegments.insert( allSegments.begin(), subBranchSegments.begin(), subBranchSegments.end() ); } return allSegments; } }