opm-simulators
blackoilenergymodules.hh
Go to the documentation of this file.
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 /*
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 2 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 
19  Consult the COPYING file in the top-level source directory of this
20  module for the precise wording of the license and the list of
21  copyright holders.
22 */
28 #ifndef EWOMS_BLACK_OIL_ENERGY_MODULE_HH
29 #define EWOMS_BLACK_OIL_ENERGY_MODULE_HH
30 
31 #include <dune/common/fvector.hh>
32 
33 #include <opm/common/ErrorMacros.hpp>
34 #include <opm/common/utility/gpuDecorators.hpp>
35 
36 #include <opm/material/common/Tabulated1DFunction.hpp>
37 #include <opm/material/common/Valgrind.hpp>
38 #include <opm/material/fluidstates/BlackOilFluidState.hpp>
39 
45 #include <opm/material/thermal/EnergyModuleType.hpp>
46 
47 #include <cassert>
48 #include <cmath>
49 #include <istream>
50 #include <memory>
51 #include <ostream>
52 #include <stdexcept>
53 #include <string>
54 
55 
56 namespace Opm {
57 
63 template <class TypeTag>
64 class BlackOilEnergyModule<TypeTag, EnergyModules::FullyImplicitThermal>
65 {
77 
78  static constexpr unsigned temperatureIdx = Indices::temperatureIdx;
79  static constexpr unsigned contiEnergyEqIdx = Indices::contiEnergyEqIdx;
80 
81  static constexpr unsigned enableFullyImplicitThermal = true;
82  static constexpr unsigned numEq = getPropValue<TypeTag, Properties::NumEq>();
83  static constexpr unsigned numPhases = FluidSystem::numPhases;
84 
85 public:
87 
91  static void registerParameters()
92  {
94  }
95 
99  static void registerOutputModules(Model& model,
100  Simulator& simulator)
101  {
102  model.addOutputModule(std::make_unique<VtkBlackOilEnergyModule<TypeTag>>(simulator));
103  }
104 
105  static OPM_HOST_DEVICE bool primaryVarApplies(unsigned pvIdx)
106  {
107  return pvIdx == temperatureIdx;
108  }
109 
110  static std::string primaryVarName([[maybe_unused]] unsigned pvIdx)
111  {
112  assert(primaryVarApplies(pvIdx));
113 
114  return "temperature";
115  }
116 
117  static Scalar primaryVarWeight([[maybe_unused]] unsigned pvIdx)
118  {
119  assert(primaryVarApplies(pvIdx));
120 
121  // TODO: it may be beneficial to chose this differently.
122  return static_cast<Scalar>(1.0);
123  }
124 
125  static OPM_HOST_DEVICE bool eqApplies(unsigned eqIdx)
126  {
127  return eqIdx == contiEnergyEqIdx;
128  }
129 
130  static std::string eqName([[maybe_unused]] unsigned eqIdx)
131  {
132  assert(eqApplies(eqIdx));
133 
134  return "conti^energy";
135  }
136 
137  static Scalar eqWeight([[maybe_unused]] unsigned eqIdx)
138  {
139  assert(eqApplies(eqIdx));
140 
141  return 1.0;
142  }
143 
144  // must be called after water storage is computed
145  template <class StorageType>
146  OPM_HOST_DEVICE static void addStorage(StorageType& storage,
147  const IntensiveQuantities& intQuants)
148  {
149  using LhsEval = typename StorageType::value_type;
150  const FluidSystem& fsys = intQuants.getFluidSystem();
151 
152  const auto& poro = decay<LhsEval>(intQuants.porosity());
153 
154  // accumulate the internal energy of the fluids
155  const auto& fs = intQuants.fluidState();
156  for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
157  if (!fsys.phaseIsActive(phaseIdx)) {
158  continue;
159  }
160 
161  const auto& u = decay<LhsEval>(fs.internalEnergy(phaseIdx));
162  const auto& S = decay<LhsEval>(fs.saturation(phaseIdx));
163  const auto& rho = decay<LhsEval>(fs.density(phaseIdx));
164 
165  storage[contiEnergyEqIdx] += poro*S*u*rho;
166  }
167 
168  // add the internal energy of the rock
169  const Scalar rockFraction = intQuants.rockFraction();
170  const auto& uRock = decay<LhsEval>(intQuants.rockInternalEnergy());
171  storage[contiEnergyEqIdx] += rockFraction * uRock;
172  storage[contiEnergyEqIdx] *= getPropValue<TypeTag, Properties::BlackOilEnergyScalingFactor>();
173  }
174 
175  OPM_HOST_DEVICE static void computeFlux(RateVector& flux,
176  const ElementContext& elemCtx,
177  unsigned scvfIdx,
178  unsigned timeIdx)
179  {
180  flux[contiEnergyEqIdx] = 0.0;
181 
182  const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
183  const unsigned focusIdx = elemCtx.focusDofIndex();
184  for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
185  if (!FluidSystem::phaseIsActive(phaseIdx)) {
186  continue;
187  }
188 
189  const unsigned upIdx = extQuants.upstreamIndex(phaseIdx);
190  if (upIdx == focusIdx) {
191  addPhaseEnthalpyFlux_<Evaluation>(flux, phaseIdx, elemCtx, scvfIdx, timeIdx);
192  }
193  else {
194  addPhaseEnthalpyFlux_<Scalar>(flux, phaseIdx, elemCtx, scvfIdx, timeIdx);
195  }
196  }
197 
198  // diffusive energy flux
199  flux[contiEnergyEqIdx] += extQuants.energyFlux();
200  flux[contiEnergyEqIdx] *= getPropValue<TypeTag, Properties::BlackOilEnergyScalingFactor>();
201  }
202 
203  template<class RateVectorT>
204  OPM_HOST_DEVICE static void addHeatFlux(RateVectorT& flux,
205  const Evaluation& heatFlux)
206  {
207  // diffusive energy flux
208  flux[contiEnergyEqIdx] += heatFlux;
209  flux[contiEnergyEqIdx] *= getPropValue<TypeTag, Properties::BlackOilEnergyScalingFactor>();
210  }
211 
212  template <class UpEval, class RateVectorT, class Eval, class FluidState>
213  OPM_HOST_DEVICE static void addPhaseEnthalpyFluxes_(RateVectorT& flux,
214  unsigned phaseIdx,
215  const Eval& volumeFlux,
216  const FluidState& upFs)
217  {
218  flux[contiEnergyEqIdx] +=
219  decay<UpEval>(upFs.enthalpy(phaseIdx)) *
220  decay<UpEval>(upFs.density(phaseIdx)) *
221  volumeFlux;
222  }
223 
224  template <class UpstreamEval>
225  OPM_HOST_DEVICE static void addPhaseEnthalpyFlux_(RateVector& flux,
226  unsigned phaseIdx,
227  const ElementContext& elemCtx,
228  unsigned scvfIdx,
229  unsigned timeIdx)
230  {
231  const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
232  const unsigned upIdx = extQuants.upstreamIndex(phaseIdx);
233  const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
234  const auto& fs = up.fluidState();
235  const auto& volFlux = extQuants.volumeFlux(phaseIdx);
236  addPhaseEnthalpyFluxes_<UpstreamEval>(flux,
237  phaseIdx,
238  volFlux,
239  fs);
240  }
241 
242  OPM_HOST_DEVICE static void addToEnthalpyRate(RateVector& flux,
243  const Evaluation& hRate)
244  {
245  flux[contiEnergyEqIdx] += hRate;
246  }
247 
251  template <class FluidState>
252  OPM_HOST_DEVICE static void assignPrimaryVars(PrimaryVariables& priVars,
253  const FluidState& fluidState)
254  {
255  priVars[temperatureIdx] = getValue(fluidState.temperature(/*phaseIdx=*/0));
256  }
257 
261  OPM_HOST_DEVICE static void updatePrimaryVars(PrimaryVariables& newPv,
262  const PrimaryVariables& oldPv,
263  const EqVector& delta)
264  {
265  // do a plain unchopped Newton update
266  newPv[temperatureIdx] = oldPv[temperatureIdx] - delta[temperatureIdx];
267  }
268 
272  OPM_HOST_DEVICE static Scalar computeUpdateError(const PrimaryVariables&,
273  const EqVector&)
274  {
275  // do not consider consider the cange of energy primary variables for
276  // convergence
277  // TODO: maybe this should be changed
278  return static_cast<Scalar>(0.0);
279  }
280 
284  OPM_HOST_DEVICE static Scalar computeResidualError(const EqVector& resid)
285  {
286  // do not weight the residual of energy when it comes to convergence
287  return std::abs(scalarValue(resid[contiEnergyEqIdx]));
288  }
289 
290  template <class DofEntity>
291  static void serializeEntity(const Model& model, std::ostream& outstream, const DofEntity& dof)
292  {
293  const unsigned dofIdx = model.dofMapper().index(dof);
294  const PrimaryVariables& priVars = model.solution(/*timeIdx=*/0)[dofIdx];
295  outstream << priVars[temperatureIdx];
296  }
297 
298  template <class DofEntity>
299  static void deserializeEntity(Model& model, std::istream& instream, const DofEntity& dof)
300  {
301  const unsigned dofIdx = model.dofMapper().index(dof);
302  PrimaryVariables& priVars0 = model.solution(/*timeIdx=*/0)[dofIdx];
303  PrimaryVariables& priVars1 = model.solution(/*timeIdx=*/1)[dofIdx];
304 
305  instream >> priVars0[temperatureIdx];
306 
307  // set the primary variables for the beginning of the current time step.
308  priVars1 = priVars0[temperatureIdx];
309  }
310 };
311 
319 template <class TypeTag>
320 class BlackOilEnergyIntensiveQuantities<TypeTag, EnergyModules::FullyImplicitThermal>
321 {
323 
329  using ThermalConductionLaw = GetPropType<TypeTag, Properties::ThermalConductionLaw>;
333 
334  enum { numPhases = getPropValue<TypeTag, Properties::NumPhases>() };
335  static constexpr unsigned temperatureIdx = Indices::temperatureIdx;
336 
337 public:
341  BlackOilEnergyIntensiveQuantities(Evaluation rockInternalEnergy,
342  Evaluation totalThermalConductivity,
343  Scalar rockFraction)
344  : rockInternalEnergy_(rockInternalEnergy)
345  , totalThermalConductivity_(totalThermalConductivity)
346  , rockFraction_(rockFraction)
347  {
348  }
349 
350  template <class OtherTypeTag>
353  : rockInternalEnergy_(other.rockInternalEnergy())
354  , totalThermalConductivity_(other.totalThermalConductivity())
355  , rockFraction_(other.rockFraction())
356  {}
357 
358  BlackOilEnergyIntensiveQuantities() = default;
359 
364  OPM_HOST_DEVICE void updateTemperature_(const ElementContext& elemCtx,
365  unsigned dofIdx,
366  unsigned timeIdx)
367  {
368  auto& fs = asImp_().fluidState_;
369  const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
370 
371  // set temperature
372  fs.setTemperature(priVars.makeEvaluation(temperatureIdx, timeIdx, elemCtx.linearizationType()));
373  }
374 
379  OPM_HOST_DEVICE void updateTemperature_([[maybe_unused]] const Problem& problem,
380  const PrimaryVariables& priVars,
381  [[maybe_unused]] unsigned globalDofIdx,
382  const unsigned timeIdx,
383  const LinearizationType& lintype)
384  {
385  auto& fs = asImp_().fluidState_;
386  fs.setTemperature(priVars.makeEvaluation(temperatureIdx, timeIdx, lintype));
387  }
388 
393  OPM_HOST_DEVICE void updateEnergyQuantities_(const ElementContext& elemCtx,
394  unsigned dofIdx,
395  unsigned timeIdx)
396  {
397  updateEnergyQuantities_(elemCtx.problem(), elemCtx.globalSpaceIndex(dofIdx, timeIdx), timeIdx);
398  }
399 
400  OPM_HOST_DEVICE void updateEnergyQuantities_(const Problem& problem,
401  const unsigned globalSpaceIdx,
402  const unsigned timeIdx)
403  {
404  auto& fs = asImp_().fluidState_;
405 
406  // compute the specific enthalpy of the fluids, the specific enthalpy of the rock
407  // and the thermal conductivity coefficients
408  for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
409  if (!asImp_().getFluidSystem().phaseIsActive(phaseIdx)) {
410  continue;
411  }
412 
413  const auto& h = asImp_().getFluidSystem().enthalpy(fs, phaseIdx, problem.pvtRegionIndex(globalSpaceIdx));
414  fs.setEnthalpy(phaseIdx, h);
415  }
416 
417  const auto& solidEnergyLawParams = problem.solidEnergyLawParams(globalSpaceIdx, timeIdx);
418  rockInternalEnergy_ = SolidEnergyLaw::solidInternalEnergy(solidEnergyLawParams, fs);
419 
420  const auto& thermalConductionLawParams = problem.thermalConductionLawParams(globalSpaceIdx, timeIdx);
421  totalThermalConductivity_ = ThermalConductionLaw::thermalConductivity(thermalConductionLawParams, fs);
422 
423  // Retrieve the rock fraction from the problem
424  // Usually 1 - porosity, but if pvmult is used to modify porosity
425  // we will apply the same multiplier to the rock fraction
426  // i.e. pvmult*(1 - porosity) and thus interpret multpv as a volume
427  // multiplier. This is to avoid negative rock volume for pvmult*porosity > 1
428  rockFraction_ = problem.rockFraction(globalSpaceIdx, timeIdx);
429  }
430 
431  OPM_HOST_DEVICE const Evaluation& rockInternalEnergy() const
432  { return rockInternalEnergy_; }
433 
434  OPM_HOST_DEVICE const Evaluation& totalThermalConductivity() const
435  { return totalThermalConductivity_; }
436 
437  OPM_HOST_DEVICE Scalar rockFraction() const
438  { return rockFraction_; }
439 
440 protected:
441  OPM_HOST_DEVICE Implementation& asImp_()
442  { return *static_cast<Implementation*>(this); }
443 
444  Evaluation rockInternalEnergy_;
445  Evaluation totalThermalConductivity_;
446  Scalar rockFraction_;
447 };
448 
449 template <class TypeTag>
450 class BlackOilEnergyIntensiveQuantities<TypeTag, EnergyModules::ConstantTemperature>
451 {
458 
460 
461 public:
462 
463  OPM_HOST_DEVICE void updateTemperature_(const ElementContext& elemCtx,
464  unsigned dofIdx,
465  unsigned timeIdx)
466  {
467  updateTemperature_(elemCtx.problem(), elemCtx.globalSpaceIndex(dofIdx, timeIdx), timeIdx);
468  }
469 
470  template<class Problem>
471  OPM_HOST_DEVICE void updateTemperature_(const Problem& problem,
472  [[maybe_unused]] const PrimaryVariables& priVars,
473  unsigned globalDofIdx,
474  unsigned timeIdx,
475  [[maybe_unused]] const LinearizationType& lintype)
476  {
477  updateTemperature_(problem, globalDofIdx, timeIdx);
478  }
479 
480  OPM_HOST_DEVICE void updateTemperature_(const Problem& problem,
481  unsigned globalDofIdx,
482  unsigned timeIdx)
483  {
484  auto& fs = asImp_().fluidState_;
485  const Scalar T = problem.temperature(globalDofIdx, timeIdx);
486  fs.setTemperature(T);
487  }
488 
489  OPM_HOST_DEVICE void updateEnergyQuantities_(const ElementContext&,
490  unsigned,
491  unsigned,
492  const typename FluidSystem::template ParameterCache<Evaluation>&)
493  {}
494 
495  OPM_HOST_DEVICE const Evaluation& rockInternalEnergy() const
496  {
497  OPM_THROW(std::logic_error,
498  "Requested the rock internal energy, which is "
499  "unavailable because energy is not conserved");
500  }
501 
502  OPM_HOST_DEVICE const Evaluation& totalThermalConductivity() const
503  {
504  OPM_THROW(std::logic_error,
505  "Requested the total thermal conductivity, which is "
506  "unavailable because energy is not conserved");
507  }
508 
509 protected:
510  OPM_HOST_DEVICE Implementation& asImp_()
511  { return *static_cast<Implementation*>(this); }
512 };
513 
514 template <class TypeTag>
515 class BlackOilEnergyIntensiveQuantities<TypeTag, EnergyModules::SequentialImplicitThermal>
516 {
524  using ThermalConductionLaw = GetPropType<TypeTag, Properties::ThermalConductionLaw>;
527 
528 public:
529 
530  OPM_HOST_DEVICE void updateTemperature_(const Problem& problem,
531  unsigned globalDofIdx,
532  unsigned timeIdx)
533  {
534  // update the temperature for output (without derivatives)
535  auto& fs = asImp_().fluidState_;
536  fs.setTemperature(problem.temperature(globalDofIdx, timeIdx));
537  }
538 
539  OPM_HOST_DEVICE void updateTemperature_(const ElementContext& elemCtx,
540  unsigned dofIdx,
541  unsigned timeIdx)
542  {
543  updateTemperature_(elemCtx.problem(), elemCtx.globalSpaceIndex(dofIdx, timeIdx), timeIdx);
544  }
545 
546  template<class Problem>
547  OPM_HOST_DEVICE void updateTemperature_(const Problem& problem,
548  [[maybe_unused]] const PrimaryVariables& priVars,
549  unsigned globalDofIdx,
550  unsigned timeIdx,
551  [[maybe_unused]] const LinearizationType& lintype)
552  {
553  updateTemperature_(problem, globalDofIdx, timeIdx);
554  }
555 
560  OPM_HOST_DEVICE void updateEnergyQuantities_([[maybe_unused]] const ElementContext& elemCtx,
561  [[maybe_unused]] unsigned dofIdx,
562  [[maybe_unused]] unsigned timeIdx)
563  {
564  }
565 
566  OPM_HOST_DEVICE void updateEnergyQuantities_([[maybe_unused]] const Problem& problem,
567  [[maybe_unused]] const unsigned globalSpaceIdx,
568  [[maybe_unused]] const unsigned timeIdx)
569  {
570  }
571 
572  OPM_HOST_DEVICE const Evaluation& rockInternalEnergy() const
573  {
574  OPM_THROW(std::logic_error,
575  "Requested the rock internal energy, which is "
576  "unavailable because energy is not conserved");
577  }
578 
579  OPM_HOST_DEVICE const Evaluation& totalThermalConductivity() const
580  {
581  OPM_THROW(std::logic_error,
582  "Requested the total thermal conductivity, which is "
583  "unavailable because energy is not conserved");
584  }
585 
586 protected:
587  OPM_HOST_DEVICE Implementation& asImp_()
588  { return *static_cast<Implementation*>(this); }
589 
590 };
591 
599 template <class TypeTag>
600 class BlackOilEnergyExtensiveQuantities<TypeTag, EnergyModules::FullyImplicitThermal>
601 {
603 
607 
608 public:
609  template<class Evaluation, class FluidState, class IntensiveQuantities>
610  OPM_HOST_DEVICE static void updateEnergy(Evaluation& energyFlux,
611  const unsigned& focusDofIndex,
612  const unsigned& inIdx,
613  const unsigned& exIdx,
614  const IntensiveQuantities& inIq,
615  const IntensiveQuantities& exIq,
616  const FluidState& inFs,
617  const FluidState& exFs,
618  const Scalar& inAlpha,
619  const Scalar& outAlpha,
620  const Scalar& faceArea)
621  {
622  Evaluation deltaT;
623  if (focusDofIndex == inIdx) {
624  deltaT = decay<Scalar>(exFs.temperature(/*phaseIdx=*/0)) -
625  inFs.temperature(/*phaseIdx=*/0);
626  }
627  else if (focusDofIndex == exIdx) {
628  deltaT = exFs.temperature(/*phaseIdx=*/0) -
629  decay<Scalar>(inFs.temperature(/*phaseIdx=*/0));
630  }
631  else {
632  deltaT = decay<Scalar>(exFs.temperature(/*phaseIdx=*/0)) -
633  decay<Scalar>(inFs.temperature(/*phaseIdx=*/0));
634  }
635 
636  Evaluation inLambda;
637  if (focusDofIndex == inIdx) {
638  inLambda = inIq.totalThermalConductivity();
639  }
640  else {
641  inLambda = decay<Scalar>(inIq.totalThermalConductivity());
642  }
643 
644  Evaluation exLambda;
645  if (focusDofIndex == exIdx) {
646  exLambda = exIq.totalThermalConductivity();
647  }
648  else {
649  exLambda = decay<Scalar>(exIq.totalThermalConductivity());
650  }
651 
652  Evaluation H;
653  const Evaluation& inH = inLambda*inAlpha;
654  const Evaluation& exH = exLambda*outAlpha;
655  if (inH > 0 && exH > 0) {
656  // compute the "thermal transmissibility". In contrast to the normal
657  // transmissibility this cannot be done as a preprocessing step because the
658  // average thermal conductivity is analogous to the permeability but
659  // depends on the solution.
660  H = 1.0 / (1.0 / inH + 1.0 / exH);
661  }
662  else {
663  H = 0.0;
664  }
665 
666  energyFlux = deltaT * (-H / faceArea);
667  }
668 
669  void updateEnergy(const ElementContext& elemCtx,
670  unsigned scvfIdx,
671  unsigned timeIdx)
672  {
673  const auto& stencil = elemCtx.stencil(timeIdx);
674  const auto& scvf = stencil.interiorFace(scvfIdx);
675 
676  const Scalar faceArea = scvf.area();
677  const unsigned inIdx = scvf.interiorIndex();
678  const unsigned exIdx = scvf.exteriorIndex();
679  const auto& inIq = elemCtx.intensiveQuantities(inIdx, timeIdx);
680  const auto& exIq = elemCtx.intensiveQuantities(exIdx, timeIdx);
681  const auto& inFs = inIq.fluidState();
682  const auto& exFs = exIq.fluidState();
683  const Scalar inAlpha = elemCtx.problem().thermalHalfTransmissibilityIn(elemCtx, scvfIdx, timeIdx);
684  const Scalar outAlpha = elemCtx.problem().thermalHalfTransmissibilityOut(elemCtx, scvfIdx, timeIdx);
685  updateEnergy(energyFlux_,
686  elemCtx.focusDofIndex(),
687  inIdx,
688  exIdx,
689  inIq,
690  exIq,
691  inFs,
692  exFs,
693  inAlpha,
694  outAlpha,
695  faceArea);
696  }
697 
698  template <class Context, class BoundaryFluidState>
699  void updateEnergyBoundary(const Context& ctx,
700  unsigned scvfIdx,
701  unsigned timeIdx,
702  const BoundaryFluidState& boundaryFs)
703  {
704  const auto& stencil = ctx.stencil(timeIdx);
705  const auto& scvf = stencil.boundaryFace(scvfIdx);
706 
707  const unsigned inIdx = scvf.interiorIndex();
708  const auto& inIq = ctx.intensiveQuantities(inIdx, timeIdx);
709  const auto& focusDofIdx = ctx.focusDofIndex();
710  const Scalar alpha = ctx.problem().thermalHalfTransmissibilityBoundary(ctx, scvfIdx);
711  updateEnergyBoundary(energyFlux_, inIq, focusDofIdx, inIdx, alpha, boundaryFs);
712  }
713 
714  template <class Evaluation, class BoundaryFluidState, class IntensiveQuantities>
715  OPM_HOST_DEVICE static void updateEnergyBoundary(Evaluation& energyFlux,
716  const IntensiveQuantities& inIq,
717  unsigned focusDofIndex,
718  unsigned inIdx,
719  Scalar alpha,
720  const BoundaryFluidState& boundaryFs)
721  {
722  const auto& inFs = inIq.fluidState();
723  Evaluation deltaT;
724  if (focusDofIndex == inIdx) {
725  deltaT = boundaryFs.temperature(/*phaseIdx=*/0) -
726  inFs.temperature(/*phaseIdx=*/0);
727  }
728  else {
729  deltaT = decay<Scalar>(boundaryFs.temperature(/*phaseIdx=*/0)) -
730  decay<Scalar>(inFs.temperature(/*phaseIdx=*/0));
731  }
732 
733  Evaluation lambda;
734  if (focusDofIndex == inIdx) {
735  lambda = inIq.totalThermalConductivity();
736  }
737  else {
738  lambda = decay<Scalar>(inIq.totalThermalConductivity());
739  }
740 
741  if (lambda > 0.0) {
742  // compute the "thermal transmissibility". In contrast to the normal
743  // transmissibility this cannot be done as a preprocessing step because the
744  // average thermal conductivity is analogous to the permeability but depends
745  // on the solution.
746  energyFlux = deltaT * lambda * -alpha;
747  }
748  else {
749  energyFlux = 0.0;
750  }
751  }
752 
753  const Evaluation& energyFlux() const
754  { return energyFlux_; }
755 
756 private:
757  Implementation& asImp_()
758  { return *static_cast<Implementation*>(this); }
759 
760  Evaluation energyFlux_;
761 };
762 
763 template <class TypeTag>
764 class BlackOilEnergyExtensiveQuantities<TypeTag, EnergyModules::SequentialImplicitThermal>
765 {
769 
770 public:
771  template<class Evaluation, class FluidState, class IntensiveQuantities>
772  static void updateEnergy(Evaluation& energyFlux,
773  const unsigned& focusDofIndex,
774  const unsigned& inIdx,
775  const unsigned& exIdx,
776  const IntensiveQuantities& inIq,
777  const IntensiveQuantities& exIq,
778  const FluidState& inFs,
779  const FluidState& exFs,
780  const Scalar& inAlpha,
781  const Scalar& outAlpha,
782  const Scalar& faceArea)
783  {
784  // Uses the same caculations as the FullyImplicitThermal approach
786  focusDofIndex,
787  inIdx,
788  exIdx,
789  inIq,
790  exIq,
791  inFs,
792  exFs,
793  inAlpha,
794  outAlpha,
795  faceArea);
796  }
797 
798  void updateEnergy(const ElementContext&,
799  unsigned,
800  unsigned)
801  { } // Old interface still used output code for fluxes. But energy flux is not used. i.e. do nothing
802 
803  template <class Context, class BoundaryFluidState>
804  void updateEnergyBoundary(const Context&,
805  unsigned,
806  unsigned,
807  const BoundaryFluidState&)
808  { }
809 
810  template <class Evaluation, class BoundaryFluidState, class IntensiveQuantities>
811  static void updateEnergyBoundary(Evaluation& /*heatFlux*/,
812  const IntensiveQuantities& /*inIq*/,
813  unsigned /*focusDofIndex*/,
814  unsigned /*inIdx*/,
815  unsigned /*timeIdx*/,
816  Scalar /*alpha*/,
817  const BoundaryFluidState& /*boundaryFs*/)
818  { }
819 
820  OPM_HOST_DEVICE const Evaluation& energyFlux() const
821  { OPM_THROW(std::logic_error, "Requested the energy flux, but energy is not conserved"); }
822 };
823 
824 } // namespace Opm
825 
826 #endif
OPM_HOST_DEVICE void updateTemperature_([[maybe_unused]] const Problem &problem, const PrimaryVariables &priVars, [[maybe_unused]] unsigned globalDofIdx, const unsigned timeIdx, const LinearizationType &lintype)
Update the temperature of the intensive quantity&#39;s fluid state.
Definition: blackoilenergymodules.hh:379
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(...))
Definition: propertysystem.hh:233
VTK output module for the black oil model&#39;s energy related quantities.
Definition: vtkblackoilenergymodule.hpp:53
static void registerOutputModules(Model &model, Simulator &simulator)
Register all energy specific VTK and ECL output modules.
Definition: blackoilenergymodules.hh:99
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
static void registerParameters()
Register all run-time parameters for the multi-phase VTK output module.
Definition: vtkblackoilenergymodule.hpp:84
Contains classes extending the black-oil model.
Definition: blackoilmodules.hpp:62
Declares the properties required by the black oil model.
static OPM_HOST_DEVICE void assignPrimaryVars(PrimaryVariables &priVars, const FluidState &fluidState)
Assign the energy specific primary variables to a PrimaryVariables object.
Definition: blackoilenergymodules.hh:252
Provides the volumetric quantities required for the equations needed by the energys extension of the ...
Definition: blackoilmodules.hpp:67
OPM_HOST_DEVICE void updateEnergyQuantities_([[maybe_unused]] const ElementContext &elemCtx, [[maybe_unused]] unsigned dofIdx, [[maybe_unused]] unsigned timeIdx)
Compute the intensive quantities needed to handle energy conservation.
Definition: blackoilenergymodules.hh:560
VTK output module for the black oil model&#39;s energy related quantities.
Definition: linearizationtype.hh:33
This method contains all callback classes for quantities that are required by some extensive quantiti...
The common code for the linearizers of non-linear systems of equations.
Provides the energy specific extensive quantities to the generic black-oil module&#39;s extensive quantit...
Definition: blackoilmodules.hpp:72
OPM_HOST_DEVICE void updateTemperature_(const ElementContext &elemCtx, unsigned dofIdx, unsigned timeIdx)
Update the temperature of the intensive quantity&#39;s fluid state.
Definition: blackoilenergymodules.hh:364
BlackOilEnergyIntensiveQuantities(Evaluation rockInternalEnergy, Evaluation totalThermalConductivity, Scalar rockFraction)
Construct the energy intensive quantities for the fully implicit thermal module.
Definition: blackoilenergymodules.hh:341
OPM_HOST_DEVICE void updateEnergyQuantities_(const ElementContext &elemCtx, unsigned dofIdx, unsigned timeIdx)
Compute the intensive quantities needed to handle energy conservation.
Definition: blackoilenergymodules.hh:393
static OPM_HOST_DEVICE void updatePrimaryVars(PrimaryVariables &newPv, const PrimaryVariables &oldPv, const EqVector &delta)
Do a Newton-Raphson update the primary variables of the energys.
Definition: blackoilenergymodules.hh:261
static void registerParameters()
Register all run-time parameters for the black-oil energy module.
Definition: blackoilenergymodules.hh:91
static OPM_HOST_DEVICE Scalar computeResidualError(const EqVector &resid)
Return how much a residual is considered an error.
Definition: blackoilenergymodules.hh:284
static OPM_HOST_DEVICE Scalar computeUpdateError(const PrimaryVariables &, const EqVector &)
Return how much a Newton-Raphson update is considered an error.
Definition: blackoilenergymodules.hh:272