GEOS
AccumulationKernel.hpp
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 Total, S.A
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_FLUIDFLOW_COMPOSITIONAL_ACCUMULATIONKERNEL_HPP
21 #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_ACCUMULATIONKERNEL_HPP
22 
23 #include "codingUtilities/Utilities.hpp"
24 #include "common/DataLayouts.hpp"
25 #include "common/DataTypes.hpp"
26 #include "common/GEOS_RAJA_Interface.hpp"
27 #include "constitutive/solid/CoupledSolidBase.hpp"
28 #include "constitutive/fluid/multifluid/MultiFluidBase.hpp"
33 #include "physicsSolvers/fluidFlow/kernels/compositional/KernelLaunchSelectors.hpp"
34 
35 namespace geos
36 {
37 
38 namespace isothermalCompositionalMultiphaseBaseKernels
39 {
40 
41 static constexpr real64 minDensForDivision = 1e-10;
42 
43 enum class KernelFlags
44 {
45  SimpleAccumulation = 1 << 0, // 1
46  TotalMassEquation = 1 << 1, // 2
48  // Flag3 = 1 << 2, // 4
49  // Flag4 = 1 << 3, // 8
50  // Flag5 = 1 << 4, // 16
51  // Flag6 = 1 << 5, // 32
52  // Flag7 = 1 << 6, // 64
53  // Flag8 = 1 << 7 //128
54 };
55 
56 /******************************** AccumulationKernel ********************************/
57 
64 template< integer NUM_COMP, integer NUM_DOF >
66 {
67 public:
68 
70  static constexpr integer numComp = NUM_COMP;
71 
73  static constexpr integer numDof = NUM_DOF;
74 
76  static constexpr integer numEqn = NUM_DOF;
77 
89  AccumulationKernel( localIndex const numPhases,
90  globalIndex const rankOffset,
91  string const dofKey,
92  ElementSubRegionBase const & subRegion,
93  constitutive::MultiFluidBase const & fluid,
94  constitutive::CoupledSolidBase const & solid,
96  arrayView1d< real64 > const & localRhs,
97  BitFlags< KernelFlags > const kernelFlags )
98  : m_numPhases( numPhases ),
99  m_rankOffset( rankOffset ),
100  m_dofNumber( subRegion.getReference< array1d< globalIndex > >( dofKey ) ),
101  m_elemGhostRank( subRegion.ghostRank() ),
102  m_volume( subRegion.getElementVolume() ),
103  m_porosity( solid.getPorosity() ),
104  m_dPoro_dPres( solid.getDporosity_dPressure() ),
105  m_dCompFrac_dCompDens( subRegion.getField< fields::flow::dGlobalCompFraction_dGlobalCompDensity >() ),
106  m_phaseVolFrac( subRegion.getField< fields::flow::phaseVolumeFraction >() ),
107  m_dPhaseVolFrac( subRegion.getField< fields::flow::dPhaseVolumeFraction >() ),
108  m_phaseDens( fluid.phaseDensity() ),
109  m_dPhaseDens( fluid.dPhaseDensity() ),
110  m_phaseCompFrac( fluid.phaseCompFraction() ),
111  m_dPhaseCompFrac( fluid.dPhaseCompFraction() ),
112  m_compDens( subRegion.getField< fields::flow::globalCompDensity >() ),
113  m_compAmount_n( subRegion.getField< fields::flow::compAmount_n >() ),
114  m_localMatrix( localMatrix ),
115  m_localRhs( localRhs ),
116  m_kernelFlags( kernelFlags )
117  {}
118 
124  {
125 public:
126 
127  // Pore volume information (used by both accumulation and volume balance)
128 
131 
134 
135  // Residual information
136 
139 
142 
145 
148 
149  };
150 
157  integer elemGhostRank( localIndex const ei ) const
158  { return m_elemGhostRank( ei ); }
159 
160 
167  void setup( localIndex const ei,
168  StackVariables & stack ) const
169  {
170  // initialize the pore volume
171  stack.poreVolume = m_volume[ei] * m_porosity[ei][0];
172  stack.dPoreVolume_dPres = m_volume[ei] * m_dPoro_dPres[ei][0];
173 
174  // set row index and degrees of freedom indices for this element
175  stack.localRow = m_dofNumber[ei] - m_rankOffset;
176  for( integer idof = 0; idof < numDof; ++idof )
177  {
178  stack.dofIndices[idof] = m_dofNumber[ei] + idof;
179  }
180  }
181 
189  template< typename FUNC = NoOpFunc >
192  StackVariables & stack,
193  FUNC && phaseAmountKernelOp = NoOpFunc{} ) const
194  {
195  if( m_kernelFlags.isSet( KernelFlags::SimpleAccumulation ) )
196  {
197  // ic - index of component whose conservation equation is assembled
198  // (i.e. row number in local matrix)
199  for( integer ic = 0; ic < numComp; ++ic )
200  {
201  real64 const compAmount = stack.poreVolume * m_compDens[ei][ic];
202  real64 const compAmount_n = m_compAmount_n[ei][ic];
203 
204  stack.localResidual[ic] += compAmount - compAmount_n;
205 
206  // Pavel: commented below is some experiment, needs to be re-tested
207  //real64 const compDens = (ic == 0 && m_compDens[ei][ic] < 1e-6) ? 1e-3 : m_compDens[ei][ic];
208  real64 const dCompAmount_dP = stack.dPoreVolume_dPres * m_compDens[ei][ic];
209  stack.localJacobian[ic][0] += dCompAmount_dP;
210 
211  real64 const dCompAmount_dC = stack.poreVolume;
212  stack.localJacobian[ic][ic + 1] += dCompAmount_dC;
213  }
214  }
215  else
216  {
217  using Deriv = constitutive::multifluid::DerivativeOffset;
218 
219  // construct the slices for variables accessed multiple times
220  arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei];
221 
222  arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei];
223  arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei];
224 
225  arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE - 2 > phaseDens = m_phaseDens[ei][0];
226  arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_DC - 2 > dPhaseDens = m_dPhaseDens[ei][0];
227 
228  arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 2 > phaseCompFrac = m_phaseCompFrac[ei][0];
229  arraySlice3d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 2 > dPhaseCompFrac = m_dPhaseCompFrac[ei][0];
230 
231  // temporary work arrays
232  real64 dPhaseAmount_dC[numComp]{};
233  real64 dPhaseCompFrac_dC[numComp]{};
234 
235  // start with old time step values
236  for( integer ic = 0; ic < numComp; ++ic )
237  {
238  stack.localResidual[ic] = -m_compAmount_n[ei][ic];
239  }
240 
241  // sum contributions to component accumulation from each phase
242  for( integer ip = 0; ip < m_numPhases; ++ip )
243  {
244  real64 const phaseAmount = stack.poreVolume * phaseVolFrac[ip] * phaseDens[ip];
245 
246  real64 const dPhaseAmount_dP = stack.dPoreVolume_dPres * phaseVolFrac[ip] * phaseDens[ip]
247  + stack.poreVolume * ( dPhaseVolFrac[ip][Deriv::dP] * phaseDens[ip]
248  + phaseVolFrac[ip] * dPhaseDens[ip][Deriv::dP] );
249 
250  // assemble density dependence
251  applyChainRule( numComp, dCompFrac_dCompDens, dPhaseDens[ip], dPhaseAmount_dC, Deriv::dC );
252  for( integer jc = 0; jc < numComp; ++jc )
253  {
254  dPhaseAmount_dC[jc] = dPhaseAmount_dC[jc] * phaseVolFrac[ip]
255  + phaseDens[ip] * dPhaseVolFrac[ip][Deriv::dC + jc];
256  dPhaseAmount_dC[jc] *= stack.poreVolume;
257  }
258 
259  // ic - index of component whose conservation equation is assembled
260  // (i.e. row number in local matrix)
261  for( integer ic = 0; ic < numComp; ++ic )
262  {
263  real64 const phaseCompAmount = phaseAmount * phaseCompFrac[ip][ic];
264 
265  real64 const dPhaseCompAmount_dP = dPhaseAmount_dP * phaseCompFrac[ip][ic]
266  + phaseAmount * dPhaseCompFrac[ip][ic][Deriv::dP];
267 
268  stack.localResidual[ic] += phaseCompAmount;
269  stack.localJacobian[ic][0] += dPhaseCompAmount_dP;
270 
271  // jc - index of component w.r.t. whose compositional var the derivative is being taken
272  // (i.e. col number in local matrix)
273 
274  // assemble phase composition dependence
275  applyChainRule( numComp, dCompFrac_dCompDens, dPhaseCompFrac[ip][ic], dPhaseCompFrac_dC, Deriv::dC );
276  for( integer jc = 0; jc < numComp; ++jc )
277  {
278  real64 const dPhaseCompAmount_dC = dPhaseCompFrac_dC[jc] * phaseAmount
279  + phaseCompFrac[ip][ic] * dPhaseAmount_dC[jc];
280 
281  stack.localJacobian[ic][jc + 1] += dPhaseCompAmount_dC;
282  }
283  }
284 
285  // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives
286  // possible use: assemble the derivatives wrt temperature, and the accumulation term of the energy equation for this phase
287  phaseAmountKernelOp( ip, phaseAmount, dPhaseAmount_dP, dPhaseAmount_dC );
288 
289  }
290  }
291  }
292 
300  template< typename FUNC = NoOpFunc >
303  StackVariables & stack,
304  FUNC && phaseVolFractionSumKernelOp = NoOpFunc{} ) const
305  {
306  using Deriv = constitutive::multifluid::DerivativeOffset;
307 
308  arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei];
309  arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei];
310 
311  real64 oneMinusPhaseVolFracSum = 1.0;
312 
313  // sum contributions to component accumulation from each phase
314  for( integer ip = 0; ip < m_numPhases; ++ip )
315  {
316  oneMinusPhaseVolFracSum -= phaseVolFrac[ip];
317  stack.localJacobian[numComp][0] -= dPhaseVolFrac[ip][Deriv::dP];
318 
319  for( integer jc = 0; jc < numComp; ++jc )
320  {
321  stack.localJacobian[numComp][jc+1] -= dPhaseVolFrac[ip][Deriv::dC+jc];
322  }
323  }
324 
325  // call the lambda in the phase loop to allow the reuse of the phase amounts and their derivatives
326  // possible use: assemble the derivatives wrt temperature, and use oneMinusPhaseVolFracSum if poreVolume depends on temperature
327  phaseVolFractionSumKernelOp( oneMinusPhaseVolFracSum );
328 
329  // scale saturation-based volume balance by pore volume (for better scaling w.r.t. other equations)
330  stack.localResidual[numComp] = stack.poreVolume * oneMinusPhaseVolFracSum;
331  for( integer idof = 0; idof < numDof; ++idof )
332  {
333  stack.localJacobian[numComp][idof] *= stack.poreVolume;
334  }
335  stack.localJacobian[numComp][0] += stack.dPoreVolume_dPres * oneMinusPhaseVolFracSum;
336  }
337 
345  StackVariables & stack ) const
346  {
347  using namespace compositionalMultiphaseUtilities;
348 
349  if( m_kernelFlags.isSet( KernelFlags::TotalMassEquation ) )
350  {
351  // apply equation/variable change transformation to the component mass balance equations
352  real64 work[numDof]{};
353  shiftRowsAheadByOneAndReplaceFirstRowWithColumnSum( numComp, numDof, stack.localJacobian, work );
354  shiftElementsAheadByOneAndReplaceFirstElementWithSum( numComp, stack.localResidual );
355  }
356 
357  // add contribution to residual and jacobian into:
358  // - the component mass balance equations (i = 0 to i = numComp-1)
359  // - the volume balance equations (i = numComp)
360  // note that numDof includes derivatives wrt temperature if this class is derived in ThermalKernels
361  integer const numRows = numComp+1;
362  for( integer i = 0; i < numRows; ++i )
363  {
364  m_localRhs[stack.localRow + i] += stack.localResidual[i];
365  m_localMatrix.addToRow< serialAtomic >( stack.localRow + i,
366  stack.dofIndices,
367  stack.localJacobian[i],
368  numDof );
369  }
370  }
371 
379  template< typename POLICY, typename KERNEL_TYPE >
380  static void
381  launch( localIndex const numElems,
382  KERNEL_TYPE const & kernelComponent )
383  {
385 
386  forAll< POLICY >( numElems, [=] GEOS_HOST_DEVICE ( localIndex const ei )
387  {
388  if( kernelComponent.elemGhostRank( ei ) >= 0 )
389  {
390  return;
391  }
392 
393  typename KERNEL_TYPE::StackVariables stack;
394 
395  kernelComponent.setup( ei, stack );
396  kernelComponent.computeAccumulation( ei, stack );
397  kernelComponent.computeVolumeBalance( ei, stack );
398  kernelComponent.complete( ei, stack );
399  } );
400  }
401 
402 protected:
403 
406 
409 
412 
415 
418 
421  arrayView2d< real64 const > const m_dPoro_dPres;
422 
425 
429 
433 
437 
438  // View on component densities
440 
441  // View on component amount (mass/moles) from previous time step
443 
448 
449  BitFlags< KernelFlags > const m_kernelFlags;
450 };
451 
456 {
457 public:
458 
472  template< typename POLICY >
473  static void
474  createAndLaunch( integer const numComps,
475  integer const numPhases,
476  globalIndex const rankOffset,
477  integer const useTotalMassEquation,
478  integer const useSimpleAccumulation,
479  string const dofKey,
480  ElementSubRegionBase const & subRegion,
481  constitutive::MultiFluidBase const & fluid,
482  constitutive::CoupledSolidBase const & solid,
483  CRSMatrixView< real64, globalIndex const > const & localMatrix,
484  arrayView1d< real64 > const & localRhs )
485  {
486  internal::kernelLaunchSelectorCompSwitch( numComps, [&] ( auto NC )
487  {
488  integer constexpr NUM_COMP = NC();
489  integer constexpr NUM_DOF = NC()+1;
490 
491  BitFlags< KernelFlags > kernelFlags;
492  if( useTotalMassEquation )
493  kernelFlags.set( KernelFlags::TotalMassEquation );
494  if( useSimpleAccumulation )
495  kernelFlags.set( KernelFlags::SimpleAccumulation );
496 
497  AccumulationKernel< NUM_COMP, NUM_DOF > kernel( numPhases, rankOffset, dofKey, subRegion,
498  fluid, solid, localMatrix, localRhs, kernelFlags );
499  AccumulationKernel< NUM_COMP, NUM_DOF >::template launch< POLICY >( subRegion.size(), kernel );
500  } );
501  }
502 
503 };
504 
505 } // namespace isothermalCompositionalMultiphaseBaseKernels
506 
507 } // namespace geos
508 
509 
510 #endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_ACCUMULATIONKERNEL_HPP
#define GEOS_HOST_DEVICE
Marks a host-device function.
Definition: GeosxMacros.hpp:49
#define GEOS_UNUSED_PARAM(X)
Mark an unused argument and silence compiler warnings.
Definition: GeosxMacros.hpp:72
#define GEOS_MARK_FUNCTION
Mark function with both Caliper and NVTX if enabled.
localIndex size() const
Get the "size" of the group, which determines the number of elements in resizable wrappers.
Definition: Group.hpp:1315
static void createAndLaunch(integer const numComps, integer const numPhases, globalIndex const rankOffset, integer const useTotalMassEquation, integer const useSimpleAccumulation, string const dofKey, ElementSubRegionBase const &subRegion, constitutive::MultiFluidBase const &fluid, constitutive::CoupledSolidBase const &solid, CRSMatrixView< real64, globalIndex const > const &localMatrix, arrayView1d< real64 > const &localRhs)
Create a new kernel and launch.
Define the interface for the assembly kernel in charge of accumulation and volume balance.
static constexpr integer numDof
Compute time value for the number of degrees of freedom.
arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFrac
Views on the phase volume fractions.
GEOS_HOST_DEVICE void complete(localIndex const GEOS_UNUSED_PARAM(ei), StackVariables &stack) const
Performs the complete phase for the kernel.
arrayView1d< integer const > const m_elemGhostRank
View on the ghost ranks.
CRSMatrixView< real64, globalIndex const > const m_localMatrix
View on the local CRS matrix.
arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > const m_phaseCompFrac
Views on the phase component fraction.
static void launch(localIndex const numElems, KERNEL_TYPE const &kernelComponent)
Performs the kernel launch.
static constexpr integer numEqn
Compute time value for the number of equations.
AccumulationKernel(localIndex const numPhases, globalIndex const rankOffset, string const dofKey, ElementSubRegionBase const &subRegion, constitutive::MultiFluidBase const &fluid, constitutive::CoupledSolidBase const &solid, CRSMatrixView< real64, globalIndex const > const &localMatrix, arrayView1d< real64 > const &localRhs, BitFlags< KernelFlags > const kernelFlags)
Constructor.
GEOS_HOST_DEVICE void computeVolumeBalance(localIndex const ei, StackVariables &stack, FUNC &&phaseVolFractionSumKernelOp=NoOpFunc{}) const
Compute the local volume balance contributions to the residual and Jacobian.
arrayView3d< real64 const, compflow::USD_COMP_DC > const m_dCompFrac_dCompDens
Views on the derivatives of comp fractions wrt component density.
arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > const m_phaseDens
Views on the phase densities.
arrayView2d< real64 const > const m_porosity
Views on the porosity.
arrayView1d< real64 > const m_localRhs
View on the local RHS.
GEOS_HOST_DEVICE void computeAccumulation(localIndex const ei, StackVariables &stack, FUNC &&phaseAmountKernelOp=NoOpFunc{}) const
Compute the local accumulation contributions to the residual and Jacobian.
GEOS_HOST_DEVICE integer elemGhostRank(localIndex const ei) const
Getter for the ghost rank of an element.
GEOS_HOST_DEVICE void setup(localIndex const ei, StackVariables &stack) const
Performs the setup phase for the kernel.
arrayView1d< real64 const > const m_volume
View on the element volumes.
static constexpr integer numComp
Compile time value for the number of components.
arrayView1d< globalIndex const > const m_dofNumber
View on the dof numbers.
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
ArrayView< T, 5, USD > arrayView5d
Alias for 5D array view.
Definition: DataTypes.hpp:244
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
ArrayView< T, 4, USD > arrayView4d
Alias for 4D array view.
Definition: DataTypes.hpp:228
ArrayView< T, 2, USD > arrayView2d
Alias for 2D array view.
Definition: DataTypes.hpp:196
Array< T, 1 > array1d
Alias for 1D array.
Definition: DataTypes.hpp:176
ArrayView< T, 3, USD > arrayView3d
Alias for 3D array view.
Definition: DataTypes.hpp:212
Kernel variables (dof numbers, jacobian and residual) located on the stack.
globalIndex dofIndices[numDof]
Indices of the matrix rows/columns corresponding to the dofs in this element.
localIndex localRow
Index of the local row corresponding to this element.
real64 localJacobian[numEqn][numDof]
C-array storage for the element local Jacobian matrix (all equations except volume balance,...
real64 localResidual[numEqn]
C-array storage for the element local residual vector (all equations except volume balance)