Skip to content

Commit 0f7eab5

Browse files
feat: Add functions to connect well perforation to surface elements (#3359)
Co-authored-by: Jian HUANG <[email protected]>
1 parent 3a78f14 commit 0f7eab5

17 files changed

+376
-79
lines changed

.integrated_tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
baselines:
22
bucket: geosx
3-
baseline: integratedTests/baseline_integratedTests-pr3843-13975-76d125d
3+
baseline: integratedTests/baseline_integratedTests-pr3359-14024-3c9ebb4
44

55
allow_fail:
66
all: ''

BASELINE_NOTES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ This file is designed to track changes to the integrated test baselines.
66
Any developer who updates the baseline ID in the .integrated_tests.yaml file is expected to create an entry in this file with the pull request number, date, and their justification for rebaselining.
77
These notes should be in reverse-chronological order, and use the following time format: (YYYY-MM-DD).
88

9+
PR #3359 (2025-10-07) <https://storage.googleapis.com/geosx/integratedTests/baseline_integratedTests-pr3359-14024-3c9ebb4.tar.gz>
10+
=====================
11+
Add functions to connect well perforation to surface elements.
12+
913
PR #3843 (2025-10-02) <https://storage.googleapis.com/geosx/integratedTests/baseline_integratedTests-pr3843-13975-76d125d.tar.gz>
1014
=====================
1115
Fix linear solver issues.
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
<ConstantPermeability
3131
name="rockPerm"
32-
permeabilityComponents="{ 1.0e-18, 1.0e-18, 1.0e-18 }" />
32+
permeabilityComponents="{ 1.0e-14, 1.0e-14, 1.0e-14 }" />
3333
<!-- Material inside the fault -->
3434
<CompressibleSolidParallelPlatesPermeability
3535
name="faultFilling"
@@ -188,14 +188,15 @@
188188
logLevel="1"
189189
wellRegionName="wellRegion2"
190190
wellControlsName="wellControls2"
191-
polylineNodeCoords="{ { -5400, -5400, 0 },
192-
{ -5400, -5400, -2500 } }"
191+
polylineNodeCoords="{ { 1200, -700, 0 },
192+
{ 1200, -700, -2500 } }"
193193
polylineSegmentConn="{ { 0, 1 } }"
194194
radius="0.1"
195195
numElementsPerSegment="1">
196196
<Perforation
197197
name="injector1_perf1"
198-
distanceFromHead="2500"/>
198+
targetRegion="Fault"
199+
distanceFromHead="1700"/>
199200
</InternalWell>
200201
</VTKMesh>
201202
</Mesh>
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Problem>
22
<Included>
3-
<File name="./singlePhasePoromechanics_FaultModel_well_base.xml"/>
3+
<File name="./singlePhasePoromechanics_WellInFault_base.xml"/>
44
</Included>
55

66
<Solvers
@@ -20,7 +20,8 @@
2020
newtonMaxIter="20"
2121
maxAllowedResidualNorm="1e+25"/>
2222
<LinearSolverParameters
23-
solverType="direct"/>
23+
solverType="direct"
24+
directParallel="1"/>
2425
</SinglePhasePoromechanicsConformingFracturesReservoir>
2526

2627
<SinglePhasePoromechanicsConformingFractures
@@ -56,15 +57,15 @@
5657
control="BHP"
5758
referenceElevation="-2500"
5859
targetBHP="1e7"
59-
targetTotalRate="1e10" />
60+
targetTotalRate="1e-3" />
6061
<WellControls
6162
name="wellControls2"
6263
logLevel="2"
6364
type="injector"
6465
control="BHP"
6566
referenceElevation="-2500"
6667
targetBHP="10e7"
67-
targetTotalRate="1e10" />
68+
targetTotalRate="1e-3" />
6869
</SinglePhaseWell>
6970
</Solvers>
7071

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Problem>
22
<Included>
3-
<File name="./singlePhasePoromechanics_FaultModel_well_new_base.xml"/>
3+
<File name="./singlePhasePoromechanics_WellInFault_base.xml"/>
44
</Included>
55

