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 )