GEOS
MultiphasePoromechanics_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_MULTIPHASEPOROMECHANICS_IMPL_HPP_
21 #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSKERNELS_MULTIPHASEPOROMECHANICS_IMPL_HPP_
22 
23 #include "constitutive/fluid/multifluid/MultiFluidBase.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 MultiphasePoromechanics( 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  localIndex const numComponents,
55  localIndex const numPhases,
56  integer const useSimpleAccumulation,
57  integer const useTotalMassEquation,
58  integer const performStressInitialization,
59  string const fluidModelKey ):
60  Base( nodeManager,
61  edgeManager,
62  faceManager,
63  targetRegionIndex,
64  elementSubRegion,
65  finiteElementSpace,
66  inputConstitutiveType,
67  inputDispDofNumber,
68  rankOffset,
69  inputMatrix,
70  inputRhs,
71  inputDt,
72  gravityVector,
73  inputFlowDofKey,
74  fluidModelKey ),
75  m_fluidPhaseVolFrac( elementSubRegion.template getField< fields::flow::phaseVolumeFraction >() ),
76  m_fluidPhaseVolFrac_n( elementSubRegion.template getField< fields::flow::phaseVolumeFraction_n >() ),
77  m_dFluidPhaseVolFrac( elementSubRegion.template getField< fields::flow::dPhaseVolumeFraction >() ),
78  m_dGlobalCompFraction_dGlobalCompDensity( elementSubRegion.template getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ),
79  m_compDens( elementSubRegion.template getField< fields::flow::globalCompDensity >() ),
80  m_compDens_n( elementSubRegion.template getField< fields::flow::globalCompDensity_n >() ),
81  m_numComponents( numComponents ),
82  m_numPhases( numPhases ),
83  m_useSimpleAccumulation( useSimpleAccumulation ),
84  m_useTotalMassEquation( useTotalMassEquation ),
85  m_performStressInitialization( performStressInitialization )
86 {
87  GEOS_ERROR_IF_GT_MSG( m_numComponents, maxNumComponents,
88  "MultiphasePoromechanics solver allows at most " <<
89  maxNumComponents << " components at the moment" );
90 
91  // extract fluid constitutive data views
92  {
93  string const fluidModelName = elementSubRegion.template getReference< string >( fluidModelKey );
94  constitutive::MultiFluidBase const & fluid =
95  elementSubRegion.template getConstitutiveModel< constitutive::MultiFluidBase >( fluidModelName );
96 
97  m_fluidPhaseDensity = fluid.phaseDensity();
98  m_fluidPhaseDensity_n = fluid.phaseDensity_n();
99  m_dFluidPhaseDensity = fluid.dPhaseDensity();
100 
101  m_fluidPhaseCompFrac = fluid.phaseCompFraction();
102  m_fluidPhaseCompFrac_n = fluid.phaseCompFraction_n();
103  m_dFluidPhaseCompFrac = fluid.dPhaseCompFraction();
104 
105  m_fluidPhaseMassDensity = fluid.phaseMassDensity();
106  m_dFluidPhaseMassDensity = fluid.dPhaseMassDensity();
107 
108  m_useMass = fluid.getMassFlag();
109  m_componentMolarWeight = fluid.componentMolarWeights();
110  }
111 }
112 
121 template< typename SUBREGION_TYPE,
122  typename CONSTITUTIVE_TYPE,
123  typename FE_TYPE >
127 setup( localIndex const k,
128  StackVariables & stack ) const
129 {
130  // initialize displacement dof and pressure dofs
131  Base::setup( k, stack );
132 
133  // setup component dofs
134  // for now, maxNumComponents > m_numComponents, so we pad localComponentDofIndices with -1
135  LvArray::tensorOps::fill< maxNumComponents >( stack.localComponentDofIndices, -1.0 );
136  for( integer flowDofIndex=0; flowDofIndex < m_numComponents; ++flowDofIndex )
137  {
138  stack.localComponentDofIndices[flowDofIndex] = stack.localPressureDofIndex + flowDofIndex + 1;
139  }
140 }
141 
142 template< typename SUBREGION_TYPE,
143  typename CONSTITUTIVE_TYPE,
144  typename FE_TYPE >
149  localIndex const q,
150  StackVariables & stack ) const
151 {
152  real64 porosity = 0.0;
153  real64 porosity_n = 0.0;
154  real64 dPorosity_dVolStrain = 0.0;
155  real64 dPorosity_dPressure = 0.0;
156  real64 dPorosity_dTemperature = 0.0;
157  real64 dSolidDensity_dPressure = 0.0;
158 
159  // Step 1: call the constitutive model to evaluate the total stress and compute porosity
160  m_constitutiveUpdate.smallStrainUpdatePoromechanics( k, q,
161  m_dt,
162  m_pressure[k],
163  m_pressure_n[k],
164  stack.temperature,
166  stack.strainIncrement,
167  stack.totalStress,
170  stack.stiffness,
171  m_performStressInitialization,
172  porosity,
173  porosity_n,
174  dPorosity_dVolStrain,
175  dPorosity_dPressure,
176  dPorosity_dTemperature,
177  dSolidDensity_dPressure );
178 
179  // Step 2: compute the body force
180  computeBodyForce( k, q,
181  porosity,
182  dPorosity_dVolStrain,
183  dPorosity_dPressure,
184  dPorosity_dTemperature,
185  dSolidDensity_dPressure,
186  stack );
187 
188  // Step 3: compute fluid mass increment
189  computeFluidIncrement( k, q,
190  porosity,
191  porosity_n,
192  dPorosity_dVolStrain,
193  dPorosity_dPressure,
194  dPorosity_dTemperature,
195  stack );
196 
197  // Step 4: compute pore volume constraint
198  computePoreVolumeConstraint( k,
199  porosity_n,
200  stack );
201 }
202 
203 template< typename SUBREGION_TYPE,
204  typename CONSTITUTIVE_TYPE,
205  typename FE_TYPE >
206 template< typename FUNC >
211  localIndex const q,
212  real64 const & porosity,
213  real64 const & dPorosity_dVolStrain,
214  real64 const & dPorosity_dPressure,
215  real64 const & dPorosity_dTemperature,
216  real64 const & dSolidDensity_dPressure,
217  StackVariables & stack,
218  FUNC && bodyForceKernelOp ) const
219 {
220  GEOS_UNUSED_VAR( dPorosity_dTemperature );
221 
222  // Step 1: compute fluid total mass density and its derivatives
223 
224  real64 totalMassDensity = 0.0;
225  real64 dTotalMassDensity_dComponents[maxNumComponents]{};
226 
227  arraySlice1d< real64 const, compflow::USD_COMP - 1 > const compDens = m_compDens[k];
228  for( integer ic = 0; ic < m_numComponents; ++ic )
229  {
230  totalMassDensity = totalMassDensity + ( m_useMass ? compDens[ic] : compDens[ic] * m_componentMolarWeight[ic] );
231  dTotalMassDensity_dComponents[ic] = m_useMass ? 1.0 : m_componentMolarWeight[ic];
232  }
233 
234  // Step 2: compute mixture density as an average between total mass density and solid density
235 
236  real64 const mixtureDensity = ( 1.0 - porosity ) * m_solidDensity( k, q ) + porosity * totalMassDensity;
237  real64 const dMixtureDens_dVolStrainIncrement = dPorosity_dVolStrain * ( -m_solidDensity( k, q ) + totalMassDensity );
238  real64 const dMixtureDens_dPressure = dPorosity_dPressure * ( -m_solidDensity( k, q ) + totalMassDensity )
239  + ( 1.0 - porosity ) * dSolidDensity_dPressure;
240  LvArray::tensorOps::scale< maxNumComponents >( dTotalMassDensity_dComponents, porosity );
241 
242  // Step 3: finally, get the body force
243 
244  LvArray::tensorOps::scaledCopy< 3 >( stack.bodyForce, m_gravityVector, mixtureDensity );
245  LvArray::tensorOps::scaledCopy< 3 >( stack.dBodyForce_dVolStrainIncrement, m_gravityVector, dMixtureDens_dVolStrainIncrement );
246  LvArray::tensorOps::scaledCopy< 3 >( stack.dBodyForce_dPressure, m_gravityVector, dMixtureDens_dPressure );
247  LvArray::tensorOps::Rij_eq_AiBj< 3, maxNumComponents >( stack.dBodyForce_dComponents, m_gravityVector, dTotalMassDensity_dComponents );
248 
249  // Step 4: customize the kernel (for instance, to add thermal derivatives)
250  bodyForceKernelOp( totalMassDensity, mixtureDensity );
251 
252 }
253 
254 template< typename SUBREGION_TYPE,
255  typename CONSTITUTIVE_TYPE,
256  typename FE_TYPE >
257 template< typename FUNC >
262  localIndex const q,
263  real64 const & porosity,
264  real64 const & porosity_n,
265  real64 const & dPorosity_dVolStrain,
266  real64 const & dPorosity_dPressure,
267  real64 const & dPorosity_dTemperature,
268  StackVariables & stack,
269  FUNC && fluidIncrementKernelOp ) const
270 {
271  LvArray::tensorOps::fill< maxNumComponents >( stack.compMassIncrement, 0.0 );
272  LvArray::tensorOps::fill< maxNumComponents >( stack.dCompMassIncrement_dVolStrainIncrement, 0.0 );
273  LvArray::tensorOps::fill< maxNumComponents >( stack.dCompMassIncrement_dPressure, 0.0 );
274  LvArray::tensorOps::fill< maxNumComponents, maxNumComponents >( stack.dCompMassIncrement_dComponents, 0.0 );
275 
276  if( m_useSimpleAccumulation )
277  {
278  arraySlice1d< real64 const, compflow::USD_COMP - 1 >
279  const compDens = m_compDens[k];
280  arraySlice1d< real64 const, compflow::USD_COMP - 1 >
281  const compDens_n = m_compDens_n[k];
282 
283  for( integer ic = 0; ic < m_numComponents; ++ic )
284  {
285  stack.compMassIncrement[ic] += porosity * compDens[ic] - porosity_n * compDens_n[ic];
286  stack.dCompMassIncrement_dPressure[ic] += dPorosity_dPressure * compDens[ic];
287  stack.dCompMassIncrement_dVolStrainIncrement[ic] += dPorosity_dVolStrain * compDens[ic];
288  stack.dCompMassIncrement_dComponents[ic][ic] += porosity;
289  }
290  }
291  else
292  {
293  using Deriv = constitutive::multifluid::DerivativeOffset;
294 
295  GEOS_UNUSED_VAR( dPorosity_dTemperature );
296 
297  // temporary work arrays and slices
298  real64 dPhaseAmount_dC[maxNumComponents]{};
299  real64 dPhaseCompFrac_dC[maxNumComponents]{};
300 
301  arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 >
302  const phaseDensity = m_fluidPhaseDensity[k][q];
303  arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 >
304  const phaseDensity_n = m_fluidPhaseDensity_n[k][q];
305  arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 >
306  const dPhaseDensity = m_dFluidPhaseDensity[k][q];
307  arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 >
308  const phaseCompFrac = m_fluidPhaseCompFrac[k][q];
309  arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 >
310  const phaseCompFrac_n = m_fluidPhaseCompFrac_n[k][q];
311  arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 >
312  const dPhaseCompFrac = m_dFluidPhaseCompFrac[k][q];
313  arraySlice1d< real64 const, compflow::USD_PHASE - 1 >
314  const phaseVolFrac = m_fluidPhaseVolFrac[k];
315  arraySlice1d< real64 const, compflow::USD_PHASE - 1 >
316  const phaseVolFrac_n = m_fluidPhaseVolFrac_n[k];
317  arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 >
318  const dPhaseVolFrac = m_dFluidPhaseVolFrac[k];
319  arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 >
320  const dGlobalCompFrac_dGlobalCompDensity = m_dGlobalCompFraction_dGlobalCompDensity[k];
321 
322  // loop over the fluid phases
323  for( integer ip = 0; ip < m_numPhases; ++ip )
324  {
325 
326  // compute the mass of the current phase
327  real64 const phaseAmount = porosity * phaseVolFrac( ip ) * phaseDensity( ip );
328  real64 const phaseAmount_n = porosity_n * phaseVolFrac_n( ip ) * phaseDensity_n( ip );
329 
330  real64 const dPhaseAmount_dVolStrain = dPorosity_dVolStrain * phaseVolFrac( ip ) * phaseDensity( ip );
331  real64 const dPhaseAmount_dP = dPorosity_dPressure * phaseVolFrac( ip ) * phaseDensity( ip )
332  + porosity * ( dPhaseVolFrac( ip, Deriv::dP ) * phaseDensity( ip )
333  + phaseVolFrac( ip ) * dPhaseDensity( ip, Deriv::dP ) );
334 
335  applyChainRule( m_numComponents,
336  dGlobalCompFrac_dGlobalCompDensity,
337  dPhaseDensity[ip],
338  dPhaseAmount_dC,
339  Deriv::dC );
340 
341  for( integer jc = 0; jc < m_numComponents; ++jc )
342  {
343  dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac( ip )
344  + phaseDensity( ip ) * dPhaseVolFrac( ip, Deriv::dC + jc );
345  dPhaseAmount_dC[jc] *= porosity;
346  }
347 
348  // for each phase, compute the amount of each component transported by the phase
349  for( integer ic = 0; ic < m_numComponents; ++ic )
350  {
351  stack.compMassIncrement[ic] += phaseAmount * phaseCompFrac( ip, ic )
352  - phaseAmount_n * phaseCompFrac_n( ip, ic );
353 
354  stack.dCompMassIncrement_dPressure[ic] += dPhaseAmount_dP * phaseCompFrac( ip, ic )
355  + phaseAmount * dPhaseCompFrac( ip, ic, Deriv::dP );
356  stack.dCompMassIncrement_dVolStrainIncrement[ic] += dPhaseAmount_dVolStrain * phaseCompFrac( ip, ic );
357 
358  applyChainRule( m_numComponents,
359  dGlobalCompFrac_dGlobalCompDensity,
360  dPhaseCompFrac[ip][ic],
361  dPhaseCompFrac_dC,
362  Deriv::dC );
363 
364  for( integer jc = 0; jc < m_numComponents; ++jc )
365  {
366  stack.dCompMassIncrement_dComponents[ic][jc] += dPhaseAmount_dC[jc] * phaseCompFrac( ip, ic )
367  + phaseAmount * dPhaseCompFrac_dC[jc];
368  }
369  }
370 
371  // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives
372  // possible use: assemble the derivatives wrt temperature, and the accumulation term of the energy equation for this phase
373  fluidIncrementKernelOp( ip, phaseAmount, phaseAmount_n, dPhaseAmount_dVolStrain, dPhaseAmount_dP, dPhaseAmount_dC );
374 
375  }
376  }
377 }
378 
379 template< typename SUBREGION_TYPE,
380  typename CONSTITUTIVE_TYPE,
381  typename FE_TYPE >
386  real64 const & porosity_n,
387  StackVariables & stack ) const
388 {
389  using Deriv = constitutive::multifluid::DerivativeOffset;
390 
391  arraySlice1d< real64 const, compflow::USD_PHASE - 1 > const phaseVolFrac = m_fluidPhaseVolFrac[k];
392  arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > const dPhaseVolFrac = m_dFluidPhaseVolFrac[k];
393 
394  stack.poreVolConstraint = 1.0;
395  stack.dPoreVolConstraint_dPressure = 0.0;
396  LvArray::tensorOps::fill< 1, maxNumComponents >( stack.dPoreVolConstraint_dComponents, 0.0 );
397 
398  for( integer ip = 0; ip < m_numPhases; ++ip )
399  {
400  stack.poreVolConstraint -= phaseVolFrac( ip );
401  stack.dPoreVolConstraint_dPressure -= dPhaseVolFrac( ip, Deriv::dP ) * porosity_n;
402 
403  for( integer jc = 0; jc < m_numComponents; ++jc )
404  {
405  stack.dPoreVolConstraint_dComponents[0][jc] -= dPhaseVolFrac( ip, Deriv::dC+jc ) * porosity_n;
406  }
407  }
408  stack.poreVolConstraint *= porosity_n;
409 }
410 
411 template< typename SUBREGION_TYPE,
412  typename CONSTITUTIVE_TYPE,
413  typename FE_TYPE >
417 assembleMomentumBalanceTerms( real64 const ( &N )[numNodesPerElem],
418  real64 const ( &dNdX )[numNodesPerElem][3],
419  real64 const & detJxW,
420  StackVariables & stack ) const
421 {
422  using namespace PDEUtilities;
423 
424  constexpr FunctionSpace displacementTrialSpace = FE_TYPE::template getFunctionSpace< numDofPerTrialSupportPoint >();
425  constexpr FunctionSpace displacementTestSpace = displacementTrialSpace;
426  constexpr FunctionSpace pressureTrialSpace = FunctionSpace::P0;
427 
428  // Step 1: compute local linear momentum balance residual
429 
430  LinearFormUtilities::compute< displacementTestSpace,
431  DifferentialOperator::SymmetricGradient >
432  (
433  stack.localResidualMomentum,
434  dNdX,
435  stack.totalStress,
436  -detJxW );
437 
438  LinearFormUtilities::compute< displacementTestSpace,
439  DifferentialOperator::Identity >
440  (
441  stack.localResidualMomentum,
442  N,
443  stack.bodyForce,
444  detJxW );
445 
446  // Step 2: compute local linear momentum balance residual derivatives with respect to displacement
447  BilinearFormUtilities::compute< displacementTestSpace,
448  displacementTrialSpace,
449  DifferentialOperator::SymmetricGradient,
450  DifferentialOperator::SymmetricGradient >
451  (
453  dNdX,
454  stack.stiffness, // fourth-order tensor handled via DiscretizationOps
455  dNdX,
456  -detJxW );
457 
458  BilinearFormUtilities::compute< displacementTestSpace,
459  displacementTrialSpace,
460  DifferentialOperator::Identity,
461  DifferentialOperator::Divergence >
462  (
464  N,
466  dNdX,
467  detJxW );
468 
469  // Step 3: compute local linear momentum balance residual derivatives with respect to pressure
470  BilinearFormUtilities::compute< displacementTestSpace,
471  pressureTrialSpace,
472  DifferentialOperator::SymmetricGradient,
473  DifferentialOperator::Identity >
474  (
476  dNdX,
478  1.0,
479  -detJxW );
480 
481  BilinearFormUtilities::compute< displacementTestSpace,
482  pressureTrialSpace,
483  DifferentialOperator::Identity,
484  DifferentialOperator::Identity >
485  (
487  N,
488  stack.dBodyForce_dPressure,
489  1.0,
490  detJxW );
491 
492  // Step 4: compute local linear momentum balance residual derivatives with respect to components
493  BilinearFormUtilities::compute< displacementTestSpace,
494  FunctionSpace::P0,
495  DifferentialOperator::Identity,
496  DifferentialOperator::Identity >
497  (
499  N,
501  1.0,
502  detJxW );
503 }
504 
505 template< typename SUBREGION_TYPE,
506  typename CONSTITUTIVE_TYPE,
507  typename FE_TYPE >
511 assembleElementBasedFlowTerms( real64 const ( &dNdX )[numNodesPerElem][3],
512  real64 const & detJxW,
513  StackVariables & stack ) const
514 {
515  using namespace PDEUtilities;
516 
517  constexpr FunctionSpace displacementTrialSpace = FE_TYPE::template getFunctionSpace< numDofPerTrialSupportPoint >();
518  constexpr FunctionSpace displacementTestSpace = displacementTrialSpace;
519 
520  // Step 1: mass balance equations
521 
522  // compute local component mass balance residual
523  LinearFormUtilities::compute< FunctionSpace::P0,
524  DifferentialOperator::Identity >
525  (
526  stack.localResidualMass,
527  1.0,
528  stack.compMassIncrement,
529  detJxW );
530 
531  // compute local mass balance residual derivatives with respect to displacement
532  BilinearFormUtilities::compute< FunctionSpace::P0,
533  displacementTestSpace,
534  DifferentialOperator::Identity,
535  DifferentialOperator::Divergence >
536  (
538  1.0,
540  dNdX,
541  detJxW );
542 
543  // compute local mass balance residual derivatives with respect to pressure
544  BilinearFormUtilities::compute< FunctionSpace::P0,
545  FunctionSpace::P0,
546  DifferentialOperator::Identity,
547  DifferentialOperator::Identity >
548  (
550  1.0,
552  1.0,
553  detJxW );
554 
555  // compute local mass balance residual derivatives with respect to components
556  BilinearFormUtilities::compute< FunctionSpace::P0,
557  FunctionSpace::P0,
558  DifferentialOperator::Identity,
559  DifferentialOperator::Identity >
560  (
562  1.0,
564  1.0,
565  detJxW );
566 
567 
568  // Step 2: pore volume constraint equation
569 
570  // compute local pore volume contraint residual
571  LinearFormUtilities::compute< FunctionSpace::P0,
572  DifferentialOperator::Identity >
573  (
575  1.0,
576  stack.poreVolConstraint,
577  detJxW );
578 
579  // compute local pore volume contraint residual derivatives with respect to pressure
580  BilinearFormUtilities::compute< FunctionSpace::P0,
581  FunctionSpace::P0,
582  DifferentialOperator::Identity,
583  DifferentialOperator::Identity >
584  (
586  1.0,
588  1.0,
589  detJxW );
590 
591  // compute local pore volume contraint residual derivatives with respect to components
592  BilinearFormUtilities::compute< FunctionSpace::P0,
593  FunctionSpace::P0,
594  DifferentialOperator::Identity,
595  DifferentialOperator::Identity >
596  (
598  1.0,
600  1.0,
601  detJxW );
602 }
603 
604 
605 template< typename SUBREGION_TYPE,
606  typename CONSTITUTIVE_TYPE,
607  typename FE_TYPE >
612  localIndex const q,
613  StackVariables & stack ) const
614 {
615  // Step 1: compute displacement finite element basis functions (N), basis function derivatives (dNdX), and
616  // determinant of the Jacobian transformation matrix times the quadrature weight (detJxW)
617  real64 N[numNodesPerElem]{};
618  real64 dNdX[numNodesPerElem][3]{};
619  FE_TYPE::calcN( q, stack.feStack, N );
620  real64 const detJxW = m_finiteElementSpace.template getGradN< FE_TYPE >( k, q, stack.xLocal,
621  stack.feStack, dNdX );
622 
623  // Step 2: compute strain increment
624  LvArray::tensorOps::fill< 6 >( stack.strainIncrement, 0.0 );
625  FE_TYPE::symmetricGradient( dNdX, stack.uhat_local, stack.strainIncrement );
626 
627  // Step 3: compute 1) the total stress, 2) the body force terms, and 3) the fluidMassIncrement
628  // using quantities returned by the PorousSolid constitutive model.
629  // This function also computes the derivatives of these three quantities wrt primary variables
630  smallStrainUpdate( k, q, stack );
631 
632  // Step 4: use the total stress and the body force to increment the local momentum balance residual
633  // This function also fills the local Jacobian rows corresponding to the momentum balance.
634  assembleMomentumBalanceTerms( N, dNdX, detJxW, stack );
635 
636  // Step 5: use the fluid mass increment to increment the local mass balance residual
637  // This function also fills the local Jacobian rows corresponding to the mass balance.
638  assembleElementBasedFlowTerms( dNdX, detJxW, stack );
639 }
640 
644 template< typename SUBREGION_TYPE,
645  typename CONSTITUTIVE_TYPE,
646  typename FE_TYPE >
650 complete( localIndex const k,
651  StackVariables & stack ) const
652 {
653  using namespace compositionalMultiphaseUtilities;
654 
655  GEOS_UNUSED_VAR( k );
656 
657  real64 maxForce = 0;
658  localIndex const numSupportPoints =
659  m_finiteElementSpace.template numSupportPoints< FE_TYPE >( stack.feStack );
660  integer numDisplacementDofs = numSupportPoints * numDofPerTestSupportPoint;
661  constexpr integer maxNumDisplacementDofs = FE_TYPE::maxSupportPoints * numDofPerTestSupportPoint;
662 
663  if( m_useTotalMassEquation > 0 )
664  {
665  // Apply equation/variable change transformation(s)
666  real64 work[maxNumDisplacementDofs > ( maxNumComponents + 1 ) ? maxNumDisplacementDofs : maxNumComponents + 1];
667  shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( m_numComponents, numDisplacementDofs, stack.dLocalResidualMass_dDisplacement, work );
668  shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( m_numComponents, 1, stack.dLocalResidualMass_dPressure, work );
669  shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( m_numComponents, m_numComponents, stack.dLocalResidualMass_dComponents, work );
670  shiftElementsAheadByOneAndReplaceFirstElementWithSum( m_numComponents, stack.localResidualMass );
671  }
672 
673  for( int localNode = 0; localNode < numSupportPoints; ++localNode )
674  {
675  for( int dim = 0; dim < numDofPerTestSupportPoint; ++dim )
676  {
677  localIndex const dof = LvArray::integerConversion< localIndex >( stack.localRowDofIndex[numDofPerTestSupportPoint * localNode + dim] - m_dofRankOffset );
678 
679  // we need this check to filter out ghost nodes in the assembly
680  if( dof < 0 || dof >= m_matrix.numRows() )
681  {
682  continue;
683  }
684  m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof,
685  stack.localRowDofIndex,
686  stack.dLocalResidualMomentum_dDisplacement[numDofPerTestSupportPoint * localNode + dim],
687  numDisplacementDofs );
688 
689  RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[dof], stack.localResidualMomentum[numDofPerTestSupportPoint * localNode + dim] );
690  maxForce = fmax( maxForce, fabs( stack.localResidualMomentum[numDofPerTestSupportPoint * localNode + dim] ) );
691 
692  m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof,
693  &stack.localPressureDofIndex,
694  stack.dLocalResidualMomentum_dPressure[numDofPerTestSupportPoint * localNode + dim],
695  1 );
696 
697  m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof,
699  stack.dLocalResidualMomentum_dComponents[numDofPerTestSupportPoint * localNode + dim],
700  m_numComponents );
701  }
702  }
703 
704  localIndex const dof = LvArray::integerConversion< localIndex >( stack.localPressureDofIndex - m_dofRankOffset );
705 
706  // we need this check to filter out ghost cells in the assembly
707  if( 0 <= dof && dof < m_matrix.numRows() )
708  {
709  for( localIndex i = 0; i < m_numComponents; ++i )
710  {
711  m_matrix.template addToRowBinarySearchUnsorted< serialAtomic >( dof + i,
712  stack.localRowDofIndex,
714  numDisplacementDofs );
715  m_matrix.template addToRow< serialAtomic >( dof + i,
716  &stack.localPressureDofIndex,
718  1 );
719  m_matrix.template addToRow< serialAtomic >( dof + i,
722  m_numComponents );
723  RAJA::atomicAdd< serialAtomic >( &m_rhs[dof+i], stack.localResidualMass[i] );
724  }
725 
726  m_matrix.template addToRow< serialAtomic >( dof + m_numComponents,
727  &stack.localPressureDofIndex,
729  1 );
730 
731  m_matrix.template addToRow< serialAtomic >( dof + m_numComponents,
734  m_numComponents );
735 
736  RAJA::atomicAdd< serialAtomic >( &m_rhs[dof+m_numComponents], stack.localResidualPoreVolConstraint[0] );
737  }
738  return maxForce;
739 }
740 
741 template< typename SUBREGION_TYPE,
742  typename CONSTITUTIVE_TYPE,
743  typename FE_TYPE >
744 template< typename POLICY,
745  typename KERNEL_TYPE >
747 kernelLaunch( localIndex const numElems,
748  KERNEL_TYPE const & kernelComponent )
749 {
751 
752  // Define a RAJA reduction variable to get the maximum residual contribution.
753  RAJA::ReduceMax< ReducePolicy< POLICY >, real64 > maxResidual( 0 );
754 
755  forAll< POLICY >( numElems,
756  [=] GEOS_HOST_DEVICE ( localIndex const k )
757  {
758  typename KERNEL_TYPE::StackVariables stack;
759 
760  kernelComponent.setup( k, stack );
761  for( integer q=0; q<KERNEL_TYPE::numQuadraturePointsPerElem; ++q )
762  {
763  kernelComponent.quadraturePointKernel( k, q, stack );
764  }
765  maxResidual.max( kernelComponent.complete( k, stack ) );
766  } );
767  return maxResidual.get();
768 }
769 
770 
771 
772 } // namespace poromechanicsKernels
773 
774 } // namespace geos
775 
776 #endif // GEOS_PHYSICSSOLVERS_MULTIPHYSICS_MULTIPHASEPOROMECHANICS_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_ERROR_IF_GT_MSG(lhs, rhs, msg)
Raise a hard error if one value compares greater than the other.
Definition: Logger.hpp:275
#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 multiphase poromechanics.
arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > m_fluidPhaseCompFrac
Views on phase component fractions and derivatives.
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.
arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_fluidPhaseDensity
Views on phase densities and derivatives.
GEOS_HOST_DEVICE void computePoreVolumeConstraint(localIndex const k, real64 const &porosity_n, StackVariables &stack) const
Helper function to compute the pore-volume constraint and its derivatives wrt primary variables.
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, FUNC &&bodyForceKernelOp=NoOpFunc{}) const
Helper function to compute the body force term (\rho g) and its derivatives wrt primary variables.
arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > m_fluidPhaseMassDensity
Views on phase mass densities.
static real64 kernelLaunch(localIndex const numElems, KERNEL_TYPE const &kernelComponent)
Kernel Launcher.
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 setup(localIndex const k, StackVariables &stack) const
Copy global values from primary field to a local stack array.
MultiphasePoromechanics(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, localIndex const numComponents, localIndex const numPhases, integer const useSimpleAccumulation, integer const useTotalMassEquation, integer const performStressInitialization, string const fluidModelKey)
Constructor.
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...
GEOS_HOST_DEVICE real64 complete(localIndex const k, StackVariables &stack) const
Performs the complete phase for the kernel.
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, FUNC &&fluidIncrementKernelOp=NoOpFunc{}) const
Helper function to compute the fluid mass increment and its derivatives wrt primary variables.
Defines the kernel structure for solving quasi-static poromechanics.
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
ArraySlice< T, 2, USD > arraySlice2d
Alias for 2D array slice.
Definition: DataTypes.hpp:200
ArraySlice< T, 3, USD > arraySlice3d
Alias for 3D array slice.
Definition: DataTypes.hpp:216
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
ArraySlice< T, 1, USD > arraySlice1d
Alias for 1D array slice.
Definition: DataTypes.hpp:184
std::int32_t integer
Signed integer type.
Definition: DataTypes.hpp:82
real64 dBodyForce_dComponents[3][maxNumComponents]
Derivative of body force wrt comp density.
real64 dLocalResidualMass_dPressure[maxNumComponents][1]
Derivative of mass balance residual wrt pressure.
real64 dCompMassIncrement_dVolStrainIncrement[maxNumComponents]
Derivative of mass accumulation wrt volumetric strain increment.
real64 dCompMassIncrement_dPressure[maxNumComponents]
Derivative of mass accumulation wrt pressure.
real64 dPoreVolConstraint_dComponents[1][maxNumComponents]
Derivative of pore volume constraint wrt comp density.
real64 dLocalResidualMass_dDisplacement[maxNumComponents][Base::StackVariables::numDispDofPerElem]
Derivative of mass balance residual wrt volumetric strain increment.
real64 dCompMassIncrement_dComponents[maxNumComponents][maxNumComponents]
Derivative of mass accumulation wrt comp density.
real64 dLocalResidualPoreVolConstraint_dPressure[1][1]
Derivative of pore volume constraint residual wrt pressure.
globalIndex localComponentDofIndices[maxNumComponents]
C-array storage for the element local row degrees of freedom.
real64 dLocalResidualMomentum_dComponents[Base::StackVariables::numDispDofPerElem][maxNumComponents]
Derivative of momemtum balance residual wrt comp density.
real64 localResidualPoreVolConstraint[1]
Pore volume constraint residual (sum of saturations = 1)
real64 dLocalResidualPoreVolConstraint_dComponents[1][maxNumComponents]
Derivative of pore volume constraint residual wrt components.
real64 dPoreVolConstraint_dPressure
Derivative of pore volume constraint wrt pressure.
real64 dLocalResidualMass_dComponents[maxNumComponents][maxNumComponents]
Derivative of mass balance residual wrt components.
real64(& dLocalResidualMomentum_dDisplacement)[numDispDofPerElem][numDispDofPerElem]
Derivative of linear momentum balance residual wrt displacement.
globalIndex localPressureDofIndex
C-array storage for the element local row degrees of freedom.
real64 dBodyForce_dPressure[3]
Derivative of body force wrt pressure.
real64 dTotalStress_dTemperature[6]
Derivative of total stress wrt temperature.
CONSTITUTIVE_TYPE::KernelWrapper::DiscretizationOps stiffness
Derivative of total stress wrt displacement.
real64 dLocalResidualMomentum_dPressure[numDispDofPerElem][1]
Derivative of linear momentum balance residual wrt pressure.
real64 dTotalStress_dPressure[6]
Derivative of total stress wrt pressure.
real64 dBodyForce_dVolStrainIncrement[3]
Derivative of body force wrt volumetric strain increment.
real64(& localResidualMomentum)[numDispDofPerElem]
Linear momentum balance residual.
real64 deltaTemperatureFromLastStep
Delta temperature since last time step.