GEOS
ThermalCompositionalMultiphaseWellKernels.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_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_HPP
21 #define GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_HPP
22 
25 #include "physicsSolvers/fluidFlow/wells/WellConstraintsBase.hpp"
26 #include "physicsSolvers/fluidFlow/wells/WellPhaseVolumeRateConstraint.hpp"
27 
28 namespace geos
29 {
30 
31 namespace thermalCompositionalMultiphaseWellKernels
32 {
33 
34 using namespace constitutive;
35 
36 /******************************** TotalMassDensityKernel ****************************/
37 
44 template< integer NUM_COMP, integer NUM_PHASE >
46 {
47 public:
49  using Base::m_dCompFrac_dCompDens;
50  using Base::m_dPhaseMassDens;
51  using Base::m_dPhaseVolFrac;
52  using Base::m_dTotalMassDens;
53  using Base::m_phaseMassDens;
54  using Base::m_phaseVolFrac;
55  using Base::m_totalMassDens;
56  using Base::numComp;
57  using Base::numPhase;
58 
65  MultiFluidBase const & fluid )
66  : Base( subRegion, fluid )
67  {}
68 
75  GEOS_HOST_DEVICE inline void compute( localIndex const ei ) const
76  {
77  using Deriv = multifluid::DerivativeOffset;
78 
79  arraySlice1d< real64 const, compflow::USD_PHASE - 1 > phaseVolFrac = m_phaseVolFrac[ei];
80  arraySlice2d< real64 const, compflow::USD_PHASE_DC - 1 > dPhaseVolFrac = m_dPhaseVolFrac[ei];
81  arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseMassDens = m_phaseMassDens[ei][0];
82  arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseMassDens = m_dPhaseMassDens[ei][0];
83 
84  real64 & dTotalMassDens_dT = m_dTotalMassDens[ei][Deriv::dT];
85 
86  // Call the base compute the compute the total mass density and derivatives
87  return Base::compute( ei, [&]( localIndex const ip )
88  {
89  dTotalMassDens_dT += dPhaseVolFrac[ip][Deriv::dT] * phaseMassDens[ip] + phaseVolFrac[ip] * dPhaseMassDens[ip][Deriv::dT];
90  } );
91  }
92 
93 protected:
94  // outputs
95  arrayView1d< real64 > m_dTotalMassDens_dTemp;
96 };
97 
102 {
103 public:
112  template< typename POLICY >
113  static void
114  createAndLaunch( integer const numComp,
115  integer const numPhase,
116  ObjectManagerBase & subRegion,
117  MultiFluidBase const & fluid )
118  {
119  if( numPhase == 2 )
120  {
121  isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&]( auto NC )
122  {
123  integer constexpr NUM_COMP = NC();
124  TotalMassDensityKernel< NUM_COMP, 2 > kernel( subRegion, fluid );
125  TotalMassDensityKernel< NUM_COMP, 2 >::template launch< POLICY >( subRegion.size(), kernel );
126  } );
127  }
128  else if( numPhase == 3 )
129  {
130  isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComp, [&]( auto NC )
131  {
132  integer constexpr NUM_COMP = NC();
133  TotalMassDensityKernel< NUM_COMP, 3 > kernel( subRegion, fluid );
134  TotalMassDensityKernel< NUM_COMP, 3 >::template launch< POLICY >( subRegion.size(), kernel );
135  } );
136  }
137  }
138 };
139 
140 /******************************** ResidualNormKernel ********************************/
141 
145 template< localIndex NUM_COMP >
147 {
148 public:
149 
151  static constexpr integer numComp = NUM_COMP;
152 
153 
155 
157  using Base::m_minNormalizer;
158  using Base::m_rankOffset;
159  using Base::m_localResidual;
160  using Base::m_dofNumber;
161 
162  ResidualNormKernel( globalIndex const rankOffset,
163  arrayView1d< real64 const > const & localResidual,
164  arrayView1d< globalIndex const > const & dofNumber,
165  arrayView1d< localIndex const > const & ghostRank,
166 
167  WellElementSubRegion const & subRegion,
168  MultiFluidBase const & fluid,
169  WellControls const & wellControls,
170  real64 const time,
171  real64 const dt,
172  real64 const minNormalizer )
173  : Base( rankOffset,
174  localResidual,
175  dofNumber,
176  ghostRank,
177  minNormalizer ),
178  m_numPhases( fluid.numFluidPhases()),
179  m_dt( dt ),
180  m_isLocallyOwned( subRegion.isLocallyOwned() ),
181  m_iwelemControl( subRegion.getTopWellElementIndex() ),
182  m_isProducer( wellControls.isProducer() ),
183  m_currentControl( wellControls.getControl() ),
184  m_targetBHP( std::numeric_limits< real64 >::max() ),
185  m_volume( subRegion.getElementVolume() ),
186  m_phaseDens_n( fluid.phaseDensity_n() ),
187  m_totalDens_n( fluid.totalDensity_n() ),
188  m_phaseVolFraction_n( subRegion.getField< fields::well::phaseVolumeFraction_n >()),
189  m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n() )
190  {
191  const WellConstraintBase * currentConstraint = wellControls.getCurrentConstraint();
192  ConstraintTypeId currentControl = wellControls.getControl();
193  if( currentControl == ConstraintTypeId::BHP )
194  {
195  m_targetBHP = currentConstraint->getConstraintValue( time );
196  }
197  else
198  {
199  m_constraintValue = currentConstraint->getConstraintValue( time );
200  if( currentControl == ConstraintTypeId::PHASEVOLRATE )
201  {
202  m_targetPhaseIndex = wellControls.getConstraintPhaseIndex();
203  }
204  }
205  }
206 
208  void computeMassEnergyNormalizers( localIndex const iwelem,
209  real64 & massNormalizer,
210  real64 & energyNormalizer ) const
211  {
212  massNormalizer = LvArray::math::max( m_minNormalizer, m_totalDens_n[iwelem][0] * m_volume[iwelem] );
213 
214  for( integer ip = 0; ip < m_numPhases; ++ip )
215  {
216  energyNormalizer += m_phaseInternalEnergy_n[iwelem][0][ip] * m_phaseDens_n[iwelem][0][ip] * m_phaseVolFraction_n[iwelem][ip] * m_volume[iwelem];
217  }
218  // warning: internal energy can be negative
219  energyNormalizer = LvArray::math::max( m_minNormalizer, LvArray::math::abs( energyNormalizer ) );
220  }
221 
223  virtual void computeLinf( localIndex const iwelem,
224  LinfStackVariables & stack ) const override
225  {
226  real64 normalizer = 0.0;
227  for( integer idof = 0; idof < WJ_ROFFSET::nEqn; ++idof )
228  {
229 
230  // Step 1: compute a normalizer for the control or pressure equation
231 
232  // for the control equation, we distinguish two cases
233  if( idof == WJ_ROFFSET::CONTROL )
234  {
235 
236  // for the top well element, normalize using the current control
237  if( m_isLocallyOwned && iwelem == m_iwelemControl )
238  {
239  if( m_currentControl == ConstraintTypeId::BHP )
240  {
241  // the residual entry is in pressure units
242  normalizer = m_targetBHP;
243  }
244  else if( m_currentControl == ConstraintTypeId::TOTALVOLRATE )
245  {
246  // the residual entry is in volume / time units
247  normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
248  }
249  else if( m_currentControl == ConstraintTypeId::PHASEVOLRATE )
250  {
251  // the residual entry is in volume / time units
252  normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
253  }
254  else if( m_currentControl == ConstraintTypeId::MASSRATE )
255  {
256  // the residual entry is in volume / time units
257  normalizer = LvArray::math::max( LvArray::math::abs( m_constraintValue ), m_minNormalizer );
258  }
259  }
260  // for the pressure difference equation, always normalize by the BHP
261  else
262  {
263  normalizer = m_targetBHP;
264  }
265  }
266  // Step 2: compute a normalizer for the mass balance equations
267  else if( idof >= WJ_ROFFSET::MASSBAL && idof < WJ_ROFFSET::MASSBAL + numComp )
268  {
269  if( m_isProducer ) // only PHASEVOLRATE is supported for now
270  {
271  // the residual is in mass units
272  normalizer = m_dt * LvArray::math::abs( m_constraintValue ) * m_phaseDens_n[iwelem][0][m_targetPhaseIndex];
273  }
274  else // Type::INJECTOR, only TOTALVOLRATE is supported for now
275  {
276  if( m_currentControl == ConstraintTypeId::MASSRATE )
277  {
278  normalizer = m_dt * LvArray::math::abs( m_constraintValue );
279  }
280  else
281  {
282  // the residual is in mass units
283  normalizer = m_dt * LvArray::math::abs( m_constraintValue ) * m_totalDens_n[iwelem][0];
284  }
285 
286  }
287 
288  // to make sure that everything still works well if the rate is zero, we add this check
289  normalizer = LvArray::math::max( normalizer, m_volume[iwelem] * m_totalDens_n[iwelem][0] );
290  }
291  // Step 3: compute a normalizer for the volume balance equations
292  else if( idof == WJ_ROFFSET::VOLBAL )
293  {
294  if( m_isProducer ) // only PHASEVOLRATE is supported for now
295  {
296  // the residual is in volume units
297  normalizer = m_dt * LvArray::math::abs( m_constraintValue );
298  }
299  else // Type::INJECTOR, only TOTALVOLRATE is supported for now
300  {
301  if( m_currentControl == ConstraintTypeId::MASSRATE )
302  {
303  normalizer = m_dt * LvArray::math::abs( m_constraintValue/ m_totalDens_n[iwelem][0] );
304  }
305  else
306  {
307  normalizer = m_dt * LvArray::math::abs( m_constraintValue );
308  }
309 
310  }
311  // to make sure that everything still works well if the rate is zero, we add this check
312  normalizer = LvArray::math::max( normalizer, m_volume[iwelem] );
313  }
314  // step 3: energy residual
315  if( idof == WJ_ROFFSET::ENERGYBAL )
316  {
317  real64 massNormalizer = 0.0, energyNormalizer = 0.0;
318  computeMassEnergyNormalizers( iwelem, massNormalizer, energyNormalizer );
319  real64 const valEnergy = LvArray::math::abs( m_localResidual[stack.localRow + WJ_ROFFSET::ENERGYBAL] ) / energyNormalizer;
320  if( valEnergy > stack.localValue[1] )
321  {
322  stack.localValue[1] = valEnergy;
323  }
324 
325  }
326  else
327  {
328  normalizer = LvArray::math::max( m_minNormalizer, normalizer );
329  // Step 4: compute the contribution to the residual
330  real64 const val = LvArray::math::abs( m_localResidual[stack.localRow + idof] ) / normalizer;
331  if( val > stack.localValue[0] )
332  {
333  stack.localValue[0] = val;
334  }
335  }
336  }
337  }
338 
340  virtual void computeL2( localIndex const iwelem,
341  L2StackVariables & stack ) const override
342  {
343  GEOS_UNUSED_VAR( iwelem, stack );
344  GEOS_ERROR( "The L2 norm is not implemented for CompositionalMultiphaseWell" );
345  }
346 
347 
348 protected:
349 
352 
355 
357  real64 const m_dt;
358 
360  bool const m_isLocallyOwned;
361 
364 
366  bool const m_isProducer;
367 
370  real64 m_constraintValue;
371  real64 m_targetBHP;
372 
373 
376 
380  arrayView2d< real64 const, compflow::USD_PHASE > const m_phaseVolFraction_n;
381  arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseInternalEnergy_n;
382 
383 };
384 
385 /*
386  *@class ResidualNormKernelFactory
387  */
389 {
390 public:
391 
407  template< typename POLICY >
408  static void
409  createAndLaunch( integer const numComp,
410  globalIndex const rankOffset,
411  string const & dofKey,
412  arrayView1d< real64 const > const & localResidual,
413  WellElementSubRegion const & subRegion,
414  MultiFluidBase const & fluid,
415  WellControls const & wellControls,
416  real64 const time,
417  real64 const dt,
418  real64 const minNormalizer,
419  real64 (& residualNorm)[2] )
420  {
421  isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch ( numComp, [&]( auto NC )
422  {
423 
424  integer constexpr NUM_COMP = NC();
425  using kernelType = ResidualNormKernel< NUM_COMP >;
426  arrayView1d< globalIndex const > const dofNumber = subRegion.getReference< array1d< globalIndex > >( dofKey );
427  arrayView1d< integer const > const ghostRank = subRegion.ghostRank();
428 
429  kernelType kernel( rankOffset, localResidual, dofNumber, ghostRank,
430  subRegion, fluid, wellControls, time, dt, minNormalizer );
431  kernelType::template launchLinf< POLICY >( subRegion.size(), kernel, residualNorm );
432  } );
433  }
434 
435 };
436 
437 /******************************** ElementBasedAssemblyKernel ********************************/
438 
445 template< localIndex NUM_COMP >
447 {
448 public:
450  using Base::m_dCompFrac_dCompDens;
451  using Base::m_dofNumber;
452  using Base::m_dPhaseCompFrac;
453  using Base::m_dPhaseDens;
454  using Base::m_dPhaseVolFrac;
455  using Base::m_dPoro_dPres;
456  using Base::m_elemGhostRank;
457  using Base::m_localMatrix;
458  using Base::m_localRhs;
459  using Base::m_numPhases;
460  using Base::m_phaseCompFrac;
461  using Base::m_phaseCompFrac_n;
462  using Base::m_phaseDens;
463  using Base::m_phaseDens_n;
464  using Base::m_phaseVolFrac;
465  using Base::m_phaseVolFrac_n;
466  using Base::m_porosity;
467  using Base::m_porosity_n;
468  using Base::m_rankOffset;
469  using Base::m_volume;
470  using Base::numComp;
471  using Base::numDof;
472  using Base::numEqn;
473 
474  using FLUID_PROP_COFFSET = multifluid::DerivativeOffsetC< NUM_COMP, 1 >;
475 
476 
488  bool const thermalEffectsEnabled,
489  integer const isProducer,
490  globalIndex const rankOffset,
491  string const dofKey,
492  WellElementSubRegion const & subRegion,
493  MultiFluidBase const & fluid,
494  CRSMatrixView< real64, globalIndex const > const & localMatrix,
495  arrayView1d< real64 > const & localRhs,
496  BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const kernelFlags )
497  : Base( numPhases, thermalEffectsEnabled, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags ),
498  m_phaseInternalEnergy_n( fluid.phaseInternalEnergy_n()),
499  m_phaseInternalEnergy( fluid.phaseInternalEnergy()),
500  m_dPhaseInternalEnergy( fluid.dPhaseInternalEnergy())
501  {}
502 
503  struct StackVariables : public Base::StackVariables
504  {
505 public:
508  : Base::StackVariables()
509  {}
510  using Base::StackVariables::eqnRowIndices;
511  using Base::StackVariables::dofColIndices;
512  using Base::StackVariables::localJacobian;
513  using Base::StackVariables::localResidual;
514  using Base::StackVariables::localRow;
515  using Base::StackVariables::volume;
516 
517 
518 
519  };
526  void setup( localIndex const ei,
527  StackVariables & stack ) const
528  {
529  Base::setup( ei, stack );
530 
531 
532 
533  }
534 
543  StackVariables & stack ) const
544  {
545  using Deriv = multifluid::DerivativeOffset;
546 
547  Base::computeAccumulation( ei, stack, [&]( integer const ip
548  , real64 const & phaseAmount
549  , real64 const & phaseAmount_n
550  , real64 const (&dPhaseAmount)[FLUID_PROP_COFFSET::nDer] )
551  {
552  // We are in the loop over phases, ip provides the current phase index.
553  // We have to do two things:
554  // 1- Assemble the derivatives of the component mass balance equations with respect to temperature
555  // 2- Assemble the phase-dependent part of the accumulation term of the energy equation
556 
557  real64 dPhaseInternalEnergy_dC[numComp]{};
558 
559  // construct the slices
560  arraySlice2d< real64 const, compflow::USD_COMP_DC - 1 > dCompFrac_dCompDens = m_dCompFrac_dCompDens[ei];
561  arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy_n = m_phaseInternalEnergy_n[ei][0];
562  arraySlice1d< real64 const, multifluid::USD_PHASE - 2 > phaseInternalEnergy = m_phaseInternalEnergy[ei][0];
563  arraySlice2d< real64 const, multifluid::USD_PHASE_DC - 2 > dPhaseInternalEnergy = m_dPhaseInternalEnergy[ei][0];
564 
565  // Step 1: assemble the phase-dependent part of the accumulation term of the energy equation
566 
567  real64 const phaseEnergy = phaseAmount * phaseInternalEnergy[ip];
568  real64 const phaseEnergy_n = phaseAmount_n * phaseInternalEnergy_n[ip];
569  real64 const dPhaseEnergy_dP = dPhaseAmount[FLUID_PROP_COFFSET::dP] * phaseInternalEnergy[ip]
570  + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dP];
571  real64 const dPhaseEnergy_dT = dPhaseAmount[FLUID_PROP_COFFSET::dT] * phaseInternalEnergy[ip]
572  + phaseAmount * dPhaseInternalEnergy[ip][Deriv::dT];
573  // local accumulation
574  stack.localResidual[numEqn-1] += phaseEnergy - phaseEnergy_n;
575 
576  // derivatives w.r.t. pressure and temperature
577  stack.localJacobian[numEqn-1][0] += dPhaseEnergy_dP;
578  stack.localJacobian[numEqn-1][numDof-1] += dPhaseEnergy_dT;
579 
580  // derivatives w.r.t. component densities
581  applyChainRule( numComp, dCompFrac_dCompDens, dPhaseInternalEnergy[ip], dPhaseInternalEnergy_dC, Deriv::dC );
582  for( integer jc = 0; jc < numComp; ++jc )
583  {
584  stack.localJacobian[numEqn-1][jc + 1] += phaseInternalEnergy[ip] * dPhaseAmount[FLUID_PROP_COFFSET::dC+jc]
585  + dPhaseInternalEnergy_dC[jc] * phaseAmount;
586  }
587  } );
588 
589 
590  }
591 
600  StackVariables & stack ) const
601  {
602  Base::computeVolumeBalance( ei, stack );
603 
604  }
605 
607  void complete( localIndex const ei,
608  StackVariables & stack ) const
609  {
610  // Assemble the component mass balance equations and volume balance equations
611  // Energy balance equation updates to solver matrices included in Base class
612  Base::complete( ei, stack );
613 
614  }
615 
616 protected:
619 
624 
625 };
626 
631 {
632 public:
645  template< typename POLICY >
646  static void
647  createAndLaunch( localIndex const numComps,
648  localIndex const numPhases,
649  integer const thermalEffectsEnabled,
650  integer const isProducer,
651  globalIndex const rankOffset,
652  BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags,
653  string const dofKey,
654  WellElementSubRegion const & subRegion,
655  MultiFluidBase const & fluid,
656  CRSMatrixView< real64, globalIndex const > const & localMatrix,
657  arrayView1d< real64 > const & localRhs )
658  {
659  isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC )
660  {
661  localIndex constexpr NUM_COMP = NC();
662 
664  kernel( numPhases, thermalEffectsEnabled, isProducer, rankOffset, dofKey, subRegion, fluid, localMatrix, localRhs, kernelFlags );
666  launch< POLICY, ElementBasedAssemblyKernel< NUM_COMP > >( subRegion.size(), kernel );
667  } );
668  }
669 };
670 
671 /******************************** FaceBasedAssemblyKernel ********************************/
672 
678 template< integer NC >
680 {
681 public:
682  static constexpr integer IS_THERMAL = 1;
684 
685  // Well jacobian column and row indicies
688 
689  using CP_Deriv = multifluid::DerivativeOffsetC< NC, IS_THERMAL >;
690 
692 
693 
694  using Base::m_isProducer;
695  using Base::m_dt;
696  using Base::m_localRhs;
697  using Base::m_localMatrix;
698  using Base::m_rankOffset;
699  using Base::maxNumElems;
700  using Base::maxStencilSize;
701  using Base::m_useTotalMassEquation;
702 
704  static constexpr integer numComp = NC;
705 
707  static constexpr integer numDof = WJ_COFFSET::nDer;
708 
710  static constexpr integer numEqn = WJ_ROFFSET::nEqn - 2;
711 
727  globalIndex const rankOffset,
728  string const wellDofKey,
729  WellControls const & wellControls,
730  WellElementSubRegion const & subRegion,
731  MultiFluidBase const & fluid,
732  CRSMatrixView< real64, globalIndex const > const & localMatrix,
733  arrayView1d< real64 > const & localRhs,
734  BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags )
735  : Base( dt
736  , rankOffset
737  , wellDofKey
738  , wellControls
739  , subRegion
740  , localMatrix
741  , localRhs
742  , kernelFlags ),
743  m_numPhases ( fluid.numFluidPhases()),
744  m_thermalEffectsEnabled( wellControls.thermalEffectsEnabled() ),
745  m_globalWellElementIndex( subRegion.getGlobalWellElementIndex() ),
746  m_phaseFraction( fluid.phaseFraction()),
747  m_dPhaseFraction( fluid.dPhaseFraction()),
748  m_phaseEnthalpy( fluid.phaseEnthalpy()),
749  m_dPhaseEnthalpy( fluid.dPhaseEnthalpy())
750  { }
751 
753  {
754 public:
755 
757  StackVariables( localIndex const size )
758  : Base::StackVariables( size )
759  {}
760 
767  };
768 
770  inline
771  void setup( localIndex const iwelem, StackVariables & stack ) const
772  {
773  Base::setup ( iwelem, stack );
774  stack.localEnergyFlux.resize( stack.numConnectedElems );
775  stack.localEnergyFluxJacobian.resize( stack.numConnectedElems, stack.stencilSize * numDof );
776  stack.localEnergyFluxJacobian_dQ.resize( stack.numConnectedElems, 1 );
777  for( integer i=0; i<stack.numConnectedElems; i++ )
778  {
779  stack.localEnergyFlux[i]=0.0;
780  stack.localEnergyFluxJacobian_dQ[i][0]=0.0;
781  for( integer j=0; j< stack.stencilSize * numDof; j++ )
782  stack.localEnergyFluxJacobian[i][j] = 0.0;
783  }
784  }
785 
787  inline
788  void complete( localIndex const iwelem, StackVariables & stack ) const
789  {
790  Base::complete ( iwelem, stack );
791  // tjb iso return;
792  if( !m_thermalEffectsEnabled ) return;
793  using namespace compositionalMultiphaseUtilities;
794  if( stack.numConnectedElems ==1 )
795  {
796  // Setup Jacobian global row indicies for energy equation
797  globalIndex oneSidedEqnRowIndices = stack.offsetUp + WJ_ROFFSET::ENERGYBAL - m_rankOffset;
798 
799  if( oneSidedEqnRowIndices >= 0 && oneSidedEqnRowIndices < m_localMatrix.numRows() )
800  {
801 
802  if( !m_isProducer && m_globalWellElementIndex[iwelem] == 0 )
803  {
804  // For top segment energy balance eqn replaced with T(n+1) - T = 0
805  // No other energy balance derivatives
806  // Assumption is global index == 0 is top segment with fixed temp BC
807  for( integer i=0; i< CP_Deriv::nDer; i++ )
808  {
809  stack.localEnergyFluxJacobian[0][i] = 0.0;
810  }
811  stack.localEnergyFluxJacobian_dQ[0][0]=0;
812  stack.localEnergyFlux[0]=0;
813  }
814 
815 
816  // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order)
817  globalIndex oneSidedDofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ;
818  globalIndex oneSidedDofColIndices_dPresCompTempUp[CP_Deriv::nDer]{};
819 
820  int ioff=0;
821  oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dP;
822  oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dT;
823  for( integer jdof = 0; jdof < NC; ++jdof )
824  {
825  oneSidedDofColIndices_dPresCompTempUp[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof;
826  }
827 
828  m_localMatrix.template addToRow< parallelDeviceAtomic >( oneSidedEqnRowIndices,
829  &oneSidedDofColIndices_dRate,
830  stack.localEnergyFluxJacobian_dQ[0],
831  1 );
832  m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( oneSidedEqnRowIndices,
833  oneSidedDofColIndices_dPresCompTempUp,
834  stack.localEnergyFluxJacobian[0],
835  CP_Deriv::nDer );
836  RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[oneSidedEqnRowIndices], stack.localEnergyFlux[0] );
837  }
838  }
839  else // if ( stack.numConnectedElems == 2 )
840  {
841  globalIndex row_current = stack.offsetCurrent + WJ_ROFFSET::ENERGYBAL - m_rankOffset;
842  globalIndex row_next = stack.offsetNext + WJ_ROFFSET::ENERGYBAL - m_rankOffset;
843 
844  if( !m_isProducer )
845  {
846  if( row_next >= 0 && row_next < m_localMatrix.numRows() )
847  {
848  if( m_globalWellElementIndex[stack.iwelemNext] == 0 )
849  {
850  for( integer i=0; i<CP_Deriv::nDer; i++ )
851  stack.localEnergyFluxJacobian[TAG::NEXT][i] = 0.0;
852  stack.localEnergyFluxJacobian_dQ[TAG::NEXT][0] =0;
853  stack.localEnergyFlux[TAG::NEXT] =0;
854  }
855 
856  }
857  }
858  // Setup Jacobian global row indicies
859  // equations for COMPONENT + ENERGY balances
860  globalIndex eqnRowIndices[2]{};
861 
862  // energy balance equations
863  eqnRowIndices[TAG::CURRENT ] = row_current;
864  eqnRowIndices[TAG::NEXT ] = row_next;
865 
866 
867  // Setup Jacobian global col indicies ( Mapping from local jac order to well jac order)
868  globalIndex dofColIndices[CP_Deriv::nDer]{};
869  globalIndex dofColIndices_dRate = stack.offsetCurrent + WJ_COFFSET::dQ;
870 
871  int ioff=0;
872  // Indice storage order reflects local jac col storage order CP::Deriv order P T DENS
873  // well jacobian order is P DENS Q T
874  dofColIndices[ioff++] = stack.offsetUp + WJ_COFFSET::dP;
875 
876  if constexpr ( IS_THERMAL )
877  {
878  dofColIndices[ioff++] = stack.offsetUp + WJ_COFFSET::dT;
879  }
880  for( integer jdof = 0; jdof < NC; ++jdof )
881  {
882  dofColIndices[ioff++] = stack.offsetUp + WJ_COFFSET::dC+ jdof;
883  }
884  // Note this updates diag and offdiag
885  for( integer i = 0; i < 2; ++i )
886  {
887  if( eqnRowIndices[i] >= 0 && eqnRowIndices[i] < m_localMatrix.numRows() )
888  {
889  m_localMatrix.template addToRow< parallelDeviceAtomic >( eqnRowIndices[i],
890  &dofColIndices_dRate,
891  stack.localEnergyFluxJacobian_dQ[i],
892  1 );
893  m_localMatrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( eqnRowIndices[i],
894  dofColIndices,
895  stack.localEnergyFluxJacobian[i],
896  CP_Deriv::nDer );
897  RAJA::atomicAdd( parallelDeviceAtomic{}, &m_localRhs[eqnRowIndices[i]], stack.localEnergyFlux[i] );
898  }
899  }
900  }
901 
902  }
903 
913  inline
914  void computeFlux( localIndex const iwelem, StackVariables & stack ) const
915  {
916  Base::computeFlux ( iwelem, stack, [&] ( localIndex const & iwelemNext
917  , localIndex const & iwelemUp
918  , real64 const & currentConnRate
919  , real64 const (&dCompFrac_dCompDens)[NC][NC] )
920  {
921 
922  if( iwelemNext < 0 && !m_isProducer ) // exit connection, injector
923  {
924  real64 eflux=0;
925  real64 eflux_dq=0;
926  for( integer ip = 0; ip < m_numPhases; ++ip )
927  {
928  eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip];
929  eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip];
930 
931  stack.localEnergyFluxJacobian[0] [CP_Deriv::dP] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dP]
932  + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dP]*m_phaseFraction[iwelemUp][0][ip];
933  stack.localEnergyFluxJacobian[0] [CP_Deriv::dT] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dT]
934  + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dT]*m_phaseFraction[iwelemUp][0][ip];
935 
936  real64 dProp1_dC[numComp]{};
937  applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseEnthalpy[iwelemUp][0][ip], dProp1_dC, CP_Deriv::dC );
938  real64 dProp2_dC[numComp]{};
939  applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseFraction[iwelemUp][0][ip], dProp2_dC, CP_Deriv::dC );
940  for( integer dof=0; dof < numComp; dof++ )
941  {
942  stack.localEnergyFluxJacobian[0] [CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dProp2_dC[dof]
943  + dProp1_dC[dof]*m_phaseFraction[iwelemUp][0][ip];
944  }
945  }
946  for( integer dof=0; dof < CP_Deriv::nDer; dof++ )
947  {
948  stack.localEnergyFluxJacobian[0] [dof] *= -m_dt*currentConnRate;
949  }
950  // Energy equation
951  stack.localEnergyFlux[0] = -m_dt * eflux * currentConnRate;
952  stack.localEnergyFluxJacobian_dQ[0][0] = -m_dt * eflux_dq;
953  }
954  else if( ( iwelemNext < 0 && m_isProducer ) ) // exit connection, producer
955  {
956  real64 eflux=0;
957  real64 eflux_dq=0;
958  for( integer ip = 0; ip < m_numPhases; ++ip )
959  {
960  eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip];
961  eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip];
962  stack.localEnergyFluxJacobian[0] [CP_Deriv::dP] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dP]
963  + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dP]*m_phaseFraction[iwelemUp][0][ip];
964  stack.localEnergyFluxJacobian[0] [CP_Deriv::dT] += m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dT]
965  + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dT]*m_phaseFraction[iwelemUp][0][ip];
966 
967  real64 dProp1_dC[numComp]{};
968  applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseEnthalpy[iwelemUp][0][ip], dProp1_dC, CP_Deriv::dC );
969  real64 dProp2_dC[numComp]{};
970  applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseFraction[iwelemUp][0][ip], dProp2_dC, CP_Deriv::dC );
971  for( integer dof=0; dof < numComp; dof++ )
972  {
973  stack.localEnergyFluxJacobian[0] [CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dProp2_dC[dof]
974  + dProp1_dC[dof]*m_phaseFraction[iwelemUp][0][ip];
975  }
976 
977  }
978 
979  for( integer dof=0; dof < CP_Deriv::nDer; dof++ )
980  {
981  stack.localEnergyFluxJacobian[0][dof] *= -m_dt*currentConnRate;
982  }
983  stack.localEnergyFlux[0] = -m_dt * eflux * currentConnRate;
984  stack.localEnergyFluxJacobian_dQ[0][0] = -m_dt*eflux_dq;
985  }
986  else
987  {
988  real64 eflux=0;
989  real64 eflux_dq=0;
990  for( integer ip = 0; ip < m_numPhases; ++ip )
991  {
992  eflux += m_phaseEnthalpy[iwelemUp][0][ip]* m_phaseFraction[iwelemUp][0][ip];
993  eflux_dq += m_phaseEnthalpy[iwelemUp][0][ip] * m_phaseFraction[iwelemUp][0][ip];
994 
995  real64 dprop_dp = m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dP]
996  + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dP]*m_phaseFraction[iwelemUp][0][ip];
997  real64 dprop_dt = m_phaseEnthalpy[iwelemUp][0][ip]*m_dPhaseFraction[iwelemUp][0][ip][CP_Deriv::dT]
998  + m_dPhaseEnthalpy[iwelemUp][0][ip][CP_Deriv::dT]*m_phaseFraction[iwelemUp][0][ip];
999 
1000  stack.localEnergyFluxJacobian[TAG::NEXT ] [CP_Deriv::dP] += dprop_dp;
1001  stack.localEnergyFluxJacobian[TAG::NEXT] [CP_Deriv::dT] += dprop_dt;
1002 
1003  stack.localEnergyFluxJacobian[TAG::CURRENT ] [CP_Deriv::dP] += dprop_dp;
1004  stack.localEnergyFluxJacobian[TAG::CURRENT] [CP_Deriv::dT] += dprop_dt;
1005 
1006  real64 dPE_dC[numComp]{};
1007  applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseEnthalpy[iwelemUp][0][ip], dPE_dC, CP_Deriv::dC );
1008  real64 dPF_dC[numComp]{};
1009  applyChainRule( numComp, dCompFrac_dCompDens, m_dPhaseFraction[iwelemUp][0][ip], dPF_dC, CP_Deriv::dC );
1010 
1011  for( integer dof=0; dof < numComp; dof++ )
1012  {
1013  stack.localEnergyFluxJacobian[TAG::NEXT ][CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof]
1014  +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip];
1015  stack.localEnergyFluxJacobian[TAG::CURRENT ][CP_Deriv::dC+dof] += m_phaseEnthalpy[iwelemUp][0][ip]*dPF_dC[dof]
1016  +dPE_dC[dof]*m_phaseFraction[iwelemUp][0][ip];
1017  }
1018  }
1019  stack.localEnergyFlux[TAG::NEXT ] = m_dt * eflux * currentConnRate;
1020  stack.localEnergyFlux[TAG::CURRENT ] = -m_dt * eflux * currentConnRate;
1021  stack.localEnergyFluxJacobian_dQ [TAG::NEXT ][0] = m_dt * eflux_dq;
1022  stack.localEnergyFluxJacobian_dQ [TAG::CURRENT][0] = -m_dt * eflux_dq;
1023  for( integer dof=0; dof < CP_Deriv::nDer; dof++ )
1024  {
1025  stack.localEnergyFluxJacobian[TAG::NEXT ][dof] *= m_dt*currentConnRate;
1026  stack.localEnergyFluxJacobian[TAG::CURRENT ][dof] *= -m_dt*currentConnRate;
1027  }
1028  }
1029 
1030  } );
1031 
1032  }
1033 
1034 
1043  template< typename POLICY, typename KERNEL_TYPE >
1044  static void
1045  launch( localIndex const numElements,
1046  KERNEL_TYPE const & kernelComponent )
1047  {
1049  forAll< POLICY >( numElements, [=] GEOS_HOST_DEVICE ( localIndex const ie )
1050  {
1051  typename KERNEL_TYPE::StackVariables stack( 1 );
1052 
1053  kernelComponent.setup( ie, stack );
1054  kernelComponent.computeFlux( ie, stack );
1055  kernelComponent.complete( ie, stack );
1056  } );
1057  }
1058 
1059 protected:
1064 
1067 
1071 
1075 
1076 
1077 };
1078 
1083 {
1084 public:
1085 
1099  template< typename POLICY >
1100  static void
1101  createAndLaunch( integer const numComps,
1102  real64 const dt,
1103  globalIndex const rankOffset,
1104  BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags,
1105  string const dofKey,
1106  WellControls const & wellControls,
1107  WellElementSubRegion const & subRegion,
1108  MultiFluidBase const & fluid,
1109  CRSMatrixView< real64, globalIndex const > const & localMatrix,
1110  arrayView1d< real64 > const & localRhs )
1111  {
1112  isothermalCompositionalMultiphaseBaseKernels::internal::kernelLaunchSelectorCompSwitch( numComps, [&]( auto NC )
1113  {
1114  integer constexpr NUM_COMP = NC();
1115 
1116  using kernelType = FaceBasedAssemblyKernel< NUM_COMP >;
1117  kernelType kernel( dt, rankOffset, dofKey, wellControls, subRegion, fluid, localMatrix, localRhs, kernelFlags );
1118  kernelType::template launch< POLICY >( subRegion.size(), kernel );
1119  } );
1120  }
1121 };
1122 
1123 } // end namespace thermalCompositionalMultiphaseWellKernels
1124 
1125 } // end namespace geos
1126 
1127 #endif // GEOS_PHYSICSSOLVERS_FLUIDFLOW_WELLS_THERMALCOMPOSITIONALMULTIPHASEWELLKERNELS_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.
#define GEOS_ERROR(...)
Raise a hard error and terminate the program.
Definition: Logger.hpp:225
#define GEOS_MARK_FUNCTION
Mark function with both Caliper and NVTX if enabled.
The ObjectManagerBase is the base object of all object managers in the mesh data hierachy.
array1d< integer > const & ghostRank()
Get the ghost information of each object.
real64 getConstraintValue(real64 const &currentTime) const
Get the target bottom hole pressure value.
This class describes the controls used to operate a well.
This class describes a collection of local well elements and perforations.
Define the interface for the assembly kernel in charge of accumulation and volume balance.
Define the interface for the assembly kernel in charge of flux terms.
Define the interface for the property kernel in charge of computing the total mass density.
GEOS_DECLTYPE_AUTO_RETURN getReference(LOOKUP_TYPE const &lookup) const
Look up a wrapper and get reference to wrapped object.
Definition: Group.hpp:1273
localIndex size() const
Get the "size" of the group, which determines the number of elements in resizable wrappers.
Definition: Group.hpp:1315
Define the base interface for the property update kernels.
Define the base interface for the residual calculations.
static void createAndLaunch(localIndex const numComps, localIndex const numPhases, integer const thermalEffectsEnabled, integer const isProducer, globalIndex const rankOffset, BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags, string const dofKey, WellElementSubRegion const &subRegion, MultiFluidBase const &fluid, 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 thermal accumulation and volume balance.
arrayView2d< real64 const > const m_dPoro_dTemp
View on derivative of porosity w.r.t temperature.
GEOS_HOST_DEVICE void computeVolumeBalance(localIndex const ei, StackVariables &stack) const
Compute the local volume balance contributions to the residual and Jacobian.
ElementBasedAssemblyKernel(localIndex const numPhases, bool const thermalEffectsEnabled, integer const isProducer, globalIndex const rankOffset, string const dofKey, WellElementSubRegion const &subRegion, MultiFluidBase const &fluid, CRSMatrixView< real64, globalIndex const > const &localMatrix, arrayView1d< real64 > const &localRhs, BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > const kernelFlags)
Constructor.
arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseInternalEnergy_n
Views on phase internal energy.
GEOS_HOST_DEVICE void computeAccumulation(localIndex const ei, StackVariables &stack) const
Compute the local accumulation contributions to the residual and Jacobian.
GEOS_HOST_DEVICE void setup(localIndex const ei, StackVariables &stack) const
Performs the setup phase for the kernel.
static void createAndLaunch(integer const numComps, real64 const dt, globalIndex const rankOffset, BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags, string const dofKey, WellControls const &wellControls, WellElementSubRegion const &subRegion, MultiFluidBase const &fluid, 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.
FaceBasedAssemblyKernel(real64 const dt, globalIndex const rankOffset, string const wellDofKey, WellControls const &wellControls, WellElementSubRegion const &subRegion, MultiFluidBase const &fluid, CRSMatrixView< real64, globalIndex const > const &localMatrix, arrayView1d< real64 > const &localRhs, BitFlags< isothermalCompositionalMultiphaseBaseKernels::KernelFlags > kernelFlags)
Constructor for the kernel interface.
bool const m_thermalEffectsEnabled
Flag specifying whether thermal effects are enabled.
arrayView3d< real64 const, multifluid::USD_PHASE > m_phaseEnthalpy
Views on phase enthalpy.
GEOS_HOST_DEVICE void computeFlux(localIndex const iwelem, StackVariables &stack) const
Compute the local flux contributions to the residual and Jacobian.
arrayView1d< globalIndex const > m_globalWellElementIndex
Global index of local element.
arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseFraction
Element phase fraction.
static void launch(localIndex const numElements, KERNEL_TYPE const &kernelComponent)
Performs the kernel launch.
static void createAndLaunch(integer const numComp, globalIndex const rankOffset, string const &dofKey, arrayView1d< real64 const > const &localResidual, WellElementSubRegion const &subRegion, MultiFluidBase const &fluid, WellControls const &wellControls, real64 const time, real64 const dt, real64 const minNormalizer, real64(&residualNorm)[2])
Create a new kernel and launch.
arrayView3d< real64 const, multifluid::USD_PHASE > const m_phaseDens_n
View on phase/total density at the previous converged time step.
localIndex const m_iwelemControl
Index of the element where the control is enforced.
virtual GEOS_HOST_DEVICE void computeLinf(localIndex const iwelem, LinfStackVariables &stack) const override
Compute the local values for the Linf norm.
virtual GEOS_HOST_DEVICE void computeL2(localIndex const iwelem, L2StackVariables &stack) const override
Compute the local values and normalizer for the L2 norm.
bool const m_isProducer
Flag indicating whether the well is a producer or an injector.
bool const m_isLocallyOwned
Flag indicating whether the well is locally owned or not.
static void createAndLaunch(integer const numComp, integer const numPhase, ObjectManagerBase &subRegion, MultiFluidBase const &fluid)
Create a new kernel and launch.
Define the interface for the property kernel in charge of computing the total mass density.
GEOS_HOST_DEVICE void compute(localIndex const ei) const
Compute the total mass density in an element.
TotalMassDensityKernel(ObjectManagerBase &subRegion, MultiFluidBase const &fluid)
Constructor.
ConstraintTypeId getControl() const
Get the control type for the well.
WellConstraintBase * getCurrentConstraint()
Get the current consrtaint.
integer getConstraintPhaseIndex() const
Const accessor for the phase constraint index.
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Definition: DataTypes.hpp:179
StackArray< T, 2, MAXSIZE > stackArray2d
Alias for 2D stack array.
Definition: DataTypes.hpp:203
GEOS_GLOBALINDEX_TYPE globalIndex
Global index type (for indexing objects across MPI partitions).
Definition: DataTypes.hpp:87
StackArray< T, 1, MAXSIZE > stackArray1d
Alias for 1D stack array.
Definition: DataTypes.hpp:187
ArraySlice< T, 2, USD > arraySlice2d
Alias for 2D array slice.
Definition: DataTypes.hpp:199
double real64
64-bit floating point type.
Definition: DataTypes.hpp:98
GEOS_LOCALINDEX_TYPE localIndex
Local index type (for indexing objects within an MPI partition).
Definition: DataTypes.hpp:84
ArraySlice< T, 1, USD > arraySlice1d
Alias for 1D array slice.
Definition: DataTypes.hpp:183
LvArray::CRSMatrixView< T, COL_INDEX, INDEX_TYPE const, LvArray::ChaiBuffer > CRSMatrixView
Alias for CRS Matrix View.
Definition: DataTypes.hpp:309
ArrayView< T, 4, USD > arrayView4d
Alias for 4D array view.
Definition: DataTypes.hpp:227
ArrayView< T, 2, USD > arrayView2d
Alias for 2D array view.
Definition: DataTypes.hpp:195
int integer
Signed integer type.
Definition: DataTypes.hpp:81
Array< T, 1 > array1d
Alias for 1D array.
Definition: DataTypes.hpp:175
ArrayView< T, 3, USD > arrayView3d
Alias for 3D array view.
Definition: DataTypes.hpp:211
Kernel variables (dof numbers, jacobian and residual) located on the stack.
stackArray1d< real64, maxNumElems > localEnergyFlux
Storage for the face local residual vector (energy equation)
stackArray2d< real64, maxNumElems *maxStencilSize > localEnergyFluxJacobian_dQ
Storage for the face local Jacobian matrix dQ only.
stackArray2d< real64, maxNumElems *maxStencilSize *CP_Deriv::nDer > localEnergyFluxJacobian
Storage for the face local energy Jacobian matrix dC dP dT.