GEOS
ThermalSinglePhasePoromechanics_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_THERMALSINGLEPHASEPOROMECHANICS_IMPL_HPP_
21 #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_THERMALSINGLEPHASEPOROMECHANICS_IMPL_HPP_
22 
23 #include "constitutive/fluid/singlefluid/SingleFluidBase.hpp"
25 
26 namespace geos
27 {
28 
29 namespace thermalPoromechanicsKernels
30 {
31 
32 template< typename SUBREGION_TYPE,
33  typename CONSTITUTIVE_TYPE,
34  typename FE_TYPE >
36 ThermalSinglePhasePoromechanics( NodeManager const & nodeManager,
37  EdgeManager const & edgeManager,
38  FaceManager const & faceManager,
39  localIndex const targetRegionIndex,
40  SUBREGION_TYPE const & elementSubRegion,
41  FE_TYPE const & finiteElementSpace,
42  CONSTITUTIVE_TYPE & inputConstitutiveType,
43  arrayView1d< globalIndex const > const inputDispDofNumber,
44  globalIndex const rankOffset,
46  arrayView1d< real64 > const inputRhs,
47  real64 const inputDt,
48  real64 const (&gravityVector)[3],
49  string const inputFlowDofKey,
50  integer const performStressInitialization,
51  string const fluidModelKey ):
52  Base( nodeManager,
53  edgeManager,
54  faceManager,
55  targetRegionIndex,
56  elementSubRegion,
57  finiteElementSpace,
58  inputConstitutiveType,
59  inputDispDofNumber,
60  rankOffset,
61  inputMatrix,
62  inputRhs,
63  inputDt,
64  gravityVector,
65  inputFlowDofKey,
66  performStressInitialization,
67  fluidModelKey ),
68  m_fluidInternalEnergy_n( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).internalEnergy_n() ),
69  m_fluidInternalEnergy( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >( fluidModelKey ) ).internalEnergy() ),
70  m_dFluidInternalEnergy( elementSubRegion.template getConstitutiveModel< constitutive::SingleFluidBase >( elementSubRegion.template getReference< string >(
71  fluidModelKey ) ).dInternalEnergy() ),
72  m_rockInternalEnergy_n( inputConstitutiveType.getInternalEnergy_n() ),
73  m_rockInternalEnergy( inputConstitutiveType.getInternalEnergy() ),
74  m_dRockInternalEnergy_dTemperature( inputConstitutiveType.getDinternalEnergy_dTemperature() ),
75  m_referenceTemperature( elementSubRegion.template getField< fields::flow::initialTemperature >() ),
76  m_temperature_n( elementSubRegion.template getField< fields::flow::temperature_n >() ),
77  m_temperature( elementSubRegion.template getField< fields::flow::temperature >() )
78 {}
79 
80 template< typename SUBREGION_TYPE,
81  typename CONSTITUTIVE_TYPE,
82  typename FE_TYPE >
86 setup( localIndex const k,
87  StackVariables & stack ) const
88 {
89  Base::setup( k, stack );
90  stack.localTemperatureDofIndex = m_flowDofNumber[k]+1;
91  stack.temperature = m_temperature[k];
92  stack.deltaTemperatureFromLastStep = m_temperature[k] - m_temperature_n[k];
93  stack.deltaTemperature = m_temperature[k] - m_referenceTemperature[k];
94 }
95 
96 template< typename SUBREGION_TYPE,
97  typename CONSTITUTIVE_TYPE,
98  typename FE_TYPE >
103  localIndex const q,
104  StackVariables & stack ) const
105 {
106  real64 porosity = 0.0;
107  real64 porosity_n = 0.0;
108  real64 dPorosity_dVolStrain = 0.0;
109  real64 dPorosity_dPressure = 0.0;
110  real64 dPorosity_dTemperature = 0.0;
111  real64 dSolidDensity_dPressure = 0.0;
112 
113  // Step 1: call the constitutive model to evaluate the total stress and compute porosity
114  m_constitutiveUpdate.smallStrainUpdatePoromechanics( k, q,
115  m_dt,
116  m_pressure[k],
117  m_pressure_n[k],
118  stack.deltaTemperature,
119  stack.deltaTemperatureFromLastStep,
120  stack.strainIncrement,
121  stack.totalStress,
122  stack.dTotalStress_dPressure,
123  stack.dTotalStress_dTemperature,
124  stack.stiffness,
125  m_performStressInitialization,
126  porosity,
127  porosity_n,
128  dPorosity_dVolStrain,
129  dPorosity_dPressure,
130  dPorosity_dTemperature,
131  dSolidDensity_dPressure );
132 
133  // Step 2: compute the body force
134  computeBodyForce( k, q,
135  porosity,
136  dPorosity_dVolStrain,
137  dPorosity_dPressure,
138  dPorosity_dTemperature,
139  dSolidDensity_dPressure,
140  stack );
141 
142  // Step 3: compute fluid mass increment
143  computeFluidIncrement( k, q,
144  porosity,
145  porosity_n,
146  dPorosity_dVolStrain,
147  dPorosity_dPressure,
148  dPorosity_dTemperature,
149  stack );
150 }
151 
152 template< typename SUBREGION_TYPE,
153  typename CONSTITUTIVE_TYPE,
154  typename FE_TYPE >
159  localIndex const q,
160  real64 const & porosity,
161  real64 const & dPorosity_dVolStrain,
162  real64 const & dPorosity_dPressure,
163  real64 const & dPorosity_dTemperature,
164  real64 const & dSolidDensity_dPressure,
165  StackVariables & stack ) const
166 {
167  Base::computeBodyForce( k, q,
168  porosity,
169  dPorosity_dVolStrain,
170  dPorosity_dPressure,
171  dPorosity_dTemperature,
172  dSolidDensity_dPressure,
173  stack );
174 
175  real64 const dMixtureDens_dTemperature =
176  dPorosity_dTemperature * ( -m_solidDensity( k, q ) + m_fluidDensity( k, q ) )
177  + porosity * m_dFluidDensity( k, q, DerivOffset::dT );
178 
179  LvArray::tensorOps::scaledCopy< 3 >( stack.dBodyForce_dTemperature, m_gravityVector, dMixtureDens_dTemperature );
180 }
181 
182 template< typename SUBREGION_TYPE,
183  typename CONSTITUTIVE_TYPE,
184  typename FE_TYPE >
189  localIndex const q,
190  real64 const & porosity,
191  real64 const & porosity_n,
192  real64 const & dPorosity_dVolStrain,
193  real64 const & dPorosity_dPressure,
194  real64 const & dPorosity_dTemperature,
195  StackVariables & stack ) const
196 {
197  // Step 1: compute fluid mass increment and its derivatives wrt vol strain and pressure
198  Base::computeFluidIncrement( k, q,
199  porosity,
200  porosity_n,
201  dPorosity_dVolStrain,
202  dPorosity_dPressure,
203  dPorosity_dTemperature,
204  stack );
205 
206  // Step 2: compute derivative of fluid mass increment wrt temperature
207  stack.dFluidMassIncrement_dTemperature = dPorosity_dTemperature * m_fluidDensity( k, q ) + porosity * m_dFluidDensity( k, q, DerivOffset::dT );
208  // tag
209 
210  // Step 3: compute fluid energy increment and its derivatives wrt vol strain, pressure, and temperature
211  real64 const fluidMass = porosity * m_fluidDensity( k, q );
212  real64 const fluidEnergy = fluidMass * m_fluidInternalEnergy( k, q );
213  real64 const fluidEnergy_n = porosity_n * m_fluidDensity_n( k, q ) * m_fluidInternalEnergy_n( k, q );
214  stack.energyIncrement = fluidEnergy - fluidEnergy_n;
215 
216  stack.dEnergyIncrement_dVolStrainIncrement = stack.dFluidMassIncrement_dVolStrainIncrement * m_fluidInternalEnergy( k, q );
217  stack.dEnergyIncrement_dPressure = stack.dFluidMassIncrement_dPressure * m_fluidInternalEnergy( k, q )
218  + fluidMass * m_dFluidInternalEnergy( k, q, DerivOffset::dP );
219  stack.dEnergyIncrement_dTemperature = stack.dFluidMassIncrement_dTemperature * m_fluidInternalEnergy( k, q )
220  + fluidMass * m_dFluidInternalEnergy( k, q, DerivOffset::dT );
221 
222 
223  // Step 4: assemble the solid part of the accumulation term
224  real64 const oneMinusPoro = 1 - porosity;
225 
226  stack.energyIncrement += oneMinusPoro * m_rockInternalEnergy( k, 0 ) - ( 1 - porosity_n ) * m_rockInternalEnergy_n( k, 0 );
227  stack.dEnergyIncrement_dVolStrainIncrement += -dPorosity_dVolStrain * m_rockInternalEnergy( k, 0 );
228  stack.dEnergyIncrement_dPressure += -dPorosity_dPressure * m_rockInternalEnergy( k, 0 );
229  stack.dEnergyIncrement_dTemperature += -dPorosity_dTemperature * m_rockInternalEnergy( k, 0 ) + oneMinusPoro * m_dRockInternalEnergy_dTemperature( k, 0 );
230 }
231 
232 template< typename SUBREGION_TYPE,
233  typename CONSTITUTIVE_TYPE,
234  typename FE_TYPE >
238 assembleMomentumBalanceTerms( real64 const ( &N )[numNodesPerElem],
239  real64 const ( &dNdX )[numNodesPerElem][3],
240  real64 const & detJxW,
241  StackVariables & stack ) const
242 {
243  using namespace PDEUtilities;
244 
245  Base::assembleMomentumBalanceTerms( N, dNdX, detJxW, stack );
246 
247  constexpr FunctionSpace displacementTrialSpace = FE_TYPE::template getFunctionSpace< numDofPerTrialSupportPoint >();
248  constexpr FunctionSpace displacementTestSpace = displacementTrialSpace;
249  constexpr FunctionSpace pressureTrialSpace = FunctionSpace::P0;
250 
251  // compute local linear momentum balance residual derivatives with respect to temperature
252 
253  BilinearFormUtilities::compute< displacementTestSpace,
254  pressureTrialSpace,
255  DifferentialOperator::SymmetricGradient,
256  DifferentialOperator::Identity >
257  (
259  dNdX,
260  stack.dTotalStress_dTemperature,
261  1.0,
262  -detJxW );
263 
264  BilinearFormUtilities::compute< displacementTestSpace,
265  pressureTrialSpace,
266  DifferentialOperator::Identity,
267  DifferentialOperator::Identity >
268  (
270  N,
272  1.0,
273  detJxW );
274 }
275 
276 template< typename SUBREGION_TYPE,
277  typename CONSTITUTIVE_TYPE,
278  typename FE_TYPE >
282 assembleElementBasedFlowTerms( real64 const ( &dNdX )[numNodesPerElem][3],
283  real64 const & detJxW,
284  StackVariables & stack ) const
285 {
286 
287  using namespace PDEUtilities;
288 
289  Base::assembleElementBasedFlowTerms( dNdX, detJxW, stack );
290 
291  constexpr FunctionSpace displacementTrialSpace = FE_TYPE::template getFunctionSpace< numDofPerTrialSupportPoint >();
292  constexpr FunctionSpace pressureTrialSpace = FunctionSpace::P0;
293  constexpr FunctionSpace pressureTestSpace = pressureTrialSpace;
294 
295  // Step 1: compute local mass balance residual derivatives with respect to temperature
296 
297  BilinearFormUtilities::compute< pressureTestSpace,
298  pressureTrialSpace,
299  DifferentialOperator::Identity,
300  DifferentialOperator::Identity >
301  (
303  1.0,
305  1.0,
306  detJxW );
307 
308  // Step 2: compute local energy balance residual and its derivatives
309 
310  LinearFormUtilities::compute< pressureTestSpace,
311  DifferentialOperator::Identity >
312  (
313  stack.localResidualEnergy,
314  1.0,
315  stack.energyIncrement,
316  detJxW );
317 
318  BilinearFormUtilities::compute< pressureTestSpace,
319  displacementTrialSpace,
320  DifferentialOperator::Identity,
321  DifferentialOperator::Divergence >
322  (
324  1.0,
326  dNdX,
327  detJxW );
328 
329  BilinearFormUtilities::compute< pressureTestSpace,
330  pressureTrialSpace,
331  DifferentialOperator::Identity,
332  DifferentialOperator::Identity >
333  (
335  1.0,
337  1.0,
338  detJxW );
339 
340  BilinearFormUtilities::compute< pressureTestSpace,
341  pressureTrialSpace,
342  DifferentialOperator::Identity,
343  DifferentialOperator::Identity >
344  (
346  1.0,
348  1.0,
349  detJxW );
350 }
351 
352 template< typename SUBREGION_TYPE,
353  typename CONSTITUTIVE_TYPE,
354  typename FE_TYPE >
359  localIndex const q,
360  StackVariables & stack ) const
361 {
362  // Step 1: compute displacement finite element basis functions (N), basis function derivatives (dNdX), and
363  // determinant of the Jacobian transformation matrix times the quadrature weight (detJxW)
364  real64 N[numNodesPerElem]{};
365  real64 dNdX[numNodesPerElem][3]{};
366  FE_TYPE::calcN( q, stack.feStack, N );
367  real64 const detJxW = m_finiteElementSpace.template getGradN< FE_TYPE >( k, q, stack.xLocal,
368  stack.feStack, dNdX );
369 
370  // Step 2: compute strain increment
371  LvArray::tensorOps::fill< 6 >( stack.strainIncrement, 0.0 );
372  FE_TYPE::symmetricGradient( dNdX, stack.uhat_local, stack.strainIncrement );
373 
374  // Step 3: compute 1) the total stress, 2) the body force terms, and 3) the fluidMassIncrement
375  // using quantities returned by the PorousSolid constitutive model.
376  // This function also computes the derivatives of these three quantities wrt primary variables
377  smallStrainUpdate( k, q, stack );
378 
379  // Step 4: use the total stress and the body force to increment the local momentum balance residual
380  // This function also fills the local Jacobian rows corresponding to the momentum balance.
381  assembleMomentumBalanceTerms( N, dNdX, detJxW, stack );
382 
383  // Step 5: use the fluid mass increment to increment the local mass balance residual
384  // This function also fills the local Jacobian rows corresponding to the mass balance.
385  assembleElementBasedFlowTerms( dNdX, detJxW, stack );
386 }
387 
388 template< typename SUBREGION_TYPE,
389  typename CONSTITUTIVE_TYPE,
390  typename FE_TYPE >
394 complete( localIndex const k,
395  StackVariables & stack ) const
396 {
397  real64 const maxForce = Base::complete( k, stack );
398 
399  localIndex const numSupportPoints =
400  m_finiteElementSpace.template numSupportPoints< FE_TYPE >( stack.feStack );
401  integer numDisplacementDofs = numSupportPoints * numDofPerTestSupportPoint;
402 
403  // Step 1: assemble the derivatives of linear momentum balance wrt temperature into the global matrix
404 
405  for( int localNode = 0; localNode < numSupportPoints; ++localNode )
406  {
407  for( integer dim = 0; dim < numDofPerTestSupportPoint; ++dim )
408  {
409  localIndex const dof = LvArray::integerConversion< localIndex >( stack.localRowDofIndex[numDofPerTestSupportPoint*localNode + dim] - m_dofRankOffset );
410 
411  // we need this check to filter out ghost nodes in the assembly
412  if( dof < 0 || dof >= m_matrix.numRows() )
413  {
414  continue;
415  }
416 
417  m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof,
419  stack.dLocalResidualMomentum_dTemperature[numDofPerTestSupportPoint * localNode + dim],
420  1 );
421  }
422  }
423 
424  // Step 2: assemble the derivatives of mass balance residual wrt temperature into the global matrix
425 
426  localIndex const massDof = LvArray::integerConversion< localIndex >( stack.localPressureDofIndex - m_dofRankOffset );
427 
428  // we need this check to filter out ghost cells in the assembly
429  if( 0 <= massDof && massDof < m_matrix.numRows() )
430  {
431  m_matrix.template addToRow< serialAtomic >( massDof,
434  1 );
435  }
436 
437  // Step 3: assemble the energy balance and its derivatives into the global matrix
438 
439  localIndex const energyDof = LvArray::integerConversion< localIndex >( stack.localTemperatureDofIndex - m_dofRankOffset );
440 
441  // we need this check to filter out ghost cells in the assembly
442  if( 0 <= energyDof && energyDof < m_matrix.numRows() )
443  {
444  m_matrix.template addToRowBinarySearchUnsorted< serialAtomic >( energyDof,
445  stack.localRowDofIndex,
447  numDisplacementDofs );
448  m_matrix.template addToRow< serialAtomic >( energyDof,
449  &stack.localPressureDofIndex,
451  1 );
452  m_matrix.template addToRow< serialAtomic >( energyDof,
455  1 );
456 
457  RAJA::atomicAdd< serialAtomic >( &m_rhs[energyDof], stack.localResidualEnergy[0] );
458  }
459 
460  return maxForce;
461 }
462 
463 template< typename SUBREGION_TYPE,
464  typename CONSTITUTIVE_TYPE,
465  typename FE_TYPE >
466 template< typename POLICY,
467  typename KERNEL_TYPE >
469 kernelLaunch( localIndex const numElems,
470  KERNEL_TYPE const & kernelComponent )
471 {
473 
474  // Define a RAJA reduction variable to get the maximum residual contribution.
475  RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxResidual( 0 );
476 
477  forAll< POLICY >( numElems,
478  [=] GEOS_HOST_DEVICE ( localIndex const k )
479  {
480  typename KERNEL_TYPE::StackVariables stack;
481 
482  kernelComponent.setup( k, stack );
483  for( integer q=0; q<KERNEL_TYPE::numQuadraturePointsPerElem; ++q )
484  {
485  kernelComponent.quadraturePointKernel( k, q, stack );
486  }
487  maxResidual.max( kernelComponent.complete( k, stack ) );
488  } );
489  return maxResidual.get();
490 }
491 
492 
493 } // namespace thermalPoromechanicsKernels
494 
495 } // namespace geos
496 
497 #endif // GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_THERMALSINGLEPHASEPOROMECHANICS_HPP_
#define GEOS_HOST_DEVICE
Marks a host-device function.
Definition: GeosxMacros.hpp:49
#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 thermal single-phase poromechanics.
GEOS_HOST_DEVICE void assembleElementBasedFlowTerms(real64 const (&dNdX)[numNodesPerElem][3], real64 const &detJxW, StackVariables &stack) const
Assemble the local mass/energy balance residual and derivatives using fluid mass/energy increment.
static real64 kernelLaunch(localIndex const numElems, KERNEL_TYPE const &kernelComponent)
Kernel Launcher.
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/energy increment and its derivatives wrt primary variables.
GEOS_HOST_DEVICE void setup(localIndex const k, StackVariables &stack) const
Copy global values from primary field to a local stack array.
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 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...
ThermalSinglePhasePoromechanics(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 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 fluidMass/EnergyIn...
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Definition: DataTypes.hpp:188
LvArray::CRSMatrixView< T, COL_INDEX, localIndex const, LvArray::ChaiBuffer > CRSMatrixView
Alias for CRS Matrix View.
Definition: DataTypes.hpp:318
GEOS_GLOBALINDEX_TYPE globalIndex
Global index type (for indexing objects across MPI partitions).
Definition: DataTypes.hpp:87
std::string string
String type.
Definition: DataTypes.hpp:90
double real64
64-bit floating point type.
Definition: DataTypes.hpp:98
GEOS_LOCALINDEX_TYPE localIndex
Local index type (for indexing objects within an MPI partition).
Definition: DataTypes.hpp:84
std::int32_t integer
Signed integer type.
Definition: DataTypes.hpp:81
Kernel variables (dof numbers, jacobian and residual) located on the stack.
real64 dLocalResidualEnergy_dDisplacement[1][numDispDofPerElem]
Derivative of energy balance residual wrt displacement.
globalIndex localTemperatureDofIndex
C-array storage for the element local row degrees of freedom.
real64 dEnergyIncrement_dVolStrainIncrement
Derivative of energy accumulation wrt volumetric strain increment.
real64 dLocalResidualMass_dTemperature[1][1]
Derivative of mass balance residual wrt pressure.
real64 dLocalResidualEnergy_dPressure[1][1]
Derivative of energy balance residual wrt pressure.
real64 dLocalResidualMomentum_dTemperature[numDispDofPerElem][1]
Derivative of linear momentum balance residual wrt temperature.
real64 dLocalResidualEnergy_dTemperature[1][1]
Derivative of energy balance residual wrt temperature.