76 static constexpr unsigned temperatureIdx = Indices::temperatureIdx;
77 static constexpr unsigned contiEnergyEqIdx = Indices::contiEnergyEqIdx;
79 static constexpr unsigned enableFullyImplicitThermal = (activeModule == EnergyModules::FullyImplicitThermal);
81 static constexpr unsigned numPhases = FluidSystem::numPhases;
91 if constexpr (enableFullyImplicitThermal) {
100 Simulator& simulator)
102 if constexpr (enableFullyImplicitThermal) {
107 static bool primaryVarApplies(
unsigned pvIdx)
109 if constexpr (enableFullyImplicitThermal) {
110 return pvIdx == temperatureIdx;
117 static std::string primaryVarName([[maybe_unused]]
unsigned pvIdx)
119 assert(primaryVarApplies(pvIdx));
121 return "temperature";
124 static Scalar primaryVarWeight([[maybe_unused]]
unsigned pvIdx)
126 assert(primaryVarApplies(pvIdx));
129 return static_cast<Scalar
>(1.0);
132 static bool eqApplies(
unsigned eqIdx)
134 if constexpr (enableFullyImplicitThermal) {
135 return eqIdx == contiEnergyEqIdx;
142 static std::string eqName([[maybe_unused]]
unsigned eqIdx)
144 assert(eqApplies(eqIdx));
146 return "conti^energy";
149 static Scalar eqWeight([[maybe_unused]]
unsigned eqIdx)
151 assert(eqApplies(eqIdx));
157 template <
class StorageType>
158 OPM_HOST_DEVICE
static void addStorage(StorageType& storage,
159 const IntensiveQuantities& intQuants)
161 using LhsEval =
typename StorageType::value_type;
163 if constexpr (enableFullyImplicitThermal) {
164 const FluidSystem& fsys = intQuants.getFluidSystem();
166 const auto& poro = decay<LhsEval>(intQuants.porosity());
169 const auto& fs = intQuants.fluidState();
170 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
171 if (!fsys.phaseIsActive(phaseIdx)) {
175 const auto& u = decay<LhsEval>(fs.internalEnergy(phaseIdx));
176 const auto& S = decay<LhsEval>(fs.saturation(phaseIdx));
177 const auto& rho = decay<LhsEval>(fs.density(phaseIdx));
179 storage[contiEnergyEqIdx] += poro*S*u*rho;
183 const Scalar rockFraction = intQuants.rockFraction();
184 const auto& uRock = decay<LhsEval>(intQuants.rockInternalEnergy());
185 storage[contiEnergyEqIdx] += rockFraction * uRock;
190 OPM_HOST_DEVICE
static void computeFlux([[maybe_unused]] RateVector& flux,
191 [[maybe_unused]]
const ElementContext& elemCtx,
192 [[maybe_unused]]
unsigned scvfIdx,
193 [[maybe_unused]]
unsigned timeIdx)
195 if constexpr (enableFullyImplicitThermal) {
196 flux[contiEnergyEqIdx] = 0.0;
198 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
199 const unsigned focusIdx = elemCtx.focusDofIndex();
200 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
201 if (!FluidSystem::phaseIsActive(phaseIdx)) {
205 const unsigned upIdx = extQuants.upstreamIndex(phaseIdx);
206 if (upIdx == focusIdx) {
207 addPhaseEnthalpyFlux_<Evaluation>(flux, phaseIdx, elemCtx, scvfIdx, timeIdx);
210 addPhaseEnthalpyFlux_<Scalar>(flux, phaseIdx, elemCtx, scvfIdx, timeIdx);
215 flux[contiEnergyEqIdx] += extQuants.energyFlux();
220 template<
class RateVectorT>
221 OPM_HOST_DEVICE
static void addHeatFlux(RateVectorT& flux,
222 const Evaluation& heatFlux)
224 if constexpr (enableFullyImplicitThermal) {
226 flux[contiEnergyEqIdx] += heatFlux;
231 template <
class UpEval,
class RateVectorT,
class Eval,
class Flu
idState>
232 OPM_HOST_DEVICE
static void addPhaseEnthalpyFluxes_(RateVectorT& flux,
234 const Eval& volumeFlux,
235 const FluidState& upFs)
237 flux[contiEnergyEqIdx] +=
238 decay<UpEval>(upFs.enthalpy(phaseIdx)) *
239 decay<UpEval>(upFs.density(phaseIdx)) *
243 template <
class UpstreamEval>
244 static void addPhaseEnthalpyFlux_(RateVector& flux,
246 const ElementContext& elemCtx,
250 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
251 const unsigned upIdx = extQuants.upstreamIndex(phaseIdx);
252 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
253 const auto& fs = up.fluidState();
254 const auto& volFlux = extQuants.volumeFlux(phaseIdx);
255 addPhaseEnthalpyFluxes_<UpstreamEval>(flux,
261 static void addToEnthalpyRate(RateVector& flux,
262 const Evaluation& hRate)
264 if constexpr (enableFullyImplicitThermal) {
265 flux[contiEnergyEqIdx] += hRate;
272 template <
class Flu
idState>
274 const FluidState& fluidState)
276 if constexpr (enableFullyImplicitThermal) {
277 priVars[temperatureIdx] = getValue(fluidState.temperature(0));
285 const PrimaryVariables& oldPv,
286 const EqVector& delta)
288 if constexpr (enableFullyImplicitThermal) {
290 newPv[temperatureIdx] = oldPv[temperatureIdx] - delta[temperatureIdx];
303 return static_cast<Scalar
>(0.0);
312 return std::abs(scalarValue(resid[contiEnergyEqIdx]));
315 template <
class DofEntity>
316 static void serializeEntity(
const Model& model, std::ostream& outstream,
const DofEntity& dof)
318 if constexpr (enableFullyImplicitThermal) {
319 const unsigned dofIdx = model.dofMapper().index(dof);
320 const PrimaryVariables& priVars = model.solution(0)[dofIdx];
321 outstream << priVars[temperatureIdx];
325 template <
class DofEntity>
326 static void deserializeEntity(Model& model, std::istream& instream,
const DofEntity& dof)
328 if constexpr (enableFullyImplicitThermal) {
329 const unsigned dofIdx = model.dofMapper().index(dof);
330 PrimaryVariables& priVars0 = model.solution(0)[dofIdx];
331 PrimaryVariables& priVars1 = model.solution(1)[dofIdx];
333 instream >> priVars0[temperatureIdx];
336 priVars1 = priVars0[temperatureIdx];
367 static constexpr int temperatureIdx = Indices::temperatureIdx;
374 Evaluation totalThermalConductivity,
376 : rockInternalEnergy_(rockInternalEnergy)
377 , totalThermalConductivity_(totalThermalConductivity)
378 , rockFraction_(rockFraction)
392 auto& fs = asImp_().fluidState_;
393 const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
396 fs.setTemperature(priVars.makeEvaluation(temperatureIdx, timeIdx, elemCtx.linearizationType()));
404 const PrimaryVariables& priVars,
405 [[maybe_unused]]
unsigned globalDofIdx,
406 const unsigned timeIdx,
409 auto& fs = asImp_().fluidState_;
410 fs.setTemperature(priVars.makeEvaluation(temperatureIdx, timeIdx, lintype));
424 void updateEnergyQuantities_(
const Problem& problem,
425 const unsigned globalSpaceIdx,
426 const unsigned timeIdx)
428 auto& fs = asImp_().fluidState_;
432 for (
int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
433 if (!FluidSystem::phaseIsActive(phaseIdx)) {
437 const auto& h = FluidSystem::enthalpy(fs, phaseIdx, problem.pvtRegionIndex(globalSpaceIdx));
438 fs.setEnthalpy(phaseIdx, h);
441 const auto& solidEnergyLawParams = problem.solidEnergyLawParams(globalSpaceIdx, timeIdx);
442 rockInternalEnergy_ = SolidEnergyLaw::solidInternalEnergy(solidEnergyLawParams, fs);
444 const auto& thermalConductionLawParams = problem.thermalConductionLawParams(globalSpaceIdx, timeIdx);
445 totalThermalConductivity_ = ThermalConductionLaw::thermalConductivity(thermalConductionLawParams, fs);
452 rockFraction_ = problem.rockFraction(globalSpaceIdx, timeIdx);
455 OPM_HOST_DEVICE
const Evaluation& rockInternalEnergy()
const
456 {
return rockInternalEnergy_; }
458 OPM_HOST_DEVICE
const Evaluation& totalThermalConductivity()
const
459 {
return totalThermalConductivity_; }
461 OPM_HOST_DEVICE Scalar rockFraction()
const
462 {
return rockFraction_; }
465 Implementation& asImp_()
466 {
return *
static_cast<Implementation*
>(
this); }
468 Evaluation rockInternalEnergy_;
469 Evaluation totalThermalConductivity_;
470 Scalar rockFraction_;
678 template<
class Evaluation,
class Flu
idState,
class IntensiveQuantities>
679 OPM_HOST_DEVICE
static void updateEnergy(Evaluation& energyFlux,
680 const unsigned& focusDofIndex,
681 const unsigned& inIdx,
682 const unsigned& exIdx,
683 const IntensiveQuantities& inIq,
684 const IntensiveQuantities& exIq,
685 const FluidState& inFs,
686 const FluidState& exFs,
687 const Scalar& inAlpha,
688 const Scalar& outAlpha,
689 const Scalar& faceArea)
692 if (focusDofIndex == inIdx) {
693 deltaT = decay<Scalar>(exFs.temperature(0)) -
696 else if (focusDofIndex == exIdx) {
697 deltaT = exFs.temperature(0) -
698 decay<Scalar>(inFs.temperature(0));
701 deltaT = decay<Scalar>(exFs.temperature(0)) -
702 decay<Scalar>(inFs.temperature(0));
706 if (focusDofIndex == inIdx) {
707 inLambda = inIq.totalThermalConductivity();
710 inLambda = decay<Scalar>(inIq.totalThermalConductivity());
714 if (focusDofIndex == exIdx) {
715 exLambda = exIq.totalThermalConductivity();
718 exLambda = decay<Scalar>(exIq.totalThermalConductivity());
722 const Evaluation& inH = inLambda*inAlpha;
723 const Evaluation& exH = exLambda*outAlpha;
724 if (inH > 0 && exH > 0) {
729 H = 1.0 / (1.0 / inH + 1.0 / exH);
735 energyFlux = deltaT * (-H / faceArea);
738 void updateEnergy(
const ElementContext& elemCtx,
742 const auto& stencil = elemCtx.stencil(timeIdx);
743 const auto& scvf = stencil.interiorFace(scvfIdx);
745 const Scalar faceArea = scvf.area();
746 const unsigned inIdx = scvf.interiorIndex();
747 const unsigned exIdx = scvf.exteriorIndex();
748 const auto& inIq = elemCtx.intensiveQuantities(inIdx, timeIdx);
749 const auto& exIq = elemCtx.intensiveQuantities(exIdx, timeIdx);
750 const auto& inFs = inIq.fluidState();
751 const auto& exFs = exIq.fluidState();
752 const Scalar inAlpha = elemCtx.problem().thermalHalfTransmissibilityIn(elemCtx, scvfIdx, timeIdx);
753 const Scalar outAlpha = elemCtx.problem().thermalHalfTransmissibilityOut(elemCtx, scvfIdx, timeIdx);
754 updateEnergy(energyFlux_,
755 elemCtx.focusDofIndex(),
767 template <
class Context,
class BoundaryFlu
idState>
768 void updateEnergyBoundary(
const Context& ctx,
771 const BoundaryFluidState& boundaryFs)
773 const auto& stencil = ctx.stencil(timeIdx);
774 const auto& scvf = stencil.boundaryFace(scvfIdx);
776 const unsigned inIdx = scvf.interiorIndex();
777 const auto& inIq = ctx.intensiveQuantities(inIdx, timeIdx);
778 const auto& focusDofIdx = ctx.focusDofIndex();
779 const Scalar alpha = ctx.problem().thermalHalfTransmissibilityBoundary(ctx, scvfIdx);
780 updateEnergyBoundary(energyFlux_, inIq, focusDofIdx, inIdx, alpha, boundaryFs);
783 template <
class Evaluation,
class BoundaryFlu
idState,
class IntensiveQuantities>
784 OPM_HOST_DEVICE
static void updateEnergyBoundary(Evaluation& energyFlux,
785 const IntensiveQuantities& inIq,
786 unsigned focusDofIndex,
789 const BoundaryFluidState& boundaryFs)
791 const auto& inFs = inIq.fluidState();
793 if (focusDofIndex == inIdx) {
794 deltaT = boundaryFs.temperature(0) -
798 deltaT = decay<Scalar>(boundaryFs.temperature(0)) -
799 decay<Scalar>(inFs.temperature(0));
803 if (focusDofIndex == inIdx) {
804 lambda = inIq.totalThermalConductivity();
807 lambda = decay<Scalar>(inIq.totalThermalConductivity());
815 energyFlux = deltaT * lambda * -alpha;
822 const Evaluation& energyFlux()
const
823 {
return energyFlux_; }
826 Implementation& asImp_()
827 {
return *
static_cast<Implementation*
>(
this); }
829 Evaluation energyFlux_;