71 using Toolbox = MathToolbox<Evaluation>;
73 using TabulatedFunction =
typename BlackOilFoamParams<Scalar>::TabulatedFunction;
75 static constexpr unsigned foamConcentrationIdx = Indices::foamConcentrationIdx;
76 static constexpr unsigned contiFoamEqIdx = Indices::contiFoamEqIdx;
77 static constexpr unsigned gasPhaseIdx = FluidSystem::gasPhaseIdx;
78 static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
80 static constexpr unsigned enableFoam = enableFoamV;
105 if constexpr (enableFoam) {
107 OpmLog::warning(
"VTK output requested, currently unsupported by the foam module.");
113 static bool primaryVarApplies(
unsigned pvIdx)
115 if constexpr (enableFoam) {
116 return pvIdx == foamConcentrationIdx;
123 static std::string primaryVarName([[maybe_unused]]
unsigned pvIdx)
125 assert(primaryVarApplies(pvIdx));
126 return "foam_concentration";
129 static Scalar primaryVarWeight([[maybe_unused]]
unsigned pvIdx)
131 assert(primaryVarApplies(pvIdx));
134 return static_cast<Scalar
>(1.0);
137 static bool eqApplies(
unsigned eqIdx)
139 if constexpr (enableFoam) {
140 return eqIdx == contiFoamEqIdx;
147 static std::string eqName([[maybe_unused]]
unsigned eqIdx)
149 assert(eqApplies(eqIdx));
154 static Scalar eqWeight([[maybe_unused]]
unsigned eqIdx)
156 assert(eqApplies(eqIdx));
159 return static_cast<Scalar
>(1.0);
163 template <
class LhsEval>
164 static void addStorage(Dune::FieldVector<LhsEval, numEq>& storage,
165 const IntensiveQuantities& intQuants)
167 if constexpr (enableFoam) {
168 const auto& fs = intQuants.fluidState();
170 LhsEval surfaceVolume = Toolbox::template decay<LhsEval>(intQuants.porosity());
171 if (params_.transport_phase_ == Phase::WATER) {
172 surfaceVolume *= Toolbox::template decay<LhsEval>(fs.saturation(waterPhaseIdx)) *
173 Toolbox::template decay<LhsEval>(fs.invB(waterPhaseIdx));
174 }
else if (params_.transport_phase_ == Phase::GAS) {
175 surfaceVolume *= Toolbox::template decay<LhsEval>(fs.saturation(gasPhaseIdx)) *
176 Toolbox::template decay<LhsEval>(fs.invB(gasPhaseIdx));
177 }
else if (params_.transport_phase_ == Phase::SOLVENT) {
178 if constexpr (enableSolvent) {
179 surfaceVolume *= Toolbox::template decay<LhsEval>( intQuants.solventSaturation()) *
180 Toolbox::template decay<LhsEval>(intQuants.solventInverseFormationVolumeFactor());
183 throw std::runtime_error(
"Transport phase is GAS/WATER/SOLVENT");
187 surfaceVolume = max(surfaceVolume, 1e-10);
190 const LhsEval freeFoam = surfaceVolume *
191 Toolbox::template decay<LhsEval>(intQuants.foamConcentration());
194 const LhsEval adsorbedFoam =
195 Toolbox::template decay<LhsEval>(1.0 - intQuants.porosity()) *
196 Toolbox::template decay<LhsEval>(intQuants.foamRockDensity()) *
197 Toolbox::template decay<LhsEval>(intQuants.foamAdsorbed());
199 const LhsEval accumulationFoam = freeFoam + adsorbedFoam;
200 storage[contiFoamEqIdx] += accumulationFoam;
204 static void computeFlux([[maybe_unused]] RateVector& flux,
205 [[maybe_unused]]
const ElementContext& elemCtx,
206 [[maybe_unused]]
unsigned scvfIdx,
207 [[maybe_unused]]
unsigned timeIdx)
209 if constexpr (enableFoam) {
210 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
211 const unsigned inIdx = extQuants.interiorIndex();
216 switch (transportPhase()) {
218 const unsigned upIdx = extQuants.upstreamIndex(waterPhaseIdx);
219 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
220 if (upIdx == inIdx) {
221 flux[contiFoamEqIdx] =
222 extQuants.volumeFlux(waterPhaseIdx) *
223 up.fluidState().invB(waterPhaseIdx) *
224 up.foamConcentration();
226 flux[contiFoamEqIdx] =
227 extQuants.volumeFlux(waterPhaseIdx) *
228 decay<Scalar>(up.fluidState().invB(waterPhaseIdx)) *
229 decay<Scalar>(up.foamConcentration());
234 const unsigned upIdx = extQuants.upstreamIndex(gasPhaseIdx);
235 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
236 if (upIdx == inIdx) {
237 flux[contiFoamEqIdx] =
238 extQuants.volumeFlux(gasPhaseIdx) *
239 up.fluidState().invB(gasPhaseIdx) *
240 up.foamConcentration();
242 flux[contiFoamEqIdx] =
243 extQuants.volumeFlux(gasPhaseIdx) *
244 decay<Scalar>(up.fluidState().invB(gasPhaseIdx)) *
245 decay<Scalar>(up.foamConcentration());
250 if constexpr (enableSolvent) {
251 const unsigned upIdx = extQuants.solventUpstreamIndex();
252 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
253 if (upIdx == inIdx) {
254 flux[contiFoamEqIdx] =
255 extQuants.solventVolumeFlux() *
256 up.solventInverseFormationVolumeFactor() *
257 up.foamConcentration();
259 flux[contiFoamEqIdx] =
260 extQuants.solventVolumeFlux() *
261 decay<Scalar>(up.solventInverseFormationVolumeFactor()) *
262 decay<Scalar>(up.foamConcentration());
265 throw std::runtime_error(
"Foam transport phase is SOLVENT but SOLVENT is not activated.");
269 throw std::runtime_error(
"Foam transport phase must be GAS/WATER/SOLVENT.");
282 return static_cast<Scalar
>(0.0);
285 template <
class DofEntity>
286 static void serializeEntity([[maybe_unused]]
const Model& model,
287 [[maybe_unused]] std::ostream& outstream,
288 [[maybe_unused]]
const DofEntity& dof)
290 if constexpr (enableFoam) {
291 const unsigned dofIdx = model.dofMapper().index(dof);
292 const PrimaryVariables& priVars = model.solution(0)[dofIdx];
293 outstream << priVars[foamConcentrationIdx];
297 template <
class DofEntity>
298 static void deserializeEntity([[maybe_unused]] Model& model,
299 [[maybe_unused]] std::istream& instream,
300 [[maybe_unused]]
const DofEntity& dof)
302 if constexpr (enableFoam) {
303 const unsigned dofIdx = model.dofMapper().index(dof);
304 PrimaryVariables& priVars0 = model.solution(0)[dofIdx];
305 PrimaryVariables& priVars1 = model.solution(1)[dofIdx];
307 instream >> priVars0[foamConcentrationIdx];
310 priVars1[foamConcentrationIdx] = priVars0[foamConcentrationIdx];
314 static const Scalar foamRockDensity(
const ElementContext& elemCtx,
318 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
319 return params_.foamRockDensity_[satnumRegionIdx];
322 static bool foamAllowDesorption(
const ElementContext& elemCtx,
326 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
327 return params_.foamAllowDesorption_[satnumRegionIdx];
330 static const TabulatedFunction& adsorbedFoamTable(
const ElementContext& elemCtx,
334 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
335 return params_.adsorbedFoamTable_[satnumRegionIdx];
338 static const TabulatedFunction& gasMobilityMultiplierTable(
const ElementContext& elemCtx,
342 const unsigned pvtnumRegionIdx = elemCtx.problem().pvtRegionIndex(elemCtx, scvIdx, timeIdx);
343 return params_.gasMobilityMultiplierTable_[pvtnumRegionIdx];
346 static const typename BlackOilFoamParams<Scalar>::FoamCoefficients&
347 foamCoefficients(
const ElementContext& elemCtx,
348 const unsigned scvIdx,
349 const unsigned timeIdx)
351 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
352 return params_.foamCoefficients_[satnumRegionIdx];
355 static Phase transportPhase()
356 {
return params_.transport_phase_; }
359 static BlackOilFoamParams<Scalar> params_;