73 using Toolbox = MathToolbox<Evaluation>;
75 using TabulatedFunction =
typename BlackOilFoamParams<Scalar>::TabulatedFunction;
77 static constexpr unsigned foamConcentrationIdx = Indices::foamConcentrationIdx;
78 static constexpr unsigned contiFoamEqIdx = Indices::contiFoamEqIdx;
79 static constexpr unsigned gasPhaseIdx = FluidSystem::gasPhaseIdx;
80 static constexpr unsigned waterPhaseIdx = FluidSystem::waterPhaseIdx;
82 static constexpr unsigned enableFoam = enableFoamV;
107 if constexpr (enableFoam) {
109 OpmLog::warning(
"VTK output requested, currently unsupported by the foam module.");
115 static bool primaryVarApplies(
unsigned pvIdx)
117 if constexpr (enableFoam) {
118 return pvIdx == foamConcentrationIdx;
125 static std::string primaryVarName([[maybe_unused]]
unsigned pvIdx)
127 assert(primaryVarApplies(pvIdx));
128 return "foam_concentration";
131 static Scalar primaryVarWeight([[maybe_unused]]
unsigned pvIdx)
133 assert(primaryVarApplies(pvIdx));
136 return static_cast<Scalar
>(1.0);
139 static bool eqApplies(
unsigned eqIdx)
141 if constexpr (enableFoam) {
142 return eqIdx == contiFoamEqIdx;
149 static std::string eqName([[maybe_unused]]
unsigned eqIdx)
151 assert(eqApplies(eqIdx));
156 static Scalar eqWeight([[maybe_unused]]
unsigned eqIdx)
158 assert(eqApplies(eqIdx));
161 return static_cast<Scalar
>(1.0);
165 template <
class StorageType>
166 OPM_HOST_DEVICE
static void addStorage(StorageType& storage,
167 const IntensiveQuantities& intQuants)
169 using LhsEval =
typename StorageType::value_type;
171 if constexpr (enableFoam) {
172 const auto& fs = intQuants.fluidState();
174 LhsEval surfaceVolume = Toolbox::template decay<LhsEval>(intQuants.porosity());
175 if (params_.transport_phase_ == Phase::WATER) {
176 surfaceVolume *= Toolbox::template decay<LhsEval>(fs.saturation(waterPhaseIdx)) *
177 Toolbox::template decay<LhsEval>(fs.invB(waterPhaseIdx));
178 }
else if (params_.transport_phase_ == Phase::GAS) {
179 surfaceVolume *= Toolbox::template decay<LhsEval>(fs.saturation(gasPhaseIdx)) *
180 Toolbox::template decay<LhsEval>(fs.invB(gasPhaseIdx));
181 }
else if (params_.transport_phase_ == Phase::SOLVENT) {
182 if constexpr (enableSolvent) {
183 surfaceVolume *= Toolbox::template decay<LhsEval>( intQuants.solventSaturation()) *
184 Toolbox::template decay<LhsEval>(intQuants.solventInverseFormationVolumeFactor());
187 throw std::runtime_error(
"Transport phase is GAS/WATER/SOLVENT");
191 surfaceVolume = max(surfaceVolume, 1e-10);
194 const LhsEval freeFoam = surfaceVolume *
195 Toolbox::template decay<LhsEval>(intQuants.foamConcentration());
198 const LhsEval adsorbedFoam =
199 Toolbox::template decay<LhsEval>(1.0 - intQuants.porosity()) *
200 Toolbox::template decay<LhsEval>(intQuants.foamRockDensity()) *
201 Toolbox::template decay<LhsEval>(intQuants.foamAdsorbed());
203 const LhsEval accumulationFoam = freeFoam + adsorbedFoam;
204 storage[contiFoamEqIdx] += accumulationFoam;
208 static void computeFlux([[maybe_unused]] RateVector& flux,
209 [[maybe_unused]]
const ElementContext& elemCtx,
210 [[maybe_unused]]
unsigned scvfIdx,
211 [[maybe_unused]]
unsigned timeIdx)
213 if constexpr (enableFoam) {
214 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
215 const unsigned inIdx = extQuants.interiorIndex();
220 switch (transportPhase()) {
222 const unsigned upIdx = extQuants.upstreamIndex(waterPhaseIdx);
223 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
224 if (upIdx == inIdx) {
225 flux[contiFoamEqIdx] =
226 extQuants.volumeFlux(waterPhaseIdx) *
227 up.fluidState().invB(waterPhaseIdx) *
228 up.foamConcentration();
230 flux[contiFoamEqIdx] =
231 extQuants.volumeFlux(waterPhaseIdx) *
232 decay<Scalar>(up.fluidState().invB(waterPhaseIdx)) *
233 decay<Scalar>(up.foamConcentration());
238 const unsigned upIdx = extQuants.upstreamIndex(gasPhaseIdx);
239 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
240 if (upIdx == inIdx) {
241 flux[contiFoamEqIdx] =
242 extQuants.volumeFlux(gasPhaseIdx) *
243 up.fluidState().invB(gasPhaseIdx) *
244 up.foamConcentration();
246 flux[contiFoamEqIdx] =
247 extQuants.volumeFlux(gasPhaseIdx) *
248 decay<Scalar>(up.fluidState().invB(gasPhaseIdx)) *
249 decay<Scalar>(up.foamConcentration());
254 if constexpr (enableSolvent) {
255 const unsigned upIdx = extQuants.solventUpstreamIndex();
256 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
257 if (upIdx == inIdx) {
258 flux[contiFoamEqIdx] =
259 extQuants.solventVolumeFlux() *
260 up.solventInverseFormationVolumeFactor() *
261 up.foamConcentration();
263 flux[contiFoamEqIdx] =
264 extQuants.solventVolumeFlux() *
265 decay<Scalar>(up.solventInverseFormationVolumeFactor()) *
266 decay<Scalar>(up.foamConcentration());
269 throw std::runtime_error(
"Foam transport phase is SOLVENT but SOLVENT is not activated.");
273 throw std::runtime_error(
"Foam transport phase must be GAS/WATER/SOLVENT.");
286 return static_cast<Scalar
>(0.0);
289 template <
class DofEntity>
290 static void serializeEntity([[maybe_unused]]
const Model& model,
291 [[maybe_unused]] std::ostream& outstream,
292 [[maybe_unused]]
const DofEntity& dof)
294 if constexpr (enableFoam) {
295 const unsigned dofIdx = model.dofMapper().index(dof);
296 const PrimaryVariables& priVars = model.solution(0)[dofIdx];
297 outstream << priVars[foamConcentrationIdx];
301 template <
class DofEntity>
302 static void deserializeEntity([[maybe_unused]] Model& model,
303 [[maybe_unused]] std::istream& instream,
304 [[maybe_unused]]
const DofEntity& dof)
306 if constexpr (enableFoam) {
307 const unsigned dofIdx = model.dofMapper().index(dof);
308 PrimaryVariables& priVars0 = model.solution(0)[dofIdx];
309 PrimaryVariables& priVars1 = model.solution(1)[dofIdx];
311 instream >> priVars0[foamConcentrationIdx];
314 priVars1[foamConcentrationIdx] = priVars0[foamConcentrationIdx];
318 static const Scalar foamRockDensity(
const ElementContext& elemCtx,
322 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
323 return params_.foamRockDensity_[satnumRegionIdx];
326 static bool foamAllowDesorption(
const ElementContext& elemCtx,
330 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
331 return params_.foamAllowDesorption_[satnumRegionIdx];
334 static const TabulatedFunction& adsorbedFoamTable(
const ElementContext& elemCtx,
338 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
339 return params_.adsorbedFoamTable_[satnumRegionIdx];
342 static const TabulatedFunction& gasMobilityMultiplierTable(
const ElementContext& elemCtx,
346 const unsigned pvtnumRegionIdx = elemCtx.problem().pvtRegionIndex(elemCtx, scvIdx, timeIdx);
347 return params_.gasMobilityMultiplierTable_[pvtnumRegionIdx];
350 static const typename BlackOilFoamParams<Scalar>::FoamCoefficients&
351 foamCoefficients(
const ElementContext& elemCtx,
352 const unsigned scvIdx,
353 const unsigned timeIdx)
355 const unsigned satnumRegionIdx = elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
356 return params_.foamCoefficients_[satnumRegionIdx];
359 static Phase transportPhase()
360 {
return params_.transport_phase_; }
363 static BlackOilFoamParams<Scalar> params_;