GEOS
SinglePhasePoromechanics_impl.hpp
Go to the documentation of this file.
1 /*
2  * ------------------------------------------------------------------------------------------------------------
3  * SPDX-License-Identifier: LGPL-2.1-only
4  *
5  * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
6  * Copyright (c) 2018-2024 TotalEnergies
7  * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
8  * Copyright (c) 2023-2024 Chevron
9  * Copyright (c) 2019- GEOS/GEOSX Contributors
10  * All rights reserved
11  *
12  * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
13  * ------------------------------------------------------------------------------------------------------------
14  */
15 
20 #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICS_IMPL_HPP_
21 #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICS_IMPL_HPP_
22 
23 #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp"
24 #include "finiteElement/BilinearFormUtilities.hpp"
25 #include "finiteElement/LinearFormUtilities.hpp"
29 
30 namespace geos
31 {
32 
33 namespace poromechanicsKernels
34 {
35 
36 template< typename SUBREGION_TYPE,
37  typename CONSTITUTIVE_TYPE,
38  typename FE_TYPE >
40 SinglePhasePoromechanics( NodeManager const & nodeManager,
41  EdgeManager const & edgeManager,
42  FaceManager const & faceManager,
43  localIndex const targetRegionIndex,
44  SUBREGION_TYPE const & elementSubRegion,
45  FE_TYPE const & finiteElementSpace,
46  CONSTITUTIVE_TYPE & inputConstitutiveType,
47  arrayView1d< globalIndex const > const inputDispDofNumber,
48  globalIndex const rankOffset,
50  arrayView1d< real64 > const inputRhs,
51  real64 const inputDt,
52  real64 const (&gravityVector)[3],
53  string const inputFlowDofKey,
54  integer const performStressInitialization,
55  string const fluidModelKey ):
56  Base( nodeManager,
57  edgeManager,
58  faceManager,
59  targetRegionIndex,
60  elementSubRegion,
61  finiteElementSpace,
62  inputConstitutiveType,
63  inputDispDofNumber,
64  rankOffset,
65  inputMatrix,
66  inputRhs,
67  inputDt,
68  gravityVector,
69  inputFlowDofKey,
70  fluidModelKey ),
71  m_fluidDensity( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).density() ),
72  m_fluidDensity_n( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).density_n() ),
73  m_dFluidDensity_dPressure( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).dDensity_dPressure() ),
74  m_performStressInitialization( performStressInitialization )
75 {}
76 
77 template< typename SUBREGION_TYPE,
78  typename CONSTITUTIVE_TYPE,
79  typename FE_TYPE >
84  localIndex const q,
85  StackVariables & stack ) const
86 {
87  real64 porosity = 0.0;
88  real64 porosity_n = 0.0;
89  real64 dPorosity_dVolStrain = 0.0;
90  real64 dPorosity_dPressure = 0.0;
91  real64 dPorosity_dTemperature = 0.0;
92  real64 dSolidDensity_dPressure = 0.0;
93 
94  // Step 1: call the constitutive model to evaluate the total stress and compute porosity
95  m_constitutiveUpdate.smallStrainUpdatePoromechanics( k, q,
96  m_dt,
97  m_pressure[k],
98  m_pressure_n[k],
99  stack.temperature,
100  stack.deltaTemperatureFromLastStep,
101  stack.strainIncrement,
102  stack.totalStress,
103  stack.dTotalStress_dPressure,
104  stack.dTotalStress_dTemperature,
105  stack.stiffness,
106  m_performStressInitialization,
107  porosity,
108  porosity_n,
109  dPorosity_dVolStrain,
110  dPorosity_dPressure,
111  dPorosity_dTemperature,
112  dSolidDensity_dPressure );
113 
114  // Step 2: compute the body force
115  computeBodyForce( k, q,
116  porosity,
117  dPorosity_dVolStrain,
118  dPorosity_dPressure,
119  dPorosity_dTemperature,
120  dSolidDensity_dPressure,
121  stack );
122 
123  // Step 3: compute fluid mass increment
124  computeFluidIncrement( k, q,
125  porosity,
126  porosity_n,
127  dPorosity_dVolStrain,
128  dPorosity_dPressure,
129  dPorosity_dTemperature,
130  stack );
131 }
132 
133 template< typename SUBREGION_TYPE,
134  typename CONSTITUTIVE_TYPE,
135  typename FE_TYPE >
140  localIndex const q,
141  real64 const & porosity,
142  real64 const & dPorosity_dVolStrain,
143  real64 const & dPorosity_dPressure,
144  real64 const & dPorosity_dTemperature,
145  real64 const & dSolidDensity_dPressure,
146  StackVariables & stack ) const
147 {
148  GEOS_UNUSED_VAR( dPorosity_dTemperature );
149 
150  real64 const mixtureDensity = ( 1.0 - porosity ) * m_solidDensity( k, q ) + porosity * m_fluidDensity( k, q );
151  real64 const dMixtureDens_dVolStrainIncrement = dPorosity_dVolStrain * ( -m_solidDensity( k, q ) + m_fluidDensity( k, q ) );
152  real64 const dMixtureDens_dPressure = dPorosity_dPressure * ( -m_solidDensity( k, q ) + m_fluidDensity( k, q ) )
153  + ( 1.0 - porosity ) * dSolidDensity_dPressure
154  + porosity * m_dFluidDensity_dPressure( k, q );
155 
156  LvArray::tensorOps::scaledCopy< 3 >( stack.bodyForce, m_gravityVector, mixtureDensity );
157  LvArray::tensorOps::scaledCopy< 3 >( stack.dBodyForce_dVolStrainIncrement, m_gravityVector, dMixtureDens_dVolStrainIncrement );
158  LvArray::tensorOps::scaledCopy< 3 >( stack.dBodyForce_dPressure, m_gravityVector, dMixtureDens_dPressure );
159 }
160 
161 template< typename SUBREGION_TYPE,
162  typename CONSTITUTIVE_TYPE,
163  typename FE_TYPE >
168  localIndex const q,
169  real64 const & porosity,
170  real64 const & porosity_n,
171  real64 const & dPorosity_dVolStrain,
172  real64 const & dPorosity_dPressure,
173  real64 const & dPorosity_dTemperature,
174  StackVariables & stack ) const
175 {
176  GEOS_UNUSED_VAR( dPorosity_dTemperature );
177 
178  stack.fluidMassIncrement = porosity * m_fluidDensity( k, q ) - porosity_n * m_fluidDensity_n( k, q );
179  stack.dFluidMassIncrement_dVolStrainIncrement = dPorosity_dVolStrain * m_fluidDensity( k, q );
180  stack.dFluidMassIncrement_dPressure = dPorosity_dPressure * m_fluidDensity( k, q ) + porosity * m_dFluidDensity_dPressure( k, q );
181 }
182 
183 template< typename SUBREGION_TYPE,
184  typename CONSTITUTIVE_TYPE,
185  typename FE_TYPE >
189 assembleMomentumBalanceTerms( real64 const ( &N )[numNodesPerElem],
190  real64 const ( &dNdX )[numNodesPerElem][3],
191  real64 const & detJxW,
192  StackVariables & stack ) const
193 {
194  using namespace PDEUtilities;
195 
196  constexpr FunctionSpace displacementTrialSpace = FE_TYPE::template getFunctionSpace< numDofPerTrialSupportPoint >();
197  constexpr FunctionSpace displacementTestSpace = displacementTrialSpace;
198  constexpr FunctionSpace pressureTrialSpace = FunctionSpace::P0;
199 
200  // Step 1: compute local linear momentum balance residual
201  LinearFormUtilities::compute< displacementTestSpace,
202  DifferentialOperator::SymmetricGradient >
203  (
204  stack.localResidualMomentum,
205  dNdX,
206  stack.totalStress,
207  -detJxW );
208 
209  LinearFormUtilities::compute< displacementTestSpace,
210  DifferentialOperator::Identity >
211  (
212  stack.localResidualMomentum,
213  N,
214  stack.bodyForce,
215  detJxW );
216 
217  // Step 2: compute local linear momentum balance residual derivatives with respect to displacement
218  BilinearFormUtilities::compute< displacementTestSpace,
219  displacementTrialSpace,
220  DifferentialOperator::SymmetricGradient,
221  DifferentialOperator::SymmetricGradient >
222  (
223  stack.dLocalResidualMomentum_dDisplacement,
224  dNdX,
225  stack.stiffness, // fourth-order tensor handled via DiscretizationOps
226  dNdX,
227  -detJxW );
228 
229  BilinearFormUtilities::compute< displacementTestSpace,
230  displacementTrialSpace,
231  DifferentialOperator::Identity,
232  DifferentialOperator::Divergence >
233  (
234  stack.dLocalResidualMomentum_dDisplacement,
235  N,
236  stack.dBodyForce_dVolStrainIncrement,
237  dNdX,
238  detJxW );
239 
240  // Step 3: compute local linear momentum balance residual derivatives with respect to pressure
241  BilinearFormUtilities::compute< displacementTestSpace,
242  pressureTrialSpace,
243  DifferentialOperator::SymmetricGradient,
244  DifferentialOperator::Identity >
245  (
246  stack.dLocalResidualMomentum_dPressure,
247  dNdX,
248  stack.dTotalStress_dPressure,
249  1.0,
250  -detJxW );
251 
252  BilinearFormUtilities::compute< displacementTestSpace,
253  pressureTrialSpace,
254  DifferentialOperator::Identity,
255  DifferentialOperator::Identity >
256  (
257  stack.dLocalResidualMomentum_dPressure,
258  N,
259  stack.dBodyForce_dPressure,
260  1.0,
261  detJxW );
262 }
263 
264 template< typename SUBREGION_TYPE,
265  typename CONSTITUTIVE_TYPE,
266  typename FE_TYPE >
270 assembleElementBasedFlowTerms( real64 const ( &dNdX )[numNodesPerElem][3],
271  real64 const & detJxW,
272  StackVariables & stack ) const
273 {
274  using namespace PDEUtilities;
275 
276  constexpr FunctionSpace displacementTrialSpace = FE_TYPE::template getFunctionSpace< numDofPerTrialSupportPoint >();
277  constexpr FunctionSpace pressureTrialSpace = FunctionSpace::P0;
278  constexpr FunctionSpace pressureTestSpace = pressureTrialSpace;
279 
280  // Step 1: compute local mass balance residual
281  LinearFormUtilities::compute< pressureTestSpace,
282  DifferentialOperator::Identity >
283  (
284  stack.localResidualMass,
285  1.0,
286  stack.fluidMassIncrement,
287  detJxW );
288 
289  // Step 2: compute local mass balance residual derivatives with respect to displacement
290  BilinearFormUtilities::compute< pressureTestSpace,
291  displacementTrialSpace,
292  DifferentialOperator::Identity,
293  DifferentialOperator::Divergence >
294  (
296  1.0,
298  dNdX,
299  detJxW );
300 
301  // Step 3: compute local mass balance residual derivatives with respect to pressure
302  BilinearFormUtilities::compute< pressureTestSpace,
303  pressureTrialSpace,
304  DifferentialOperator::Identity,
305  DifferentialOperator::Identity >
306  (
308  1.0,
310  1.0,
311  detJxW );
312 }
313 
314 template< typename SUBREGION_TYPE,
315  typename CONSTITUTIVE_TYPE,
316  typename FE_TYPE >
321  localIndex const q,
322  StackVariables & stack ) const
323 {
324  // Governing equations (strong form)
325  // ---------------------------------
326  //
327  // divergence( totalStress ) + bodyForce = 0 (quasi-static linear momentum balance)
328  // dFluidMass_dTime + divergence( fluidMassFlux ) = source (fluid phase mass balance)
329  //
330  // with currently the following dependencies on the strainIncrement tensor and pressure
331  //
332  // totalStress = totalStress( strainIncrement, pressure)
333  // bodyForce = bodyForce( strainIncrement, pressure)
334  // fluidMass = fluidMass( strainIncrement, pressure)
335  // fluidMassFlux = fludiMassFlux( pressure)
336  //
337  // Note that the fluidMassFlux will depend on the strainIncrement if a stress-dependent constitutive
338  // model is assumed. A dependency on pressure can also occur in the source term of the mass
339  // balance equation, e.g. if a Peaceman well model is used.
340  //
341  // In this kernel cell-based contributions to Jacobian matrix and residual
342  // vector are computed. The face-based contributions, namely associated with the fluid
343  // mass flux term are computed in a different kernel. The source term in the mass balance
344  // equation is also treated elsewhere.
345  //
346  // Integration in time is performed using a backward Euler scheme (in the mass balance
347  // equation LHS and RHS are multiplied by the timestep).
348  //
349  // Using a weak formulation of the governing equation the following terms are assembled in this kernel
350  //
351  // Rmom = - \int symmetricGradient( \eta ) : totalStress + \int \eta \cdot bodyForce = 0
352  // Rmas = \int \chi ( fluidMass - fluidMass_n) = 0
353  //
354  // dRmom_dVolStrain = - \int_Omega symmetricGradient( \eta ) : dTotalStress_dVolStrain
355  // + \int \eta \cdot dBodyForce_dVolStrain
356  // dRmom_dPressure = - \int_Omega symmetricGradient( \eta ) : dTotalStress_dPressure
357  // + \int \eta \cdot dBodyForce_dPressure
358  // dRmas_dVolStrain = \int \chi dFluidMass_dVolStrain
359  // dRmas_dPressure = \int \chi dFluidMass_dPressure
360  //
361  // with \eta and \chi test basis functions for the displacement and pressure field, respectively.
362  // A continuous interpolation is used for the displacement, with \eta continuous finite element
363  // basis functions. A piecewise-constant approximation is used for the pressure.
364 
365  // Step 1: compute displacement finite element basis functions (N), basis function derivatives (dNdX), and
366  // determinant of the Jacobian transformation matrix times the quadrature weight (detJxW)
367  real64 N[numNodesPerElem]{};
368  real64 dNdX[numNodesPerElem][3]{};
369  FE_TYPE::calcN( q, stack.feStack, N );
370  real64 const detJxW = m_finiteElementSpace.template getGradN< FE_TYPE >( k, q, stack.xLocal,
371  stack.feStack, dNdX );
372 
373  // Step 2: compute strain increment
374  LvArray::tensorOps::fill< 6 >( stack.strainIncrement, 0.0 );
375  FE_TYPE::symmetricGradient( dNdX, stack.uhat_local, stack.strainIncrement );
376 
377  // Step 3: compute 1) the total stress, 2) the body force terms, and 3) the fluidMassIncrement
378  // using quantities returned by the PorousSolid constitutive model.
379  // This function also computes the derivatives of these three quantities wrt primary variables
380  smallStrainUpdate( k, q, stack );
381 
382  // Step 4: use the total stress and the body force to increment the local momentum balance residual
383  // This function also fills the local Jacobian rows corresponding to the momentum balance.
384  assembleMomentumBalanceTerms( N, dNdX, detJxW, stack );
385 
386  // Step 5: use the fluid mass increment to increment the local mass balance residual
387  // This function also fills the local Jacobian rows corresponding to the mass balance.
388  assembleElementBasedFlowTerms( dNdX, detJxW, stack );
389 }
390 
391 template< typename SUBREGION_TYPE,
392  typename CONSTITUTIVE_TYPE,
393  typename FE_TYPE >
397 complete( localIndex const k,
398  StackVariables & stack ) const
399 {
400  GEOS_UNUSED_VAR( k );
401  real64 maxForce = 0;
402  localIndex const numSupportPoints =
403  m_finiteElementSpace.template numSupportPoints< FE_TYPE >( stack.feStack );
404  integer numDisplacementDofs = numSupportPoints * numDofPerTestSupportPoint;
405 
406  for( int localNode = 0; localNode < numSupportPoints; ++localNode )
407  {
408  for( int dim = 0; dim < numDofPerTestSupportPoint; ++dim )
409  {
410 
411  localIndex const dof = LvArray::integerConversion< localIndex >( stack.localRowDofIndex[numDofPerTestSupportPoint*localNode + dim] - m_dofRankOffset );
412 
413  // we need this check to filter out ghost nodes in the assembly
414  if( dof < 0 || dof >= m_matrix.numRows() )
415  {
416  continue;
417  }
418  m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof,
419  stack.localRowDofIndex,
420  stack.dLocalResidualMomentum_dDisplacement[numDofPerTestSupportPoint * localNode + dim],
421  numDisplacementDofs );
422 
423  RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localResidualMomentum[numDofPerTestSupportPoint * localNode + dim] );
424  maxForce = fmax( maxForce, fabs( stack.localResidualMomentum[numDofPerTestSupportPoint * localNode + dim] ) );
425  m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof,
426  &stack.localPressureDofIndex,
427  stack.dLocalResidualMomentum_dPressure[numDofPerTestSupportPoint * localNode + dim],
428  1 );
429  }
430  }
431 
432  localIndex const dof = LvArray::integerConversion< localIndex >( stack.localPressureDofIndex - m_dofRankOffset );
433 
434  // we need this check to filter out ghost cells in the assembly
435  if( 0 <= dof && dof < m_matrix.numRows() )
436  {
437  m_matrix.template addToRowBinarySearchUnsorted< serialAtomic >( dof,
438  stack.localRowDofIndex,
440  numDisplacementDofs );
441  m_matrix.template addToRow< serialAtomic >( dof,
442  &stack.localPressureDofIndex,
444  1 );
445  RAJA::atomicAdd< serialAtomic >( &m_rhs[dof], stack.localResidualMass[0] );
446  }
447  return maxForce;
448 }
449 
450 template< typename SUBREGION_TYPE,
451  typename CONSTITUTIVE_TYPE,
452  typename FE_TYPE >
453 template< typename POLICY,
454  typename KERNEL_TYPE >
455 real64
457 kernelLaunch( localIndex const numElems,
458  KERNEL_TYPE const & kernelComponent )
459 {
461 
462  // Define a RAJA reduction variable to get the maximum residual contribution.
463  RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxResidual( 0 );
464 
465  forAll< POLICY >( numElems,
466  [=] GEOS_HOST_DEVICE ( localIndex const k )
467  {
468  typename KERNEL_TYPE::StackVariables stack;
469 
470  kernelComponent.setup( k, stack );
471  for( integer q=0; q<KERNEL_TYPE::numQuadraturePointsPerElem; ++q )
472  {
473  kernelComponent.quadraturePointKernel( k, q, stack );
474  }
475  maxResidual.max( kernelComponent.complete( k, stack ) );
476  } );
477  return maxResidual.get();
478 }
479 
480 
481 } // namespace poromechanicsKernels
482 
483 } // namespace geos
484 
485 #endif // GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_SINGLEPHASEPOROMECHANICS_IMPL_HPP_
#define GEOS_HOST_DEVICE
Marks a host-device function.
Definition: GeosxMacros.hpp:49
#define GEOS_UNUSED_VAR(...)
Mark an unused variable and silence compiler warnings.
Definition: GeosxMacros.hpp:84
#define GEOS_FORCE_INLINE
Marks a function or lambda for inlining.
Definition: GeosxMacros.hpp:51
#define GEOS_MARK_FUNCTION
Mark function with both Caliper and NVTX if enabled.
This class provides an interface to ObjectManagerBase in order to manage edge data.
Definition: EdgeManager.hpp:43
The FaceManager class provides an interface to ObjectManagerBase in order to manage face data.
Definition: FaceManager.hpp:44
The NodeManager class provides an interface to ObjectManagerBase in order to manage node data.
Definition: NodeManager.hpp:46
Implements kernels for solving quasi-static single-phase poromechanics.
GEOS_HOST_DEVICE void smallStrainUpdate(localIndex const k, localIndex const q, StackVariables &stack) const
Helper function to compute 1) the total stress, 2) the body force term, and 3) the fluidMassIncrement...
GEOS_HOST_DEVICE void computeFluidIncrement(localIndex const k, localIndex const q, real64 const &porosity, real64 const &porosity_n, real64 const &dPorosity_dVolStrain, real64 const &dPorosity_dPressure, real64 const &dPorosity_dTemperature, StackVariables &stack) const
Helper function to compute the fluid mass increment and its derivatives wrt primary variables.
static real64 kernelLaunch(localIndex const numElems, KERNEL_TYPE const &kernelComponent)
Kernel Launcher.
GEOS_HOST_DEVICE void computeBodyForce(localIndex const k, localIndex const q, real64 const &porosity, real64 const &dPorosity_dVolStrain, real64 const &dPorosity_dPressure, real64 const &dPorosity_dTemperature, real64 const &dSolidDensity_dPressure, StackVariables &stack) const
Helper function to compute the body force term (\rho g) and its derivatives wrt primary variables.
GEOS_HOST_DEVICE void assembleElementBasedFlowTerms(real64 const (&dNdX)[numNodesPerElem][3], real64 const &detJxW, StackVariables &stack) const
Assemble the local mass balance residual and derivatives using fluid mass/energy increment.
SinglePhasePoromechanics(NodeManager const &nodeManager, EdgeManager const &edgeManager, FaceManager const &faceManager, localIndex const targetRegionIndex, SUBREGION_TYPE const &elementSubRegion, FE_TYPE const &finiteElementSpace, CONSTITUTIVE_TYPE &inputConstitutiveType, arrayView1d< globalIndex const > const inputDispDofNumber, globalIndex const rankOffset, CRSMatrixView< real64, globalIndex const > const inputMatrix, arrayView1d< real64 > const inputRhs, real64 const inputDt, real64 const (&gravityVector)[3], string const inputFlowDofKey, integer const performStressInitialization, string const fluidModelKey)
Constructor.
GEOS_HOST_DEVICE real64 complete(localIndex const k, StackVariables &stack) const
Performs the complete phase for the kernel.
GEOS_HOST_DEVICE void assembleMomentumBalanceTerms(real64 const (&N)[numNodesPerElem], real64 const (&dNdX)[numNodesPerElem][3], real64 const &detJxW, StackVariables &stack) const
Assemble the local linear momentum balance residual and derivatives using total stress and body force...
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Definition: DataTypes.hpp:180
LvArray::CRSMatrixView< T, COL_INDEX, localIndex const, LvArray::ChaiBuffer > CRSMatrixView
Alias for CRS Matrix View.
Definition: DataTypes.hpp:310
GEOS_GLOBALINDEX_TYPE globalIndex
Global index type (for indexing objects across MPI partitions).
Definition: DataTypes.hpp:88
std::string string
String type.
Definition: DataTypes.hpp:91
double real64
64-bit floating point type.
Definition: DataTypes.hpp:99
GEOS_LOCALINDEX_TYPE localIndex
Local index type (for indexing objects within an MPI partition).
Definition: DataTypes.hpp:85
std::int32_t integer
Signed integer type.
Definition: DataTypes.hpp:82
real64 dFluidMassIncrement_dVolStrainIncrement
Derivative of mass accumulation wrt volumetric strain increment.
real64 dLocalResidualMass_dPressure[1][1]
Derivative of mass balance residual wrt pressure.
real64 dLocalResidualMass_dDisplacement[1][Base::StackVariables::numDispDofPerElem]
Derivative of mass balance residual wrt displacement.
real64 dFluidMassIncrement_dPressure
Derivative of mass accumulation wrt pressure.