///////////////////////////////////////////////////////////////////////////////// // // Copyright (C) 2017 Statoil 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 "RigWellPathIntersectionTools.h" #include "RiaLogging.h" #include "RigCellGeometryTools.h" #include "RigEclipseCaseData.h" #include "RigEclipseWellLogExtractor.h" #include "RigMainGrid.h" #include "RigSimulationWellCoordsAndMD.h" #include "RigWellLogExtractionTools.h" #include "RigWellPath.h" #include "RimEclipseCase.h" //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RigWellPathIntersectionTools::findCellIntersectionInfosAlongPath( const RigEclipseCaseData* caseData, const QString& wellPathName, const std::vector& pathCoords, const std::vector& pathMds ) { std::vector intersectionInfos; if ( pathCoords.size() < 2 ) return intersectionInfos; cvf::ref dummyWellPath = new RigWellPath( pathCoords, pathMds ); std::string errorIdName = ( wellPathName + " " + caseData->ownerCase()->caseUserDescription() ).toStdString(); cvf::ref extractor = new RigEclipseWellLogExtractor( caseData, dummyWellPath.p(), errorIdName ); return extractor->cellIntersectionInfosAlongWellPath(); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::set RigWellPathIntersectionTools::findIntersectedGlobalCellIndicesForWellPath( const RigEclipseCaseData* caseData, const RigWellPath* wellPath ) { std::set globalCellIndices; if ( caseData ) { cvf::ref extractor = new RigEclipseWellLogExtractor( caseData, wellPath, caseData->ownerCase()->caseUserDescription().toStdString() ); std::vector intersections = extractor->cellIntersectionInfosAlongWellPath(); for ( const auto& intersection : intersections ) { globalCellIndices.insert( intersection.globCellIndex ); } } return globalCellIndices; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::set RigWellPathIntersectionTools::findIntersectedGlobalCellIndices( const RigEclipseCaseData* caseData, const std::vector& coords, const std::vector& measuredDepths ) { std::set globalCellIndices; if ( caseData ) { cvf::ref dummyWellPath; if ( measuredDepths.size() == coords.size() ) { dummyWellPath = new RigWellPath( coords, measuredDepths ); } else { RigSimulationWellCoordsAndMD helper( coords ); dummyWellPath = new RigWellPath( helper.wellPathPoints(), helper.measuredDepths() ); } globalCellIndices = findIntersectedGlobalCellIndicesForWellPath( caseData, dummyWellPath.p() ); } return globalCellIndices; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Vec3d RigWellPathIntersectionTools::calculateLengthInCell( const std::array& hexCorners, const cvf::Vec3d& startPoint, const cvf::Vec3d& endPoint ) { cvf::Vec3d vec = endPoint - startPoint; cvf::Vec3d iAxisDirection; cvf::Vec3d jAxisDirection; cvf::Vec3d kAxisDirection; RigCellGeometryTools::findCellLocalXYZ( hexCorners, iAxisDirection, jAxisDirection, kAxisDirection ); cvf::Mat3d localCellCoordinateSystem( iAxisDirection.x(), jAxisDirection.x(), kAxisDirection.x(), iAxisDirection.y(), jAxisDirection.y(), kAxisDirection.y(), iAxisDirection.z(), jAxisDirection.z(), kAxisDirection.z() ); auto signedVector = vec.getTransformedVector( localCellCoordinateSystem.getInverted() ); return { std::fabs( signedVector.x() ), std::fabs( signedVector.y() ), std::fabs( signedVector.z() ) }; } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- cvf::Vec3d RigWellPathIntersectionTools::calculateLengthInCell( const RigMainGrid* grid, size_t cellIndex, const cvf::Vec3d& startPoint, const cvf::Vec3d& endPoint ) { std::array hexCorners; grid->cellCornerVertices( cellIndex, hexCorners.data() ); return calculateLengthInCell( hexCorners, startPoint, endPoint ); } //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- std::vector RigWellPathIntersectionTools::buildContinuousIntersections( const std::vector& originalIntersections, const cvf::StructGridInterface* grid ) { std::vector intersectionsNoGap; if ( originalIntersections.empty() ) return intersectionsNoGap; for ( size_t i = 0; i < originalIntersections.size() - 1; i++ ) { const WellPathCellIntersectionInfo& current = originalIntersections[i]; const WellPathCellIntersectionInfo& next = originalIntersections[i + 1]; double distance = std::fabs( current.endMD - next.startMD ); double gapInGridThreshold = 0.1; if ( distance > gapInGridThreshold ) { WellPathCellIntersectionInfo extraIntersection; bool showDebugInfo = false; if ( showDebugInfo ) { QString ijkTextCurrent; { size_t i = 0, j = 0, k = 0; if ( grid ) { grid->ijkFromCellIndex( current.globCellIndex, &i, &j, &k ); } ijkTextCurrent = QString( "(%1 %2 %3)" ).arg( i + 1 ).arg( j + 1 ).arg( k + 1 ); } QString ijkTextNext; { size_t i = 0, j = 0, k = 0; if ( grid ) { grid->ijkFromCellIndex( next.globCellIndex, &i, &j, &k ); } ijkTextNext = QString( "(%1 %2 %3)" ).arg( i + 1 ).arg( j + 1 ).arg( k + 1 ); } QString text = QString( "Gap detected : Distance diff : %1, epsilon = %2\n Global Cell Index 1 : %3, " "IJK=%4, endMD : %5\n Global Cell Index 2 : %6, IJK=%7, startMD : %8" ) .arg( distance ) .arg( gapInGridThreshold ) .arg( current.globCellIndex ) .arg( ijkTextCurrent ) .arg( current.endMD ) .arg( next.globCellIndex ) .arg( ijkTextNext ) .arg( next.startMD ); RiaLogging::info( text ); } extraIntersection.globCellIndex = std::numeric_limits::max(); extraIntersection.startPoint = current.endPoint; extraIntersection.endPoint = next.startPoint; extraIntersection.startMD = current.endMD; extraIntersection.endMD = next.startMD; extraIntersection.intersectedCellFaceIn = cvf::StructGridInterface::oppositeFace( current.intersectedCellFaceOut ); extraIntersection.intersectedCellFaceOut = cvf::StructGridInterface::oppositeFace( next.intersectedCellFaceIn ); extraIntersection.intersectionLengthsInCellCS = cvf::Vec3d::ZERO; intersectionsNoGap.push_back( extraIntersection ); } intersectionsNoGap.push_back( current ); } if ( !originalIntersections.empty() ) { intersectionsNoGap.push_back( originalIntersections.back() ); } return intersectionsNoGap; }