71 static constexpr unsigned temperatureIdx = Indices::temperatureIdx;
72 static constexpr unsigned contiEnergyEqIdx = Indices::contiEnergyEqIdx;
74 static constexpr unsigned enableEnergy = enableEnergyV;
76 static constexpr unsigned numPhases = FluidSystem::numPhases;
86 if constexpr (enableEnergy) {
97 if constexpr (enableEnergy) {
102 static bool primaryVarApplies(
unsigned pvIdx)
104 if constexpr (enableEnergy) {
105 return pvIdx == temperatureIdx;
112 static std::string primaryVarName([[maybe_unused]]
unsigned pvIdx)
114 assert(primaryVarApplies(pvIdx));
116 return "temperature";
119 static Scalar primaryVarWeight([[maybe_unused]]
unsigned pvIdx)
121 assert(primaryVarApplies(pvIdx));
124 return static_cast<Scalar
>(1.0);
127 static bool eqApplies(
unsigned eqIdx)
129 if constexpr (enableEnergy) {
130 return eqIdx == contiEnergyEqIdx;
137 static std::string eqName([[maybe_unused]]
unsigned eqIdx)
139 assert(eqApplies(eqIdx));
141 return "conti^energy";
144 static Scalar eqWeight([[maybe_unused]]
unsigned eqIdx)
146 assert(eqApplies(eqIdx));
152 template <
class LhsEval>
153 static void addStorage(Dune::FieldVector<LhsEval, numEq>& storage,
154 const IntensiveQuantities& intQuants)
156 if constexpr (enableEnergy) {
157 const auto& poro = decay<LhsEval>(intQuants.porosity());
160 const auto& fs = intQuants.fluidState();
161 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
162 if (!FluidSystem::phaseIsActive(phaseIdx)) {
166 const auto& u = decay<LhsEval>(fs.internalEnergy(phaseIdx));
167 const auto& S = decay<LhsEval>(fs.saturation(phaseIdx));
168 const auto& rho = decay<LhsEval>(fs.density(phaseIdx));
170 storage[contiEnergyEqIdx] += poro*S*u*rho;
174 const Scalar rockFraction = intQuants.rockFraction();
175 const auto& uRock = decay<LhsEval>(intQuants.rockInternalEnergy());
176 storage[contiEnergyEqIdx] += rockFraction * uRock;
181 static void computeFlux([[maybe_unused]] RateVector& flux,
182 [[maybe_unused]]
const ElementContext& elemCtx,
183 [[maybe_unused]]
unsigned scvfIdx,
184 [[maybe_unused]]
unsigned timeIdx)
186 if constexpr (enableEnergy) {
187 flux[contiEnergyEqIdx] = 0.0;
189 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
190 const unsigned focusIdx = elemCtx.focusDofIndex();
191 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
192 if (!FluidSystem::phaseIsActive(phaseIdx)) {
196 const unsigned upIdx = extQuants.upstreamIndex(phaseIdx);
197 if (upIdx == focusIdx) {
198 addPhaseEnthalpyFlux_<Evaluation>(flux, phaseIdx, elemCtx, scvfIdx, timeIdx);
201 addPhaseEnthalpyFlux_<Scalar>(flux, phaseIdx, elemCtx, scvfIdx, timeIdx);
206 flux[contiEnergyEqIdx] += extQuants.energyFlux();
211 static void addHeatFlux(RateVector& flux,
212 const Evaluation& heatFlux)
214 if constexpr (enableEnergy) {
216 flux[contiEnergyEqIdx] += heatFlux;
221 template <
class UpEval,
class Eval,
class Flu
idState>
222 static void addPhaseEnthalpyFluxes_(RateVector& flux,
224 const Eval& volumeFlux,
225 const FluidState& upFs)
227 flux[contiEnergyEqIdx] +=
228 decay<UpEval>(upFs.enthalpy(phaseIdx)) *
229 decay<UpEval>(upFs.density(phaseIdx)) *
233 template <
class UpstreamEval>
234 static void addPhaseEnthalpyFlux_(RateVector& flux,
236 const ElementContext& elemCtx,
240 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
241 const unsigned upIdx = extQuants.upstreamIndex(phaseIdx);
242 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
243 const auto& fs = up.fluidState();
244 const auto& volFlux = extQuants.volumeFlux(phaseIdx);
245 addPhaseEnthalpyFluxes_<UpstreamEval>(flux,
251 static void addToEnthalpyRate(RateVector& flux,
252 const Evaluation& hRate)
254 if constexpr (enableEnergy) {
255 flux[contiEnergyEqIdx] += hRate;
262 template <
class Flu
idState>
264 const FluidState& fluidState)
266 if constexpr (enableEnergy) {
267 priVars[temperatureIdx] = getValue(fluidState.temperature(0));
275 const PrimaryVariables& oldPv,
276 const EqVector& delta)
278 if constexpr (enableEnergy) {
280 newPv[temperatureIdx] = oldPv[temperatureIdx] - delta[temperatureIdx];
293 return static_cast<Scalar
>(0.0);
302 return std::abs(scalarValue(resid[contiEnergyEqIdx]));
305 template <
class DofEntity>
306 static void serializeEntity(
const Model& model, std::ostream& outstream,
const DofEntity& dof)
308 if constexpr (enableEnergy) {
309 const unsigned dofIdx = model.dofMapper().index(dof);
310 const PrimaryVariables& priVars = model.solution(0)[dofIdx];
311 outstream << priVars[temperatureIdx];
315 template <
class DofEntity>
316 static void deserializeEntity(Model& model, std::istream& instream,
const DofEntity& dof)
318 if constexpr (enableEnergy) {
319 const unsigned dofIdx = model.dofMapper().index(dof);
320 PrimaryVariables& priVars0 = model.solution(0)[dofIdx];
321 PrimaryVariables& priVars1 = model.solution(1)[dofIdx];
323 instream >> priVars0[temperatureIdx];
326 priVars1 = priVars0[temperatureIdx];
357 static constexpr int temperatureIdx = Indices::temperatureIdx;
368 auto& fs = asImp_().fluidState_;
369 const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
372 fs.setTemperature(priVars.makeEvaluation(temperatureIdx, timeIdx, elemCtx.linearizationType()));
380 const PrimaryVariables& priVars,
381 [[maybe_unused]]
unsigned globalDofIdx,
382 const unsigned timeIdx,
385 auto& fs = asImp_().fluidState_;
386 fs.setTemperature(priVars.makeEvaluation(temperatureIdx, timeIdx, lintype));
400 void updateEnergyQuantities_(
const Problem& problem,
401 const unsigned globalSpaceIdx,
402 const unsigned timeIdx)
404 auto& fs = asImp_().fluidState_;
408 for (
int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
409 if (!FluidSystem::phaseIsActive(phaseIdx)) {
413 const auto& h = FluidSystem::enthalpy(fs, phaseIdx, problem.pvtRegionIndex(globalSpaceIdx));
414 fs.setEnthalpy(phaseIdx, h);
417 const auto& solidEnergyLawParams = problem.solidEnergyLawParams(globalSpaceIdx, timeIdx);
418 rockInternalEnergy_ = SolidEnergyLaw::solidInternalEnergy(solidEnergyLawParams, fs);
420 const auto& thermalConductionLawParams = problem.thermalConductionLawParams(globalSpaceIdx, timeIdx);
421 totalThermalConductivity_ = ThermalConductionLaw::thermalConductivity(thermalConductionLawParams, fs);
428 rockFraction_ = problem.rockFraction(globalSpaceIdx, timeIdx);
431 const Evaluation& rockInternalEnergy()
const
432 {
return rockInternalEnergy_; }
434 const Evaluation& totalThermalConductivity()
const
435 {
return totalThermalConductivity_; }
437 Scalar rockFraction()
const
438 {
return rockFraction_; }
441 Implementation& asImp_()
442 {
return *
static_cast<Implementation*
>(
this); }
444 Evaluation rockInternalEnergy_;
445 Evaluation totalThermalConductivity_;
446 Scalar rockFraction_;
537 template<
class Flu
idState>
538 static void updateEnergy(Evaluation& energyFlux,
539 const unsigned& focusDofIndex,
540 const unsigned& inIdx,
541 const unsigned& exIdx,
542 const IntensiveQuantities& inIq,
543 const IntensiveQuantities& exIq,
544 const FluidState& inFs,
545 const FluidState& exFs,
546 const Scalar& inAlpha,
547 const Scalar& outAlpha,
548 const Scalar& faceArea)
551 if (focusDofIndex == inIdx) {
552 deltaT = decay<Scalar>(exFs.temperature(0)) -
555 else if (focusDofIndex == exIdx) {
556 deltaT = exFs.temperature(0) -
557 decay<Scalar>(inFs.temperature(0));
560 deltaT = decay<Scalar>(exFs.temperature(0)) -
561 decay<Scalar>(inFs.temperature(0));
565 if (focusDofIndex == inIdx) {
566 inLambda = inIq.totalThermalConductivity();
569 inLambda = decay<Scalar>(inIq.totalThermalConductivity());
573 if (focusDofIndex == exIdx) {
574 exLambda = exIq.totalThermalConductivity();
577 exLambda = decay<Scalar>(exIq.totalThermalConductivity());
581 const Evaluation& inH = inLambda*inAlpha;
582 const Evaluation& exH = exLambda*outAlpha;
583 if (inH > 0 && exH > 0) {
588 H = 1.0 / (1.0 / inH + 1.0 / exH);
594 energyFlux = deltaT * (-H / faceArea);
597 void updateEnergy(
const ElementContext& elemCtx,
601 const auto& stencil = elemCtx.stencil(timeIdx);
602 const auto& scvf = stencil.interiorFace(scvfIdx);
604 const Scalar faceArea = scvf.area();
605 const unsigned inIdx = scvf.interiorIndex();
606 const unsigned exIdx = scvf.exteriorIndex();
607 const auto& inIq = elemCtx.intensiveQuantities(inIdx, timeIdx);
608 const auto& exIq = elemCtx.intensiveQuantities(exIdx, timeIdx);
609 const auto& inFs = inIq.fluidState();
610 const auto& exFs = exIq.fluidState();
611 const Scalar inAlpha = elemCtx.problem().thermalHalfTransmissibilityIn(elemCtx, scvfIdx, timeIdx);
612 const Scalar outAlpha = elemCtx.problem().thermalHalfTransmissibilityOut(elemCtx, scvfIdx, timeIdx);
613 updateEnergy(energyFlux_,
614 elemCtx.focusDofIndex(),
626 template <
class Context,
class BoundaryFlu
idState>
627 void updateEnergyBoundary(
const Context& ctx,
630 const BoundaryFluidState& boundaryFs)
632 const auto& stencil = ctx.stencil(timeIdx);
633 const auto& scvf = stencil.boundaryFace(scvfIdx);
635 const unsigned inIdx = scvf.interiorIndex();
636 const auto& inIq = ctx.intensiveQuantities(inIdx, timeIdx);
637 const auto& focusDofIdx = ctx.focusDofIndex();
638 const Scalar alpha = ctx.problem().thermalHalfTransmissibilityBoundary(ctx, scvfIdx);
639 updateEnergyBoundary(energyFlux_, inIq, focusDofIdx, inIdx, alpha, boundaryFs);
642 template <
class BoundaryFlu
idState>
643 static void updateEnergyBoundary(Evaluation& energyFlux,
644 const IntensiveQuantities& inIq,
645 unsigned focusDofIndex,
648 const BoundaryFluidState& boundaryFs)
650 const auto& inFs = inIq.fluidState();
652 if (focusDofIndex == inIdx) {
653 deltaT = boundaryFs.temperature(0) -
657 deltaT = decay<Scalar>(boundaryFs.temperature(0)) -
658 decay<Scalar>(inFs.temperature(0));
662 if (focusDofIndex == inIdx) {
663 lambda = inIq.totalThermalConductivity();
666 lambda = decay<Scalar>(inIq.totalThermalConductivity());
674 energyFlux = deltaT * lambda * -alpha;
681 const Evaluation& energyFlux()
const
682 {
return energyFlux_; }
685 Implementation& asImp_()
686 {
return *
static_cast<Implementation*
>(
this); }
688 Evaluation energyFlux_;