GEOS
ThermalFluxComputeKernel.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_FLUIDFLOW_SINGLEPHASE_THERMALFLUXCOMPUTEKERNEL_HPP
21 #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALFLUXCOMPUTEKERNEL_HPP
22 
24 
25 #include "constitutive/thermalConductivity/SinglePhaseThermalConductivityBase.hpp"
26 #include "constitutive/thermalConductivity/ThermalConductivityFields.hpp"
27 
28 namespace geos
29 {
30 
31 namespace thermalSinglePhaseFVMKernels
32 {
33 /******************************** FluxComputeKernel ********************************/
34 
41 template< integer NUM_EQN, integer NUM_DOF, typename STENCILWRAPPER >
42 class FluxComputeKernel : public singlePhaseFVMKernels::FluxComputeKernel< NUM_EQN, NUM_DOF, STENCILWRAPPER >
43 {
44 public:
45 
52  template< typename VIEWTYPE >
54 
56  using DofNumberAccessor = AbstractBase::DofNumberAccessor;
60 
61  using AbstractBase::m_dt;
64  using AbstractBase::m_gravCoef;
65  using AbstractBase::m_mob;
66  using AbstractBase::m_dMob;
68  using AbstractBase::m_dDens;
69 
71  using Base::numDof;
72  using Base::numEqn;
73  using Base::maxNumElems;
74  using Base::maxNumConns;
77  using Base::m_seri;
78  using Base::m_sesri;
79  using Base::m_sei;
80 
83 
85  StencilMaterialAccessors< constitutive::SingleFluidBase,
86  fields::singlefluid::enthalpy,
87  fields::singlefluid::dEnthalpy >;
88 
90  StencilMaterialAccessors< constitutive::SinglePhaseThermalConductivityBase,
91  fields::thermalconductivity::effectiveConductivity,
92  fields::thermalconductivity::dEffectiveConductivity_dT >;
93 
94 
110  FluxComputeKernel( globalIndex const rankOffset,
111  STENCILWRAPPER const & stencilWrapper,
112  DofNumberAccessor const & dofNumberAccessor,
113  SinglePhaseFlowAccessors const & singlePhaseFlowAccessors,
114  ThermalSinglePhaseFlowAccessors const & thermalSinglePhaseFlowAccessors,
115  SinglePhaseFluidAccessors const & singlePhaseFluidAccessors,
116  ThermalSinglePhaseFluidAccessors const & thermalSinglePhaseFluidAccessors,
117  PermeabilityAccessors const & permeabilityAccessors,
118  ThermalConductivityAccessors const & thermalConductivityAccessors,
119  real64 const & dt,
120  CRSMatrixView< real64, globalIndex const > const & localMatrix,
121  arrayView1d< real64 > const & localRhs )
122  : Base( rankOffset,
123  stencilWrapper,
124  dofNumberAccessor,
125  singlePhaseFlowAccessors,
126  singlePhaseFluidAccessors,
127  permeabilityAccessors,
128  dt,
129  localMatrix,
130  localRhs ),
131  m_temp( thermalSinglePhaseFlowAccessors.get( fields::flow::temperature {} ) ),
132  m_enthalpy( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::enthalpy {} ) ),
133  m_dEnthalpy( thermalSinglePhaseFluidAccessors.get( fields::singlefluid::dEnthalpy {} ) ),
134  m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) ),
135  m_dThermalCond_dT( thermalConductivityAccessors.get( fields::thermalconductivity::dEffectiveConductivity_dT {} ) )
136  {}
137 
139  {
140 public:
141 
143  StackVariables( localIndex const size, localIndex numElems )
144  : Base::StackVariables( size, numElems ),
145  energyFlux( 0.0 ),
146  dEnergyFlux_dP( size ),
147  dEnergyFlux_dT( size )
148  {}
149 
157 
158  // Thermal transmissibility
159  real64 thermalTransmissibility[maxNumConns][2]{};
160 
163 
164  // Energy fluxes and derivatives
165 
172 
173  };
174 
181  void computeFlux( localIndex const iconn,
182  StackVariables & stack ) const
183  {
184  using DerivOffset = constitutive::singlefluid::DerivativeOffsetC< 1 >;
185  // ***********************************************
186  // First, we call the base computeFlux to compute:
187  // 1) compFlux and its derivatives (including derivatives wrt temperature),
188  // 2) enthalpy part of energyFlux and its derivatives (including derivatives wrt temperature)
189  //
190  // Computing dFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux,
191  // such as potGrad, fluxVal, and the indices of the upwind cell
192  // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables
193  Base::computeFlux( iconn, stack, [&] ( localIndex const (&k)[2],
194  localIndex const (&seri)[2],
195  localIndex const (&sesri)[2],
196  localIndex const (&sei)[2],
197  localIndex const connectionIndex,
198  real64 const alpha,
199  real64 const mobility,
200  real64 const & potGrad,
201  real64 const & fluxVal,
202  real64 const (&dFlux_dP)[2] )
203  {
204  // Step 1: compute the derivatives of the mean density at the interface wrt temperature
205 
206  real64 dDensMean_dT[2]{0.0, 0.0};
207 
208  real64 const trans[2] = { stack.transmissibility[connectionIndex][0], stack.transmissibility[connectionIndex][1] };
209 
210  for( integer ke = 0; ke < 2; ++ke )
211  {
212  dDensMean_dT[ke] = 0.5 * m_dDens[seri[ke]][sesri[ke]][sei[ke]][0][DerivOffset::dT];
213  }
214 
215  // Step 2: compute the derivatives of the potential difference wrt temperature
216  //***** calculation of flux *****
217 
218  real64 dGravHead_dT[2]{0.0, 0.0};
219 
220  // compute potential difference
221  for( integer ke = 0; ke < 2; ++ke )
222  {
223  localIndex const er = seri[ke];
224  localIndex const esr = sesri[ke];
225  localIndex const ei = sei[ke];
226 
227  // compute derivative of gravity potential difference wrt temperature
228  real64 const gravD = trans[ke] * m_gravCoef[er][esr][ei];
229 
230  for( integer i = 0; i < 2; ++i )
231  {
232  dGravHead_dT[i] += dDensMean_dT[i] * gravD;
233  }
234  }
235 
236  // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature
237  // *** upwinding ***
238 
239  real64 dFlux_dT[2]{0.0, 0.0};
240 
241  // Step 3.1: compute the derivative of flux wrt temperature
242  for( integer ke = 0; ke < 2; ++ke )
243  {
244  dFlux_dT[ke] -= dGravHead_dT[ke];
245  }
246 
247  for( integer ke = 0; ke < 2; ++ke )
248  {
249  dFlux_dT[ke] *= mobility;
250  }
251 
252  real64 dMob_dT[2]{};
253 
254  if( alpha <= 0.0 || alpha >= 1.0 )
255  {
256  localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) );
257  dMob_dT[k_up] = m_dMob[seri[k_up]][sesri[k_up]][sei[k_up]][DerivOffset::dT];
258  }
259  else
260  {
261  real64 const mobWeights[2] = { alpha, 1.0 - alpha };
262  for( integer ke = 0; ke < 2; ++ke )
263  {
264  dMob_dT[ke] = mobWeights[ke] * m_dMob[seri[ke]][sesri[ke]][sei[ke]][DerivOffset::dT];
265  }
266  }
267 
268  // add contribution from upstream cell mobility derivatives
269  for( integer ke = 0; ke < 2; ++ke )
270  {
271  dFlux_dT[ke] += dMob_dT[ke] * potGrad;
272  }
273 
274  // add dFlux_dTemp to localFluxJacobian
275  for( integer ke = 0; ke < 2; ++ke )
276  {
277  localIndex const localDofIndexTemp = k[ke] * numDof + numDof - 1;
278  stack.localFluxJacobian[k[0]*numEqn][localDofIndexTemp] += m_dt * dFlux_dT[ke];
279  stack.localFluxJacobian[k[1]*numEqn][localDofIndexTemp] -= m_dt * dFlux_dT[ke];
280  }
281 
282  // Step 4: compute the enthalpy flux
283  real64 enthalpy = 0.0;
284  real64 dEnthalpy_dP[2]{0.0, 0.0};
285  real64 dEnthalpy_dT[2]{0.0, 0.0};
286 
287  if( alpha <= 0.0 || alpha >= 1.0 )
288  {
289  localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) );
290 
291  enthalpy = m_enthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0];
292  dEnthalpy_dP[k_up] = m_dEnthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0][DerivOffset::dP];
293  dEnthalpy_dT[k_up] = m_dEnthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0][DerivOffset::dT];
294  }
295  else
296  {
297  real64 const mobWeights[2] = { alpha, 1.0 - alpha };
298  for( integer ke = 0; ke < 2; ++ke )
299  {
300  enthalpy += mobWeights[ke] * m_enthalpy[seri[ke]][sesri[ke]][sei[ke]][0];
301  dEnthalpy_dP[ke] = mobWeights[ke] * m_dEnthalpy[seri[ke]][sesri[ke]][sei[ke]][0][DerivOffset::dP];
302  dEnthalpy_dT[ke] = mobWeights[ke] * m_dEnthalpy[seri[ke]][sesri[ke]][sei[ke]][0][DerivOffset::dT];
303  }
304  }
305 
306  stack.energyFlux += fluxVal * enthalpy;
307 
308  for( integer ke = 0; ke < 2; ++ke )
309  {
310  stack.dEnergyFlux_dP[ke] += dFlux_dP[ke] * enthalpy;
311  stack.dEnergyFlux_dT[ke] += dFlux_dT[ke] * enthalpy;
312  }
313 
314  for( integer ke = 0; ke < 2; ++ke )
315  {
316  stack.dEnergyFlux_dP[ke] += fluxVal * dEnthalpy_dP[ke];
317  stack.dEnergyFlux_dT[ke] += fluxVal * dEnthalpy_dT[ke];
318  }
319 
320  } );
321 
322  // *****************************************************
323  // Computation of the conduction term in the energy flux
324  // Note that the enthalpy term in the energy was computed above
325  // Note that this term is computed using an explicit treatment of conductivity for now
326 
327  // Step 1: compute the thermal transmissibilities at this face
328  // We follow how the thermal compositional multi-phase solver does to update the thermal transmissibility
329  m_stencilWrapper.computeWeights( iconn,
332  stack.thermalTransmissibility,
333  stack.dThermalTrans_dT );
334 
335  localIndex k[2];
336  localIndex connectionIndex = 0;
337 
338  for( k[0] = 0; k[0] < stack.numFluxElems; ++k[0] )
339  {
340  for( k[1] = k[0] + 1; k[1] < stack.numFluxElems; ++k[1] )
341  {
342  real64 const thermalTrans[2] = { stack.thermalTransmissibility[connectionIndex][0], stack.thermalTransmissibility[connectionIndex][1] };
343  real64 const dThermalTrans_dT[2] = { stack.dThermalTrans_dT[connectionIndex][0], stack.dThermalTrans_dT[connectionIndex][1] };
344 
345  localIndex const seri[2] = {m_seri( iconn, k[0] ), m_seri( iconn, k[1] )};
346  localIndex const sesri[2] = {m_sesri( iconn, k[0] ), m_sesri( iconn, k[1] )};
347  localIndex const sei[2] = {m_sei( iconn, k[0] ), m_sei( iconn, k[1] )};
348 
349  // Step 2: compute temperature difference at the interface
350  for( integer ke = 0; ke < 2; ++ke )
351  {
352  localIndex const er = seri[ke];
353  localIndex const esr = sesri[ke];
354  localIndex const ei = sei[ke];
355 
356  stack.energyFlux += thermalTrans[ke] * m_temp[er][esr][ei];
357  stack.dEnergyFlux_dT[ke] += thermalTrans[ke] + dThermalTrans_dT[ke] * m_temp[er][esr][ei];
358  }
359 
360  // add energyFlux and its derivatives to localFlux and localFluxJacobian
361  stack.localFlux[k[0]*numEqn + numEqn - 1] += m_dt * stack.energyFlux;
362  stack.localFlux[k[1]*numEqn + numEqn - 1] -= m_dt * stack.energyFlux;
363 
364  for( integer ke = 0; ke < 2; ++ke )
365  {
366  integer const localDofIndexPres = k[ke] * numDof;
367  stack.localFluxJacobian[k[0]*numEqn + numEqn - 1][localDofIndexPres] = m_dt * stack.dEnergyFlux_dP[ke];
368  stack.localFluxJacobian[k[1]*numEqn + numEqn - 1][localDofIndexPres] = -m_dt * stack.dEnergyFlux_dP[ke];
369  integer const localDofIndexTemp = localDofIndexPres + numDof - 1;
370  stack.localFluxJacobian[k[0]*numEqn + numEqn - 1][localDofIndexTemp] = m_dt * stack.dEnergyFlux_dT[ke];
371  stack.localFluxJacobian[k[1]*numEqn + numEqn - 1][localDofIndexTemp] = -m_dt * stack.dEnergyFlux_dT[ke];
372  }
373 
374  connectionIndex++;
375  }
376  }
377  }
378 
385  void complete( localIndex const iconn,
386  StackVariables & stack ) const
387  {
388  // Call Case::complete to assemble the mass balance equations
389  // In the lambda, add contribution to residual and jacobian into the energy balance equation
390  Base::complete( iconn, stack, [&] ( integer const i,
391  localIndex const localRow )
392  {
393  // The no. of fluxes is equal to the no. of equations in m_localRhs and m_localMatrix
394  // Different from the one in compositional multi-phase flow, which has a volume balance eqn.
395  RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn-1], stack.localFlux[i * numEqn + numEqn-1] );
396 
397  AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >( localRow + numEqn-1,
398  stack.dofColIndices.data(),
399  stack.localFluxJacobian[i * numEqn + numEqn-1].dataIfContiguous(),
400  stack.stencilSize * numDof );
401 
402  } );
403  }
404 
405 protected:
406 
409 
413 
416 
419 
420 };
421 
426 {
427 public:
428 
442  template< typename POLICY, typename STENCILWRAPPER >
443  static void
444  createAndLaunch( globalIndex const rankOffset,
445  string const & dofKey,
446  string const & solverName,
447  ElementRegionManager const & elemManager,
448  STENCILWRAPPER const & stencilWrapper,
449  real64 const & dt,
450  CRSMatrixView< real64, globalIndex const > const & localMatrix,
451  arrayView1d< real64 > const & localRhs )
452  {
453  integer constexpr NUM_DOF = 2;
454  integer constexpr NUM_EQN = 2;
455 
457  elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey );
458  dofNumberAccessor.setName( solverName + "/accessors/" + dofKey );
459 
461  typename KernelType::SinglePhaseFlowAccessors flowAccessors( elemManager, solverName );
462  typename KernelType::ThermalSinglePhaseFlowAccessors thermalFlowAccessors( elemManager, solverName );
463  typename KernelType::SinglePhaseFluidAccessors fluidAccessors( elemManager, solverName );
464  typename KernelType::ThermalSinglePhaseFluidAccessors thermalFluidAccessors( elemManager, solverName );
465  typename KernelType::PermeabilityAccessors permAccessors( elemManager, solverName );
466  typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName );
467 
468  KernelType kernel( rankOffset, stencilWrapper, dofNumberAccessor,
469  flowAccessors, thermalFlowAccessors, fluidAccessors, thermalFluidAccessors,
470  permAccessors, thermalConductivityAccessors,
471  dt, localMatrix, localRhs );
472  KernelType::template launch< POLICY >( stencilWrapper.size(), kernel );
473  }
474 };
475 
476 } // namespace thermalSinglePhaseFVMKernels
477 
478 } // namespace geos
479 
480 #endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_THERMALFLUXCOMPUTEKERNEL_HPP
#define GEOS_HOST_DEVICE
Marks a host-device function.
Definition: GeosxMacros.hpp:49
The ElementRegionManager class provides an interface to ObjectManagerBase in order to manage ElementR...
ElementViewAccessor< ArrayView< T const, NDIM, getUSD< PERM > > > constructArrayViewAccessor(string const &name, string const &neighborName=string()) const
This is a function to construct a ElementViewAccessor to access array data registered on the mesh.
array1d< array1d< VIEWTYPE > > ElementViewAccessor
The ElementViewAccessor at the ElementRegionManager level is an array of array of VIEWTYPE.
typename ElementViewAccessor< VIEWTYPE >::NestedViewTypeConst ElementViewConst
The ElementViewAccessor at the ElementRegionManager level is the type resulting from ElementViewAcces...
A struct to automatically construct and store element view accessors.
A struct to automatically construct and store element view accessors.
Base class for FluxComputeKernel that holds all data not dependent on template parameters (like stenc...
ElementViewConst< arrayView1d< real64 const > > const m_mob
Views on fluid mobility.
ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber
Views on dof numbers.
arrayView1d< real64 > const m_localRhs
View on the local RHS.
ElementViewConst< arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > > const m_dens
Views on fluid density.
globalIndex const m_rankOffset
Offset for my MPI rank.
CRSMatrixView< real64, globalIndex const > const m_localMatrix
View on the local CRS matrix.
Define the interface for the assembly kernel in charge of flux terms.
static constexpr integer numEqn
Compute time value for the number of equations.
static constexpr localIndex maxNumConns
Maximum number of connections at the face.
GEOS_HOST_DEVICE void complete(localIndex const iconn, StackVariables &stack, FUNC &&kernelOp=NoOpFunc{}) const
Performs the complete phase for the kernel.
static constexpr localIndex maxStencilSize
Maximum number of points in the stencil.
STENCILWRAPPER::IndexContainerViewConstType const m_seri
Connection to element maps.
static constexpr integer numDof
Compute time value for the number of degrees of freedom.
STENCILWRAPPER const m_stencilWrapper
Reference to the stencil wrapper.
GEOS_HOST_DEVICE void computeFlux(localIndex const iconn, StackVariables &stack, FUNC &&kernelOp=NoOpFunc{}) const
Compute the local flux contributions to the residual and Jacobian.
static constexpr localIndex maxNumElems
Maximum number of elements at the face.
static void createAndLaunch(globalIndex const rankOffset, string const &dofKey, string const &solverName, ElementRegionManager const &elemManager, STENCILWRAPPER const &stencilWrapper, real64 const &dt, 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 flux terms.
static constexpr integer numEqn
Compute time value for the number of equations.
ElementViewConst< arrayView1d< real64 const > > const m_temp
Views on temperature.
ElementViewConst< arrayView3d< real64 const > > m_dThermalCond_dT
View on derivatives of thermal conductivity w.r.t. temperature.
static constexpr localIndex maxNumConns
Maximum number of connections at the face.
STENCILWRAPPER::IndexContainerViewConstType const m_seri
Connection to element maps.
FluxComputeKernel(globalIndex const rankOffset, STENCILWRAPPER const &stencilWrapper, DofNumberAccessor const &dofNumberAccessor, SinglePhaseFlowAccessors const &singlePhaseFlowAccessors, ThermalSinglePhaseFlowAccessors const &thermalSinglePhaseFlowAccessors, SinglePhaseFluidAccessors const &singlePhaseFluidAccessors, ThermalSinglePhaseFluidAccessors const &thermalSinglePhaseFluidAccessors, PermeabilityAccessors const &permeabilityAccessors, ThermalConductivityAccessors const &thermalConductivityAccessors, real64 const &dt, CRSMatrixView< real64, globalIndex const > const &localMatrix, arrayView1d< real64 > const &localRhs)
Constructor for the kernel interface.
ElementViewConst< arrayView2d< real64 const, constitutive::singlefluid::USD_FLUID > > const m_enthalpy
Views on enthalpies.
static constexpr integer numDof
Compute time value for the number of degrees of freedom.
GEOS_HOST_DEVICE void complete(localIndex const iconn, StackVariables &stack) const
Performs the complete phase for the kernel.
GEOS_HOST_DEVICE void computeFlux(localIndex const iconn, StackVariables &stack) const
Compute the local flux contributions to the residual and Jacobian.
ElementViewConst< arrayView3d< real64 const > > m_thermalConductivity
View on thermal conductivity.
STENCILWRAPPER const m_stencilWrapper
Reference to the stencil wrapper.
ElementRegionManager::ElementViewConst< VIEWTYPE > ElementViewConst
The type for element-based data. Consists entirely of ArrayView's.
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
StackArray< T, 1, MAXSIZE > stackArray1d
Alias for 1D stack array.
Definition: DataTypes.hpp:188
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
Kernel variables (dof numbers, jacobian and residual) located on the stack.
real64 dTrans_dPres[maxNumConns][2]
Derivatives of transmissibility with respect to pressure.
stackArray1d< globalIndex, maxNumElems *numDof > dofColIndices
Indices of the matrix rows/columns corresponding to the dofs in this face.
stackArray1d< real64, maxNumElems *numEqn > localFlux
Storage for the face local residual vector (all equations except volume balance)
localIndex const stencilSize
Stencil size for a given connection.
stackArray2d< real64, maxNumElems *numEqn *maxStencilSize *numDof > localFluxJacobian
Storage for the face local Jacobian matrix.
localIndex const numFluxElems
Number of elements for a given connection.
stackArray1d< real64, maxStencilSize > dEnergyFlux_dP
Derivatives of energy fluxes wrt pressure.
real64 dThermalTrans_dT[maxNumConns][2]
Derivatives of thermal transmissibility with respect to temperature.
stackArray1d< real64, maxStencilSize > dEnergyFlux_dT
Derivatives of energy fluxes wrt temperature.