GEOS
FluxKernelsHelper.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_FLUXKERNELSHELPER_HPP
21 #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXKERNELSHELPER_HPP
22 
23 #include "common/DataTypes.hpp"
25 
26 namespace geos
27 {
28 
29 namespace singlePhaseFluxKernelsHelper
30 {
31 
38 template< typename VIEWTYPE >
40 
42 inline
43 void computeSinglePhaseFlux( localIndex const ( &seri )[2],
44  localIndex const ( &sesri )[2],
45  localIndex const ( &sei )[2],
46  real64 const ( &transmissibility )[2],
47  real64 const ( &dTrans_dPres )[2],
51  ElementViewConst< arrayView2d< real64 const > > const & dDens_dPres,
53  ElementViewConst< arrayView1d< real64 const > > const & dMob_dPres,
54  real64 & alpha,
55  real64 & mobility,
56  real64 & potGrad,
57  real64 & fluxVal,
58  real64 ( & dFlux_dP )[2],
59  real64 & dFlux_dTrans )
60 {
61  // average density
62  real64 densMean = 0.0;
63  real64 dDensMean_dP[2];
64 
65  for( localIndex ke = 0; ke < 2; ++ke )
66  {
67  densMean += 0.5 * dens[seri[ke]][sesri[ke]][sei[ke]][0];
68  dDensMean_dP[ke] = 0.5 * dDens_dPres[seri[ke]][sesri[ke]][sei[ke]][0];
69  }
70 
71  // compute potential difference
72  real64 dpotGrad_dTrans = 0.0;
73  real64 sumWeightGrav = 0.0;
74  real64 potScale = 0.0;
75  int signpotGradf[2] = {1, -1};
76 
77  for( localIndex ke = 0; ke < 2; ++ke )
78  {
79  localIndex const er = seri[ke];
80  localIndex const esr = sesri[ke];
81  localIndex const ei = sei[ke];
82 
83  real64 const pressure = pres[er][esr][ei];
84  real64 const gravD = gravCoef[er][esr][ei];
85  real64 const pot = transmissibility[ke] * ( pressure - densMean * gravD );
86 
87  potGrad += pot;
88  dpotGrad_dTrans += signpotGradf[ke] * ( pressure - densMean * gravD );
89  sumWeightGrav += transmissibility[ke] * gravD;
90 
91  potScale = fmax( potScale, fabs( pot ) );
92  }
93 
94  // compute upwinding tolerance
95  real64 constexpr upwRelTol = 1e-8;
96  real64 const upwAbsTol = fmax( potScale * upwRelTol, LvArray::NumericLimits< real64 >::epsilon );
97 
98  // decide mobility coefficients - smooth variation in [-upwAbsTol; upwAbsTol]
99  alpha = ( potGrad + upwAbsTol ) / ( 2 * upwAbsTol );
100 
101  real64 dMobility_dP[2]{};
102  if( alpha <= 0.0 || alpha >= 1.0 )
103  {
104  // happy path: single upwind direction
105  localIndex const ke = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) );
106  mobility = mob[seri[ke]][sesri[ke]][sei[ke]];
107  dMobility_dP[ke] = dMob_dPres[seri[ke]][sesri[ke]][sei[ke]];
108  }
109  else
110  {
111  // sad path: weighted averaging
112  real64 const mobWeights[2] = { alpha, 1.0 - alpha };
113  for( localIndex ke = 0; ke < 2; ++ke )
114  {
115  mobility += mobWeights[ke] * mob[seri[ke]][sesri[ke]][sei[ke]];
116  dMobility_dP[ke] = mobWeights[ke] * dMob_dPres[seri[ke]][sesri[ke]][sei[ke]];
117  }
118  }
119 
120  // compute the final flux and derivative w.r.t transmissibility
121  fluxVal = mobility * potGrad;
122 
123  dFlux_dTrans = mobility * dpotGrad_dTrans;
124 
125  for( localIndex ke = 0; ke < 2; ++ke )
126  {
127  dFlux_dP[ke] = mobility * ( transmissibility[ke] - dDensMean_dP[ke] * sumWeightGrav )
128  + dMobility_dP[ke] * potGrad + dFlux_dTrans * dTrans_dPres[ke];
129  }
130 
131 }
132 
133 
134 template< typename ENERGYFLUX_DERIVATIVE_TYPE >
136 void computeEnthalpyFlux( localIndex const ( &seri )[2],
137  localIndex const ( &sesri )[2],
138  localIndex const ( &sei )[2],
139  real64 const ( &transmissibility )[2],
140  ElementViewConst< arrayView2d< real64 const > > const & enthalpy,
141  ElementViewConst< arrayView2d< real64 const > > const & dEnthalpy_dPressure,
142  ElementViewConst< arrayView2d< real64 const > > const & dEnthalpy_dTemperature,
143  ElementViewConst< arrayView1d< real64 const > > const & gravCoef,
144  ElementViewConst< arrayView2d< real64 const > > const & dDens_dTemp,
145  ElementViewConst< arrayView1d< real64 const > > const & dMob_dTemp,
146  real64 const & alpha,
147  real64 const & mobility,
148  real64 const & potGrad,
149  real64 const & massFlux,
150  real64 const & dMassFlux_dTrans,
151  real64 const ( &dMassFlux_dP )[2],
152  real64 ( & dMassFlux_dT )[2],
153  real64 & energyFlux,
154  real64 & dEnergyFlux_dTrans,
155  ENERGYFLUX_DERIVATIVE_TYPE & dEnergyFlux_dP,
156  ENERGYFLUX_DERIVATIVE_TYPE & dEnergyFlux_dT )
157 {
158  // Step 1: compute the derivatives of the mean density at the interface wrt temperature
159 
160  real64 dDensMean_dT[2]{0.0, 0.0};
161 
162  for( integer ke = 0; ke < 2; ++ke )
163  {
164  real64 const dDens_dT = dDens_dTemp[seri[ke]][sesri[ke]][sei[ke]][0];
165  dDensMean_dT[ke] = 0.5 * dDens_dT;
166  }
167 
168  // Step 2: compute the derivatives of the potential difference wrt temperature
169  //***** calculation of flux *****
170 
171  real64 dGravHead_dT[2]{0.0, 0.0};
172 
173  // compute potential difference
174  for( integer ke = 0; ke < 2; ++ke )
175  {
176  localIndex const er = seri[ke];
177  localIndex const esr = sesri[ke];
178  localIndex const ei = sei[ke];
179 
180  // compute derivative of gravity potential difference wrt temperature
181  real64 const gravD = transmissibility[ke] * gravCoef[er][esr][ei];
182 
183  for( integer i = 0; i < 2; ++i )
184  {
185  dGravHead_dT[i] += dDensMean_dT[i] * gravD;
186  }
187  }
188 
189  // Step 3: compute the derivatives of the (upwinded) compFlux wrt temperature
190  // *** upwinding ***
191 
192  // Step 3.1: compute the derivative of the mass flux wrt temperature
193  for( integer ke = 0; ke < 2; ++ke )
194  {
195  dMassFlux_dT[ke] -= dGravHead_dT[ke];
196  }
197 
198  for( integer ke = 0; ke < 2; ++ke )
199  {
200  dMassFlux_dT[ke] *= mobility;
201  }
202 
203  real64 dMob_dT[2]{};
204 
205  if( alpha <= 0.0 || alpha >= 1.0 )
206  {
207  localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) );
208 
209  dMob_dT[k_up] = dMob_dTemp[seri[k_up]][sesri[k_up]][sei[k_up]];
210  }
211  else
212  {
213  real64 const mobWeights[2] = { alpha, 1.0 - alpha };
214  for( integer ke = 0; ke < 2; ++ke )
215  {
216  dMob_dT[ke] = mobWeights[ke] * dMob_dTemp[seri[ke]][sesri[ke]][sei[ke]];
217  }
218  }
219 
220  // add contribution from upstream cell mobility derivatives
221  for( integer ke = 0; ke < 2; ++ke )
222  {
223  dMassFlux_dT[ke] += dMob_dT[ke] * potGrad;
224  }
225 
226  // Step 4: compute the enthalpy flux
227  real64 enthalpyTimesMobWeight = 0.0;
228  real64 dEnthalpy_dP[2]{0.0, 0.0};
229  real64 dEnthalpy_dT[2]{0.0, 0.0};
230 
231  if( alpha <= 0.0 || alpha >= 1.0 )
232  {
233  localIndex const k_up = 1 - localIndex( fmax( fmin( alpha, 1.0 ), 0.0 ) );
234 
235  enthalpyTimesMobWeight = enthalpy[seri[k_up]][sesri[k_up]][sei[k_up]][0];
236  dEnthalpy_dP[k_up] = dEnthalpy_dPressure[seri[k_up]][sesri[k_up]][sei[k_up]][0];
237  dEnthalpy_dT[k_up] = dEnthalpy_dTemperature[seri[k_up]][sesri[k_up]][sei[k_up]][0];
238  }
239  else
240  {
241  real64 const mobWeights[2] = { alpha, 1.0 - alpha };
242  for( integer ke = 0; ke < 2; ++ke )
243  {
244  enthalpyTimesMobWeight += mobWeights[ke] * enthalpy[seri[ke]][sesri[ke]][sei[ke]][0];
245  dEnthalpy_dP[ke] = mobWeights[ke] * dEnthalpy_dPressure[seri[ke]][sesri[ke]][sei[ke]][0];
246  dEnthalpy_dT[ke] = mobWeights[ke] * dEnthalpy_dTemperature[seri[ke]][sesri[ke]][sei[ke]][0];
247  }
248  }
249 
250  energyFlux += massFlux * enthalpyTimesMobWeight;
251  dEnergyFlux_dTrans = enthalpyTimesMobWeight * dMassFlux_dTrans;
252 
253  for( integer ke = 0; ke < 2; ++ke )
254  {
255  dEnergyFlux_dP[ke] += dMassFlux_dP[ke] * enthalpyTimesMobWeight;
256  dEnergyFlux_dT[ke] += dMassFlux_dT[ke] * enthalpyTimesMobWeight;
257  }
258 
259  for( integer ke = 0; ke < 2; ++ke )
260  {
261  dEnergyFlux_dP[ke] += massFlux * dEnthalpy_dP[ke];
262  dEnergyFlux_dT[ke] += massFlux * dEnthalpy_dT[ke];
263  }
264 }
265 
266 
267 template< typename ENERGYFLUX_DERIVATIVE_TYPE >
269 void computeConductiveFlux( localIndex const ( &seri )[2],
270  localIndex const ( &sesri )[2],
271  localIndex const ( &sei )[2],
272  ElementViewConst< arrayView1d< real64 const > > const & temperature,
273  real64 const ( &thermalTrans )[2],
274  real64 & energyFlux,
275  ENERGYFLUX_DERIVATIVE_TYPE & dEnergyFlux_dT )
276 {
277  for( integer ke = 0; ke < 2; ++ke )
278  {
279  localIndex const er = seri[ke];
280  localIndex const esr = sesri[ke];
281  localIndex const ei = sei[ke];
282 
283  energyFlux += thermalTrans[ke] * temperature[er][esr][ei];
284  dEnergyFlux_dT[ke] += thermalTrans[ke];
285  }
286 }
287 
288 } // namespace singlePhaseFluxKernelsHelper
289 
290 } // namespace geos
291 
292 #endif //GEOS_PHYSICSSOLVERS_FLUIDFLOW_SINGLEPHASE_FLUXKERNELSHELPER_HPP
ElementRegionManager::ElementViewConst< VIEWTYPE > ElementViewConst
The type for element-based data. Consists entirely of ArrayView's.
#define GEOS_HOST_DEVICE
Marks a host-device function.
Definition: GeosxMacros.hpp:49
typename ElementViewAccessor< VIEWTYPE >::NestedViewTypeConst ElementViewConst
The ElementViewAccessor at the ElementRegionManager level is the type resulting from ElementViewAcces...
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Definition: DataTypes.hpp:180
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
ArrayView< T, 2, USD > arrayView2d
Alias for 2D array view.
Definition: DataTypes.hpp:196