diff --git a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_new_base.xml b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_new_base.xml index f91d3f1e8f..c6bbab3527 100644 --- a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_new_base.xml +++ b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_new_base.xml @@ -29,7 +29,7 @@ + permeabilityComponents="{ 1.0e-14, 1.0e-14, 1.0e-14 }" /> + targetRegion="Fault" + distanceFromHead="1700"/> diff --git a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_seq_new_smoke.xml b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_seq_new_smoke.xml index 2f56fcd462..f3d621e13e 100644 --- a/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_seq_new_smoke.xml +++ b/inputFiles/poromechanicsFractures/singlePhasePoromechanics_FaultModel_well_seq_new_smoke.xml @@ -39,6 +39,7 @@ targetRegions="{ Region, Fault, wellRegion1, wellRegion2 }"> diff --git a/src/coreComponents/mesh/DomainPartition.cpp b/src/coreComponents/mesh/DomainPartition.cpp index befc10b485..b7c95962db 100644 --- a/src/coreComponents/mesh/DomainPartition.cpp +++ b/src/coreComponents/mesh/DomainPartition.cpp @@ -242,10 +242,11 @@ void DomainPartition::setupCommunications( bool use_nonblocking ) { NodeManager & nodeManager = meshLevel.getNodeManager(); FaceManager & faceManager = meshLevel.getFaceManager(); + ElementRegionManager & elemManager = meshLevel.getElemManager(); CommunicationTools::getInstance().setupGhosts( meshLevel, m_neighbors, use_nonblocking ); - faceManager.sortAllFaceNodes( nodeManager, meshLevel.getElemManager() ); - faceManager.computeGeometry( nodeManager ); + faceManager.sortAllFaceNodes( nodeManager, elemManager ); + faceManager.computeGeometry( nodeManager, elemManager ); } else if( !meshLevel.isShallowCopyOf( meshBody.getMeshLevels().getGroup< MeshLevel >( 0 )) ) { diff --git a/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.cpp b/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.cpp index 875d23b289..67ed74c2f8 100644 --- a/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.cpp +++ b/src/coreComponents/mesh/EmbeddedSurfaceSubRegion.cpp @@ -48,14 +48,6 @@ EmbeddedSurfaceSubRegion::EmbeddedSurfaceSubRegion( string const & name, { m_elementType = ElementType::Polygon; - registerWrapper( viewKeyStruct::elementCenterString(), &m_elementCenter ). - setDescription( "The center of each EmbeddedSurface element." ); - - registerWrapper( viewKeyStruct::elementVolumeString(), &m_elementVolume ). - setApplyDefaultValue( -1.0 ). - setPlotLevel( dataRepository::PlotLevel::LEVEL_0 ). - setDescription( "The volume of each EmbeddedSurface element." ); - registerWrapper( viewKeyStruct::connectivityIndexString(), &m_connectivityIndex ). setApplyDefaultValue( 1 ). setDescription( "Connectivity index of each EmbeddedSurface." ); diff --git a/src/coreComponents/mesh/FaceManager.cpp b/src/coreComponents/mesh/FaceManager.cpp index 044cd1beb4..b9e80a8ed2 100644 --- a/src/coreComponents/mesh/FaceManager.cpp +++ b/src/coreComponents/mesh/FaceManager.cpp @@ -208,7 +208,7 @@ void FaceManager::setGeometricalRelations( CellBlockManagerABC const & cellBlock if( isBaseMeshLevel ) { - computeGeometry( nodeManager ); + computeGeometry( nodeManager, elemRegionManager ); } } @@ -222,7 +222,8 @@ void FaceManager::setupRelatedObjectsInRelations( NodeManager const & nodeManage m_toElements.setElementRegionManager( elemRegionManager ); } -void FaceManager::computeGeometry( NodeManager const & nodeManager ) +void FaceManager::computeGeometry( NodeManager const & nodeManager, + ElementRegionManager const & elemManager ) { arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & X = nodeManager.referencePosition(); @@ -235,6 +236,11 @@ void FaceManager::computeGeometry( NodeManager const & nodeManager ) m_faceNormal[ faceIndex ] ); } ); + + elemManager.forElementSubRegions< CellElementSubRegion, FaceElementSubRegion >( [&] ( auto const & subRegion ) + { + subRegion.calculateElementCenters( X ); + } ); } void FaceManager::setIsExternal() @@ -263,11 +269,6 @@ void FaceManager::sortAllFaceNodes( NodeManager const & nodeManager, ArrayOfArraysView< localIndex > const facesToNodes = nodeList().toView(); - elemManager.forElementSubRegions< CellElementSubRegion, FaceElementSubRegion >( [&] ( auto const & subRegion ) - { - subRegion.calculateElementCenters( X ); - } ); - ElementRegionManager::ElementViewAccessor< arrayView2d< real64 const > > elemCenter = elemManager.constructArrayViewAccessor< real64, 2 >( ElementSubRegionBase::viewKeyStruct::elementCenterString() ); diff --git a/src/coreComponents/mesh/FaceManager.hpp b/src/coreComponents/mesh/FaceManager.hpp index 97fc818767..8136c88b0a 100644 --- a/src/coreComponents/mesh/FaceManager.hpp +++ b/src/coreComponents/mesh/FaceManager.hpp @@ -137,8 +137,10 @@ class FaceManager : public ObjectManagerBase /** * @brief Compute faces center, area and normal. * @param[in] nodeManager NodeManager associated with the current DomainPartition + * @param[in] elemManager element manager allowing access to the cell elements */ - void computeGeometry( NodeManager const & nodeManager ); + void computeGeometry( NodeManager const & nodeManager, + ElementRegionManager const & elemManager ); /** * @brief Builds the face-on-domain-boundary indicator. diff --git a/src/coreComponents/mesh/PerforationData.cpp b/src/coreComponents/mesh/PerforationData.cpp index 4363c2ac1c..852ba97230 100644 --- a/src/coreComponents/mesh/PerforationData.cpp +++ b/src/coreComponents/mesh/PerforationData.cpp @@ -233,23 +233,40 @@ void PerforationData::getReservoirElementDimensions( MeshLevel const & mesh, { ElementRegionManager const & elemManager = mesh.getElemManager(); NodeManager const & nodeManager = mesh.getNodeManager(); - CellElementRegion const & region = elemManager.getRegion< CellElementRegion >( er ); - CellElementSubRegion const & subRegion = region.getSubRegion< CellElementSubRegion >( esr ); - - // compute the bounding box of the element - real64 boxDims[ 3 ]; - computationalGeometry::getBoundingBox( ei, - subRegion.nodeList(), - nodeManager.referencePosition(), - boxDims ); - - // dx and dz from bounding box - dx = boxDims[ 0 ]; - dy = boxDims[ 1 ]; - - // dz is computed as vol / (dx * dy) - dz = subRegion.getElementVolume()[ei]; - dz /= dx * dy; + ElementRegionBase const & region = elemManager.getRegion< ElementRegionBase >( er ); + ElementSubRegionBase const & subRegionBase = region.getSubRegion< ElementSubRegionBase >( esr ); + + region.applyLambdaToContainer< CellElementSubRegion, SurfaceElementSubRegion >( subRegionBase, [&]( auto const & subRegion ) + { + // compute the bounding box of the element + real64 boxDims[ 3 ]; + computationalGeometry::getBoundingBox( ei, + subRegion.nodeList(), + nodeManager.referencePosition(), + boxDims ); + + // dx and dz from bounding box + dx = boxDims[ 0 ]; + dy = boxDims[ 1 ]; + dz = boxDims[ 2 ]; + + if( dx < 1e-10 ) + { + dx = subRegion.getElementVolume()[ei]; + dx /= dy * dz; + } + else if( dy < 1e-10 ) + { + dy = subRegion.getElementVolume()[ei]; + dy /= dx * dz; + } + else + { + // dz is computed as vol / (dx * dy) + dz = subRegion.getElementVolume()[ei]; + dz /= dx * dy; + } + } ); } void PerforationData::connectToWellElements( LineBlockABC const & lineBlock, diff --git a/src/coreComponents/mesh/WellElementSubRegion.cpp b/src/coreComponents/mesh/WellElementSubRegion.cpp index c16ea1c6d0..85c3a4bf69 100644 --- a/src/coreComponents/mesh/WellElementSubRegion.cpp +++ b/src/coreComponents/mesh/WellElementSubRegion.cpp @@ -21,6 +21,7 @@ #include "common/MpiWrapper.hpp" #include "LvArray/src/output.hpp" +#include namespace geos { @@ -143,7 +144,6 @@ bool isPointInsideElement( SUBREGION_TYPE const & GEOS_UNUSED_PARAM( subRegion ) arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & GEOS_UNUSED_PARAM( referencePosition ), localIndex const & GEOS_UNUSED_PARAM( eiLocal ), ArrayOfArraysView< localIndex const > const & GEOS_UNUSED_PARAM( facesToNodes ), - real64 const (&GEOS_UNUSED_PARAM( elemCenter ))[3], real64 const (&GEOS_UNUSED_PARAM( location ))[3] ) { // only CellElementSubRegion is currently supported @@ -154,10 +154,13 @@ bool isPointInsideElement( CellElementSubRegion const & subRegion, arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & referencePosition, localIndex const & eiLocal, ArrayOfArraysView< localIndex const > const & facesToNodes, - real64 const (&elemCenter)[3], real64 const (&location)[3] ) { arrayView2d< localIndex const > const elemsToFaces = subRegion.faceList(); + arrayView2d< real64 const > const elemCenters = subRegion.getElementCenter(); + real64 const elemCenter[3] = { elemCenters[eiLocal][0], + elemCenters[eiLocal][1], + elemCenters[eiLocal][2] }; return computationalGeometry::isPointInsidePolyhedron( referencePosition, elemsToFaces[eiLocal], facesToNodes, @@ -165,6 +168,58 @@ bool isPointInsideElement( CellElementSubRegion const & subRegion, location ); } +// Define a hash function +template< typename POINT_TYPE > +struct PointHash +{ + std::size_t operator()( POINT_TYPE const point ) const + { + std::size_t h1 = std::hash< real64 >()( point[0] ); + std::size_t h2 = std::hash< real64 >()( point[1] ); + std::size_t h3 = std::hash< real64 >()( point[2] ); + return h1 ^ (h2 << 1) ^ (h3 << 2); + } +}; + +// Define equality operator +template< typename POINT_TYPE > +struct PointsEqual +{ + bool operator()( POINT_TYPE const & p1, POINT_TYPE const & p2 ) const + { + return (std::abs( p1[0] - p2[0] ) < 1e-10) && (std::abs( p1[1] - p2[1] ) < 1e-10) && (std::abs( p1[2] - p2[2] ) < 1e-10); + } +}; + +bool isPointInsideElement( SurfaceElementSubRegion const & subRegion, + arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & referencePosition, + localIndex const & eiLocal, + ArrayOfArraysView< localIndex const > const & GEOS_UNUSED_PARAM( facesToNodes ), + real64 const (&location)[3] ) +{ + typedef std::array< real64, 3 > Point3d; + + // collect element nodes + integer const nV = subRegion.numNodesPerElement( eiLocal ); + SurfaceElementSubRegion::NodeMapType const & nodeList = subRegion.nodeList(); + std::vector< Point3d > polygon( nV ); + for( integer i = 0; i < nV; ++i ) + { + for( integer j = 0; j < 3; ++j ) + { + polygon[i][j] = referencePosition[nodeList( eiLocal, i )][j]; + } + } + + // remove duplicates + std::unordered_set< Point3d, PointHash< Point3d >, PointsEqual< Point3d > > + unique_points( polygon.begin(), polygon.end()); + polygon.clear(); + std::copy( unique_points.begin(), unique_points.end(), std::back_inserter( polygon )); + + return computationalGeometry::isPointInPolygon3d( polygon, polygon.size(), location ); +} + /** * @brief Search the reservoir elements that can be accessed from the set "nodes". Stop if a reservoir element containing the perforation is found. @@ -230,8 +285,6 @@ bool visitNeighborElements( MeshLevel const & mesh, ElementRegionBase const & region = elemManager.getRegion< ElementRegionBase >( er ); SUBREGION_TYPE const & subRegion = region.getSubRegion< SUBREGION_TYPE >( esr ); - arrayView2d< real64 const > const elemCenters = subRegion.getElementCenter(); - globalIndex const eiGlobal = subRegion.localToGlobalMap()[eiLocal]; // if this element has not been visited yet, save it @@ -239,13 +292,9 @@ bool visitNeighborElements( MeshLevel const & mesh, { elements.insert( eiGlobal ); - real64 const elemCenter[3] = { elemCenters[eiLocal][0], - elemCenters[eiLocal][1], - elemCenters[eiLocal][2] }; - // perform the test to see if the point is in this reservoir element // if the point is in the resevoir element, save the indices and stop the search - if( isPointInsideElement( subRegion, referencePosition, eiLocal, facesToNodes, elemCenter, location ) ) + if( isPointInsideElement( subRegion, referencePosition, eiLocal, facesToNodes, location ) ) { eiMatched = eiLocal; giMatched = eiGlobal; @@ -288,6 +337,7 @@ void initializeLocalSearch( MeshLevel const & mesh, localIndex & eiInit ) { ElementSubRegionBase const & subRegion = mesh.getElemManager().getRegion( targetRegionIndex ).getSubRegion( targetSubRegionIndex ); + ElementRegionManager::ElementViewAccessor< arrayView2d< real64 const > > resElemCenter = mesh.getElemManager().constructViewAccessor< array2d< real64 >, arrayView2d< real64 const > >( ElementSubRegionBase::viewKeyStruct::elementCenterString() ); diff --git a/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp b/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp index d9c054d340..fe9dca9067 100644 --- a/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp +++ b/src/coreComponents/mesh/utilities/ComputationalGeometry.hpp @@ -433,6 +433,124 @@ bool isPointInsidePolyhedron( arrayView2d< real64 const, nodes::REFERENCE_POSITI return true; } +/** + * @brief Check if a point is inside a polygon (2D version) + * @tparam POLYGON_TYPE type of @p polygon + * @tparam POINT_TYPE type of @p point + * @param[in] polygon array of ploygon nodes coordinates + * @param[in] n number of polygon nodes + * @param[in] point coordinates of the query point + * @return whether the point is inside + */ +template< typename POLYGON_TYPE, typename POINT_TYPE > +bool isPointInPolygon2d( POLYGON_TYPE const & polygon, integer n, POINT_TYPE const & point ) +{ + integer count = 0; + + for( integer i = 0; i < n; i++ ) + { + auto const & p1 = polygon[i]; + auto const & p2 = polygon[(i + 1) % n]; + + if((point[1] > std::min( p1[1], p2[1] )) && + (point[1] <= std::max( p1[1], p2[1] )) && + (point[0] <= std::max( p1[0], p2[0] ))) + { + real64 const xIntersect = (point[1] - p1[1]) * (p2[0] - p1[0]) / (p2[1] - p1[1]) + p1[0]; + if( std::abs( p1[0] - p2[0] ) < 1e-10 || point[0] <= xIntersect ) + { + count++; + } + } + } + + return count % 2 == 1; +} + +/** + * @brief Check if a point is inside a polygon (3D version) + * @tparam POLYGON_TYPE type of @p polygon + * @tparam POINT_TYPE type of @p point + * @param[in] polygon array of ploygon nodes coordinates + * @param[in] n number of polygon nodes + * @param[in] point coordinates of the query point + * @return whether the point is inside + */ +template< typename POLYGON_TYPE, typename POINT_TYPE > +bool isPointInPolygon3d( POLYGON_TYPE const & polygon, integer const n, POINT_TYPE const & point ) +{ + // Check if the point lies in the plane of the polygon + auto const & p0 = polygon[0]; + POINT_TYPE normal = {0, 0, 0}; + for( integer i = 1; i < n - 1; i++ ) + { + auto const & p1 = polygon[i]; + auto const & p2 = polygon[i + 1]; + normal[0] += (p1[1] - p0[1]) * (p2[2] - p0[2]) - (p1[2] - p0[2]) * (p2[1] - p0[1]); + normal[1] += (p1[2] - p0[2]) * (p2[0] - p0[0]) - (p1[0] - p0[0]) * (p2[2] - p0[2]); + normal[2] += (p1[0] - p0[0]) * (p2[1] - p0[1]) - (p1[1] - p0[1]) * (p2[0] - p0[0]); + } + + real64 d = -(normal[0] * p0[0] + normal[1] * p0[1] + normal[2] * p0[2]); + real64 dist = normal[0] * point[0] + normal[1] * point[1] + normal[2] * point[2] + d; + + if( std::abs( dist ) > 1e-6 ) + { + return false; + } + + // Determine the dominant component of the normal vector + int dominantIndex = 0; + if( std::abs( normal[1] ) > std::abs( normal[0] )) + { + dominantIndex = 1; + } + if( std::abs( normal[2] ) > std::abs( normal[dominantIndex] )) + { + dominantIndex = 2; + } + + // Project the polygon and the point onto a 2D plane + POLYGON_TYPE projectedPolygon( n ); + POINT_TYPE projectedPoint; + for( integer i = 0; i < n; i++ ) + { + projectedPolygon[i][0] = polygon[i][1]; + projectedPolygon[i][1] = polygon[i][2]; + } + if( dominantIndex == 0 ) // X is dominant, project onto YZ plane + { + for( int i = 0; i < n; i++ ) + { + projectedPolygon[i][0] = polygon[i][1]; + projectedPolygon[i][1] = polygon[i][2]; + } + projectedPoint[0] = point[1]; + projectedPoint[1] = point[2]; + } + else if( dominantIndex == 1 ) // Y is dominant, project onto XZ plane + { + for( int i = 0; i < n; i++ ) + { + projectedPolygon[i][0] = polygon[i][0]; + projectedPolygon[i][1] = polygon[i][2]; + } + projectedPoint[0] = point[0]; + projectedPoint[1] = point[2]; + } + else // Z is dominant, project onto XY plane + { + for( int i = 0; i < n; i++ ) + { + projectedPolygon[i][0] = polygon[i][0]; + projectedPolygon[i][1] = polygon[i][1]; + } + projectedPoint[0] = point[0]; + projectedPoint[1] = point[1]; + } + + return isPointInPolygon2d( projectedPolygon, n, projectedPoint ); +} /** * @brief Method to perform lexicographic comparison of two nodes based on coordinates. @@ -839,10 +957,10 @@ bool isPointInsideConvexPolyhedronRobust( localIndex element, * @param[in] pointCoordinates the vertices coordinates. * @param[out] boxDims The dimensions of the bounding box. */ -template< typename VEC_TYPE > +template< typename NODE_MAP_TYPE, typename VEC_TYPE > GEOS_HOST_DEVICE void getBoundingBox( localIndex const elemIndex, - arrayView2d< localIndex const, cells::NODE_MAP_USD > const & pointIndices, + NODE_MAP_TYPE const & pointIndices, arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const & pointCoordinates, VEC_TYPE && boxDims ) { @@ -855,7 +973,7 @@ void getBoundingBox( localIndex const elemIndex, LvArray::tensorOps::fill< 3 >( boxDims, LvArray::NumericLimits< real64 >::lowest ); // loop over all the vertices of the element to get the min and max coords - for( localIndex a = 0; a < pointIndices.size( 1 ); ++a ) + for( localIndex a = 0; a < pointIndices[elemIndex].size(); ++a ) { localIndex const id = pointIndices( elemIndex, a ); for( localIndex d = 0; d < 3; ++d )