GEOS
ThermalDirichletFluxComputeKernel.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 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_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP
21 #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP
22 
24 #include "constitutive/fluid/multifluid/MultiFluidBase.hpp"
25 #include "constitutive/fluid/multifluid/MultiFluidFields.hpp"
26 #include "constitutive/thermalConductivity/MultiPhaseThermalConductivityBase.hpp"
27 #include "constitutive/thermalConductivity/ThermalConductivityFields.hpp"
28 
29 namespace geos
30 {
31 
32 namespace thermalCompositionalMultiphaseFVMKernels
33 {
34 
35 /******************************** DirichletFluxComputeKernel ********************************/
36 
44 template< integer NUM_COMP, integer NUM_DOF, typename FLUIDWRAPPER >
46  NUM_DOF,
47  FLUIDWRAPPER >
48 {
49 public:
50 
57  template< typename VIEWTYPE >
59 
61  using DofNumberAccessor = AbstractBase::DofNumberAccessor;
66 
67  using AbstractBase::m_dt;
71  using AbstractBase::m_gravCoef;
73  using AbstractBase::m_dPhaseCompFrac;
75 
77  using Base::numComp;
78  using Base::numDof;
79  using Base::numEqn;
80  using Base::m_phaseMob;
81  using Base::m_dPhaseMob;
82  using Base::m_dPhaseMassDens;
84  using Base::m_seri;
85  using Base::m_sesri;
86  using Base::m_sei;
87  using Base::m_faceTemp;
89 
90 
93 
95  StencilMaterialAccessors< constitutive::MultiFluidBase,
96  fields::multifluid::phaseEnthalpy,
97  fields::multifluid::dPhaseEnthalpy >;
98 
100  StencilMaterialAccessors< constitutive::MultiPhaseThermalConductivityBase,
101  fields::thermalconductivity::effectiveConductivity >;
102  // for now, we treat thermal conductivity explicitly
103 
125  globalIndex const rankOffset,
126  FaceManager const & faceManager,
127  BoundaryStencilWrapper const & stencilWrapper,
128  FLUIDWRAPPER const & fluidWrapper,
129  DofNumberAccessor const & dofNumberAccessor,
130  CompFlowAccessors const & compFlowAccessors,
131  ThermalCompFlowAccessors const & thermalCompFlowAccessors,
132  MultiFluidAccessors const & multiFluidAccessors,
133  ThermalMultiFluidAccessors const & thermalMultiFluidAccessors,
134  CapPressureAccessors const & capPressureAccessors,
135  PermeabilityAccessors const & permeabilityAccessors,
136  ThermalConductivityAccessors const & thermalConductivityAccessors,
137  real64 const dt,
138  CRSMatrixView< real64, globalIndex const > const & localMatrix,
139  arrayView1d< real64 > const & localRhs,
140  BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags )
141  : Base( numPhases,
142  rankOffset,
143  faceManager,
144  stencilWrapper,
145  fluidWrapper,
146  dofNumberAccessor,
147  compFlowAccessors,
148  multiFluidAccessors,
149  capPressureAccessors,
150  permeabilityAccessors,
151  dt,
152  localMatrix,
153  localRhs,
154  kernelFlags ),
155  m_temp( thermalCompFlowAccessors.get( fields::flow::temperature {} ) ),
156  m_phaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::phaseEnthalpy {} ) ),
157  m_dPhaseEnthalpy( thermalMultiFluidAccessors.get( fields::multifluid::dPhaseEnthalpy {} ) ),
158  m_thermalConductivity( thermalConductivityAccessors.get( fields::thermalconductivity::effectiveConductivity {} ) )
159  {}
160 
161  struct StackVariables : public Base::StackVariables
162  {
163 public:
164 
171  StackVariables( localIndex const size, localIndex numElems )
172  : Base::StackVariables( size, numElems )
173  {}
174 
175  using Base::StackVariables::transmissibility;
176  using Base::StackVariables::dofColIndices;
177  using Base::StackVariables::localFlux;
178  using Base::StackVariables::localFluxJacobian;
179 
180  // Component fluxes and derivatives
181 
184 
185 
186  // Energy fluxes and derivatives
187 
196 
197  };
198 
205  void computeFlux( localIndex const iconn,
206  StackVariables & stack ) const
207  {
208  using Order = BoundaryStencil::Order;
209  using Deriv = constitutive::multifluid::DerivativeOffset;
210 
211  // ***********************************************
212  // First, we call the base computeFlux to compute:
213  // 1) compFlux and its derivatives (including derivatives wrt temperature),
214  // 2) enthalpy part of energyFlux and its derivatives (including derivatives wrt temperature)
215  //
216  // Computing dCompFlux_dT and the enthalpy flux requires quantities already computed in the base computeFlux,
217  // such as potGrad, phaseFlux, and the indices of the upwind cell
218  // We use the lambda below (called **inside** the phase loop of the base computeFlux) to access these variables
219  Base::computeFlux( iconn, stack, [&] ( integer const ip,
220  localIndex const er,
221  localIndex const esr,
222  localIndex const ei,
223  localIndex const kf,
224  real64 const f, // potGrad times trans
225  real64 const facePhaseMob,
228  real64 const phaseFlux,
229  real64 const dPhaseFlux_dP,
230  real64 const (&dPhaseFlux_dC)[numComp] )
231  {
232  // We are in the loop over phases, ip provides the current phase index.
233 
234  // Step 1: compute the derivatives of the mean density at the interface wrt temperature
235 
236  real64 const dDensMean_dT = 0.5 * m_dPhaseMassDens[er][esr][ei][0][ip][Deriv::dT];
237 
238  // Step 2: compute the derivatives of the phase potential difference wrt temperature
239  //***** calculation of flux *****
240 
241  real64 const dF_dT = -stack.transmissibility * dDensMean_dT * ( m_gravCoef[er][esr][ei] - m_faceGravCoef[kf] );
242 
243  // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature
244  // *** upwinding ***
245 
246  // note: the upwinding is done in the base class, which is in charge of
247  // computing the following quantities: potGrad, phaseFlux
248  // It is easier to hard-code the if/else because it is difficult to address elem and face variables in a uniform way
249 
250 
251  if( f >= 0 ) // the element is upstream
252  {
253 
254  // Step 3.1.a: compute the derivative of phase flux wrt temperature
255  real64 const dPhaseFlux_dT = m_phaseMob[er][esr][ei][ip] * dF_dT + m_dPhaseMob[er][esr][ei][ip][Deriv::dT] * f;
256 
257  // Step 3.2.a: compute the derivative of component flux wrt temperature
258 
259  // slice some constitutive arrays to avoid too much indexing in component loop
260  arraySlice1d< real64 const, constitutive::multifluid::USD_PHASE_COMP - 3 > phaseCompFracSub =
261  m_phaseCompFrac[er][esr][ei][0][ip];
262  arraySlice2d< real64 const, constitutive::multifluid::USD_PHASE_COMP_DC - 3 > dPhaseCompFracSub =
263  m_dPhaseCompFrac[er][esr][ei][0][ip];
264 
265  for( integer ic = 0; ic < numComp; ++ic )
266  {
267  real64 const ycp = phaseCompFracSub[ic];
268  stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp + phaseFlux * dPhaseCompFracSub[ic][Deriv::dT];
269  }
270 
271  // Step 3.3.a: compute the enthalpy flux
272 
273  real64 const enthalpy = m_phaseEnthalpy[er][esr][ei][0][ip];
274  stack.energyFlux += phaseFlux * enthalpy;
275  stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dP];
276  stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy + phaseFlux * m_dPhaseEnthalpy[er][esr][ei][0][ip][Deriv::dT];
277 
278  real64 dProp_dC[numComp]{};
279  applyChainRule( numComp,
280  m_dCompFrac_dCompDens[er][esr][ei],
281  m_dPhaseEnthalpy[er][esr][ei][0][ip],
282  dProp_dC,
283  Deriv::dC );
284  for( integer jc = 0; jc < numComp; ++jc )
285  {
286  stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy + phaseFlux * dProp_dC[jc];
287  }
288 
289  }
290  else // the face is upstream
291  {
292 
293  // Step 3.1.b: compute the derivative of phase flux wrt temperature
294  real64 const dPhaseFlux_dT = facePhaseMob * dF_dT;
295 
296  // Step 3.2.b: compute the derivative of component flux wrt temperature
297 
298  for( integer ic = 0; ic < numComp; ++ic )
299  {
300  real64 const ycp = facePhaseCompFrac[ip][ic];
301  stack.dCompFlux_dT[ic] += dPhaseFlux_dT * ycp;
302  }
303 
304  // Step 3.3.b: compute the enthalpy flux
305 
306  real64 const enthalpy = facePhaseEnthalpy[ip];
307  stack.energyFlux += phaseFlux * enthalpy;
308  stack.dEnergyFlux_dP += dPhaseFlux_dP * enthalpy;
309  stack.dEnergyFlux_dT += dPhaseFlux_dT * enthalpy;
310  for( integer jc = 0; jc < numComp; ++jc )
311  {
312  stack.dEnergyFlux_dC[jc] += dPhaseFlux_dC[jc] * enthalpy;
313  }
314 
315  }
316 
317  } );
318 
319  // *****************************************************
320  // Computation of the conduction term in the energy flux
321  // Note that the phase enthalpy term in the energy was computed above
322  // Note that this term is computed using an explicit treatment of conductivity for now
323 
324  // Step 1: compute the thermal transmissibilities at this face
325  // Below, the thermal conductivity used to compute (explicitly) the thermal conducivity
326  // To avoid modifying the signature of the "computeWeights" function for now, we pass m_thermalConductivity twice
327  // TODO: modify computeWeights to accomodate explicit coefficients
328  real64 thermalTrans = 0.0;
329  real64 dThermalTrans_dPerm[3]{}; // not used
332  thermalTrans,
333  dThermalTrans_dPerm );
334 
335  // Step 2: compute temperature difference at the interface
336  stack.energyFlux += thermalTrans
337  * ( m_temp[m_seri( iconn, Order::ELEM )][m_sesri( iconn, Order::ELEM )][m_sei( iconn, Order::ELEM )] - m_faceTemp[m_sei( iconn, Order::FACE )] );
338  stack.dEnergyFlux_dT += thermalTrans;
339 
340 
341  // **********************************************************************************
342  // At this point, we have computed the energyFlux and the compFlux for all components
343  // We have to do two things here:
344  // 1) Add dCompFlux_dTemp to the localFluxJacobian of the component mass balance equations
345  // 2) Add energyFlux and its derivatives to the localFlux(Jacobian) of the energy balance equation
346 
347  // Step 1: add dCompFlux_dTemp to localFluxJacobian
348  for( integer ic = 0; ic < numComp; ++ic )
349  {
350  stack.localFluxJacobian[ic][numDof-1] = m_dt * stack.dCompFlux_dT[ic];
351  }
352 
353  // Step 2: add energyFlux and its derivatives to localFlux and localFluxJacobian
354  integer const localRowIndexEnergy = numEqn-1;
355  stack.localFlux[localRowIndexEnergy] = m_dt * stack.energyFlux;
356 
357  stack.localFluxJacobian[localRowIndexEnergy][0] = m_dt * stack.dEnergyFlux_dP;
358  stack.localFluxJacobian[localRowIndexEnergy][numDof-1] = m_dt * stack.dEnergyFlux_dT;
359  for( integer jc = 0; jc < numComp; ++jc )
360  {
361  stack.localFluxJacobian[localRowIndexEnergy][jc+1] = m_dt * stack.dEnergyFlux_dC[jc];
362  }
363  }
364 
371  void complete( localIndex const iconn,
372  StackVariables & stack ) const
373  {
374  // Call Case::complete to assemble the component mass balance equations (i = 0 to i = numDof-2)
375  // In the lambda, add contribution to residual and jacobian into the energy balance equation
376  Base::complete( iconn, stack, [&] ( localIndex const localRow )
377  {
378  // beware, there is volume balance eqn in m_localRhs and m_localMatrix!
379  RAJA::atomicAdd( parallelDeviceAtomic{}, &AbstractBase::m_localRhs[localRow + numEqn], stack.localFlux[numEqn-1] );
380  AbstractBase::m_localMatrix.addToRowBinarySearchUnsorted< parallelDeviceAtomic >
381  ( localRow + numEqn,
382  stack.dofColIndices,
383  stack.localFluxJacobian[numEqn-1],
384  numDof );
385 
386  } );
387  }
388 
389 protected:
390 
393 
397 
400  // for now, we treat thermal conductivity explicitly
401 
402 };
403 
408 {
409 public:
410 
428  template< typename POLICY, typename STENCILWRAPPER >
429  static void
430  createAndLaunch( integer const numComps,
431  integer const numPhases,
432  globalIndex const rankOffset,
433  integer const useTotalMassEquation,
434  string const & dofKey,
435  string const & solverName,
436  FaceManager const & faceManager,
437  ElementRegionManager const & elemManager,
438  STENCILWRAPPER const & stencilWrapper,
439  constitutive::MultiFluidBase & fluidBase,
440  real64 const dt,
441  CRSMatrixView< real64, globalIndex const > const & localMatrix,
442  arrayView1d< real64 > const & localRhs )
443  {
444  constitutive::constitutiveComponentUpdatePassThru< true >( fluidBase, numComps, [&]( auto & fluid, auto NC )
445  {
446  using FluidType = TYPEOFREF( fluid );
447  typename FluidType::KernelWrapper const fluidWrapper = fluid.createKernelWrapper();
448 
449  integer constexpr NUM_COMP = NC();
450  integer constexpr NUM_DOF = NC() + 2;
451 
453  elemManager.constructArrayViewAccessor< globalIndex, 1 >( dofKey );
454  dofNumberAccessor.setName( solverName + "/accessors/" + dofKey );
455 
456  // for now, we neglect capillary pressure in the kernel
457  BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags;
458  if( useTotalMassEquation )
459  kernelFlags.set( isothermalCompositionalMultiphaseFVMKernels::KernelFlags::TotalMassEquation );
460 
462  typename KernelType::CompFlowAccessors compFlowAccessors( elemManager, solverName );
463  typename KernelType::ThermalCompFlowAccessors thermalCompFlowAccessors( elemManager, solverName );
464  typename KernelType::MultiFluidAccessors multiFluidAccessors( elemManager, solverName );
465  typename KernelType::ThermalMultiFluidAccessors thermalMultiFluidAccessors( elemManager, solverName );
466  typename KernelType::CapPressureAccessors capPressureAccessors( elemManager, solverName );
467  typename KernelType::PermeabilityAccessors permeabilityAccessors( elemManager, solverName );
468  typename KernelType::ThermalConductivityAccessors thermalConductivityAccessors( elemManager, solverName );
469 
470  KernelType kernel( numPhases, rankOffset, faceManager, stencilWrapper, fluidWrapper,
471  dofNumberAccessor, compFlowAccessors, thermalCompFlowAccessors, multiFluidAccessors, thermalMultiFluidAccessors,
472  capPressureAccessors, permeabilityAccessors, thermalConductivityAccessors,
473  dt, localMatrix, localRhs, kernelFlags );
474  KernelType::template launch< POLICY >( stencilWrapper.size(), kernel );
475  } );
476  }
477 };
478 
479 } // namespace thermalCompositionalMultiphaseFVMKernels
480 
481 } // namespace geos
482 
483 
484 #endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_COMPOSITIONAL_THERMALDIRICHLETFLUXCOMPUTEKERNEL_HPP
#define GEOS_HOST_DEVICE
Marks a host-device function.
Definition: GeosxMacros.hpp:49
GEOS_HOST_DEVICE void computeWeights(localIndex const iconn, CoefficientAccessor< arrayView3d< real64 const > > const &coefficient, real64 &weight, real64(&dWeight_dCoef)[3]) const
Compute weights and derivatives w.r.t to the coefficient.
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...
The FaceManager class provides an interface to ObjectManagerBase in order to manage face data.
Definition: FaceManager.hpp:44
A struct to automatically construct and store element view accessors.
A struct to automatically construct and store element view accessors.
Define the interface for the assembly kernel in charge of Dirichlet face flux terms.
arrayView1d< real64 const > const m_faceGravCoef
View on the face gravity coefficient.
GEOS_HOST_DEVICE void complete(localIndex const iconn, StackVariables &stack, FUNC &&assemblyKernelOp=NoOpFunc{}) const
Performs the complete phase for the kernel.
GEOS_HOST_DEVICE void computeFlux(localIndex const iconn, StackVariables &stack, FUNC &&compFluxKernelOp=NoOpFunc{}) const
Compute the local Dirichlet face flux contributions to the residual and Jacobian.
Base class for FluxComputeKernel that holds all data not dependent on template parameters (like stenc...
ElementViewConst< arrayView1d< globalIndex const > > const m_dofNumber
Views on dof numbers.
ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const m_phaseCompFrac
Views on phase component fractions.
CRSMatrixView< real64, globalIndex const > const m_localMatrix
View on the local CRS matrix.
ElementViewConst< arrayView3d< real64 const, compflow::USD_COMP_DC > > const m_dCompFrac_dCompDens
Views on derivatives of comp fractions.
static constexpr integer numEqn
Compute time value for the number of equations (all of them, except the volume balance equation)
ElementViewConst< arrayView2d< real64 const, compflow::USD_PHASE > > const m_phaseMob
Views on phase mobilities.
static constexpr integer numDof
Compute time value for the number of degrees of freedom.
static void createAndLaunch(integer const numComps, integer const numPhases, globalIndex const rankOffset, integer const useTotalMassEquation, string const &dofKey, string const &solverName, FaceManager const &faceManager, ElementRegionManager const &elemManager, STENCILWRAPPER const &stencilWrapper, constitutive::MultiFluidBase &fluidBase, 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 Dirichlet face flux terms.
ElementViewConst< arrayView3d< real64 const > > const m_thermalConductivity
View on thermal conductivity.
ElementRegionManager::ElementViewConst< VIEWTYPE > ElementViewConst
The type for element-based data. Consists entirely of ArrayView's.
GEOS_HOST_DEVICE void complete(localIndex const iconn, StackVariables &stack) const
Performs the complete phase for the kernel.
ElementViewConst< arrayView4d< real64 const, constitutive::multifluid::USD_PHASE_COMP > > const m_phaseCompFrac
Views on phase component fractions.
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, compflow::USD_COMP_DC > > const m_dCompFrac_dCompDens
Views on derivatives of comp fractions.
DirichletFluxComputeKernel(integer const numPhases, globalIndex const rankOffset, FaceManager const &faceManager, BoundaryStencilWrapper const &stencilWrapper, FLUIDWRAPPER const &fluidWrapper, DofNumberAccessor const &dofNumberAccessor, CompFlowAccessors const &compFlowAccessors, ThermalCompFlowAccessors const &thermalCompFlowAccessors, MultiFluidAccessors const &multiFluidAccessors, ThermalMultiFluidAccessors const &thermalMultiFluidAccessors, CapPressureAccessors const &capPressureAccessors, PermeabilityAccessors const &permeabilityAccessors, ThermalConductivityAccessors const &thermalConductivityAccessors, real64 const dt, CRSMatrixView< real64, globalIndex const > const &localMatrix, arrayView1d< real64 > const &localRhs, BitFlags< isothermalCompositionalMultiphaseFVMKernels::KernelFlags > kernelFlags)
Constructor for the kernel interface.
ElementViewConst< arrayView1d< real64 const > > const m_temp
Views on temperature.
ElementViewConst< arrayView3d< real64 const, constitutive::multifluid::USD_PHASE > > const m_phaseEnthalpy
Views on phase enthalpies.
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
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
Defines the order of element/face in the stencil.
GEOS_HOST_DEVICE StackVariables(localIndex const size, localIndex numElems)
Constructor for the stack variables.