66
<Solvers
@@ -20,7 +20,8 @@
2020
newtonTol="1e-3"
2121
newtonMaxIter="20"/>
2222
<LinearSolverParameters
23-
solverType="direct"/>
23+
solverType="direct"
24+
directParallel="1"/>
2425
</SinglePhaseReservoirPoromechanicsConformingFractures>
2526

2627
<SolidMechanicsLagrangeContact
@@ -38,6 +39,7 @@
3839
targetRegions="{ Region, Fault, wellRegion1, wellRegion2 }">
3940
<NonlinearSolverParameters
4041
newtonMaxIter="40"
42+
newtonTol="1e-4"
4143
maxAllowedResidualNorm="1e+25"/>
4244
<LinearSolverParameters
4345
directParallel="0"/>
@@ -60,15 +62,15 @@
6062
control="BHP"
6163
referenceElevation="-2500"
6264
targetBHP="1e7"
63-
targetTotalRate="1e10" />
65+
targetTotalRate="1e-3" />
6466
<WellControls
6567
name="wellControls2"
6668
logLevel="2"
6769
type="injector"
6870
control="BHP"
6971
referenceElevation="-2500"
7072
targetBHP="10e7"
71-
targetTotalRate="1e10" />
73+
targetTotalRate="1e-3" />
7274
</SinglePhaseWell>
7375
</Solvers>
7476

src/coreComponents/mainInterface/ProblemManager.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -863,11 +863,12 @@ void ProblemManager::generateMeshLevel( MeshLevel & meshLevel,
863863
elemRegionManager.forElementSubRegions< ElementSubRegionBase >( [&]( ElementSubRegionBase & subRegion )
864864
{
865865
subRegion.setupRelatedObjectsInRelations( meshLevel );
866+
// TODO calling calculateElementGeometricQuantities for `FaceElementSubRegion` here is not very accurate:
866867
// `FaceElementSubRegion` has no node and therefore needs the nodes positions from the neighbor elements
867868
// in order to compute the geometric quantities.
868869
// And this point of the process, the ghosting has not been done and some elements of the `FaceElementSubRegion`
869-
// can have no neighbor. Making impossible the computation, which is therfore postponed to after the ghosting.
870-
if( isBaseMeshLevel && !dynamicCast< FaceElementSubRegion * >( &subRegion ) )
870+
// can have no neighbor. We still call it only to compute element centers to be used for well perforation computations.
871+
if( isBaseMeshLevel ) // && !dynamicCast< FaceElementSubRegion * >( &subRegion ) )
871872
{
872873
subRegion.calculateElementGeometricQuantities( nodeManager, faceManager );
873874
}

src/coreComponents/mesh/DomainPartition.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,9 +247,10 @@ void DomainPartition::setupCommunications( bool use_nonblocking )
247247
{
248248
NodeManager & nodeManager = meshLevel.getNodeManager();
249249
FaceManager & faceManager = meshLevel.getFaceManager();
250+
ElementRegionManager & elemManager = meshLevel.getElemManager();
250251

251252
CommunicationTools::getInstance().setupGhosts( meshLevel, m_neighbors, use_nonblocking );
252-
faceManager.sortAllFaceNodes( nodeManager, meshLevel.getElemManager() );
253+
faceManager.sortAllFaceNodes( nodeManager, elemManager );
253254
faceManager.computeGeometry( nodeManager );
254255
}
255256
else if( !meshLevel.isShallowCopyOf( meshBody.getMeshLevels().getGroup< MeshLevel >( 0 )) )

src/coreComponents/mesh/ElementRegionManager.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,11 @@ void ElementRegionManager::generateWells( CellBlockManagerABC const & cellBlockM
203203
// generate the local data (well elements, nodes, perforations) on this well
204204
// note: each MPI rank knows the global info on the entire well (constructed earlier in InternalWellGenerator)
205205
// so we only need node and element offsets to construct the local-to-global maps in each wellElemSubRegion
206-
wellRegion.generateWell( meshLevel, lineBlock, nodeOffsetGlobal + wellNodeCount, elemOffsetGlobal + wellElemCount );
206+
wellRegion.generateWell( meshLevel,
207+
lineBlock,
208+
nodeOffsetGlobal + wellNodeCount,
209+
elemOffsetGlobal + wellElemCount,
210+
cellBlockManager.getGlobalLength() );
207211

208212
// increment counters with global number of nodes and elements
209213
wellElemCount += lineBlock.numElements();

src/coreComponents/mesh/ElementSubRegionBase.hpp

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,14 +279,45 @@ class ElementSubRegionBase : public ObjectManagerBase
279279

280280
forAll< parallelHostPolicy >( size(), [=]( localIndex const k )
281281
{
282-
LvArray::tensorOps::copy< 3 >( elementCenters[k], X[e2n( k, 0 )] );
282+
// collect node coordinates for element k
283283
localIndex const numNodes = this->numNodesPerElement( k );
284-
for( localIndex a = 1; a < numNodes; ++a )
284+
std::vector< std::array< real64, 3 > > nodes;
285+
nodes.reserve( numNodes );
286+
for( localIndex a = 0; a < numNodes; ++a )
285287
{
286-
LvArray::tensorOps::add< 3 >( elementCenters[k], X[e2n( k, a )] );
288+
localIndex const nA = e2n( k, a );
289+
nodes.push_back( { X( nA, 0 ), X( nA, 1 ), X( nA, 2 ) } );
287290
}
288291

289-
LvArray::tensorOps::scale< 3 >( elementCenters[k], 1.0 / numNodes );
292+
// sort + unique with tolerance to remove near-duplicates (stable and robust for floating point)
293+
auto cmpLex = []( auto const & A, auto const & B )
294+
{
295+
return std::tie( A[0], A[1], A[2] ) < std::tie( B[0], B[1], B[2] );
296+
};
297+
const real64 tol = 1e-10;
298+
auto almostEqual = [tol]( auto const & A, auto const & B )
299+
{
300+
return ( std::abs( A[0] - B[0] ) < tol ) &&
301+
( std::abs( A[1] - B[1] ) < tol ) &&
302+
( std::abs( A[2] - B[2] ) < tol );
303+
};
304+
305+
std::sort( nodes.begin(), nodes.end(), cmpLex );
306+
nodes.erase( std::unique( nodes.begin(), nodes.end(), almostEqual ), nodes.end() );
307+
308+
// compute average (center) of unique nodes
309+
std::array< real64, 3 > centre = { 0.0, 0.0, 0.0 };
310+
for( auto const & p : nodes )
311+
{
312+
centre[0] += p[0];
313+
centre[1] += p[1];
314+
centre[2] += p[2];
315+
}
316+
const real64 inv = 1.0 / static_cast< real64 >( nodes.size() );
317+
318+
elementCenters[k][0] = centre[0] * inv;
319+
elementCenters[k][1] = centre[1] * inv;
320+
elementCenters[k][2] = centre[2] * inv;
290321
} );
291322
}
292323
};

src/coreComponents/mesh/EmbeddedSurfaceSubRegion.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,6 @@ EmbeddedSurfaceSubRegion::EmbeddedSurfaceSubRegion( string const & name,
4848
{
4949
m_elementType = ElementType::Polygon;
5050

51-
registerWrapper( viewKeyStruct::elementCenterString(), &m_elementCenter ).
52-
setDescription( "The center of each EmbeddedSurface element." );
53-
54-
registerWrapper( viewKeyStruct::elementVolumeString(), &m_elementVolume ).
55-
setApplyDefaultValue( -1.0 ).
56-
setPlotLevel( dataRepository::PlotLevel::LEVEL_0 ).
57-
setDescription( "The volume of each EmbeddedSurface element." );
58-
5951
registerWrapper( viewKeyStruct::connectivityIndexString(), &m_connectivityIndex ).
6052
setApplyDefaultValue( 1 ).
6153
setDescription( "Connectivity index of each EmbeddedSurface." );

0 commit comments

Comments
 (0)