24#ifndef DUMUX_FVPRESSURE2P2C_HH
25#define DUMUX_FVPRESSURE2P2C_HH
28#include <dune/istl/bvector.hh>
29#include <dune/istl/operators.hh>
30#include <dune/istl/solvers.hh>
31#include <dune/istl/preconditioners.hh>
32#include <dune/common/float_cmp.hh>
82 using MaterialLaw =
typename SpatialParams::MaterialLaw;
93 dim = GridView::dimension, dimWorld = GridView::dimensionworld
97 pw = Indices::pressureW,
98 pn = Indices::pressureN,
99 pGlobal = Indices::pressureGlobal
103 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
104 wCompIdx = Indices::wPhaseIdx, nCompIdx = Indices::nPhaseIdx,
105 contiWEqIdx = Indices::contiWEqIdx, contiNEqIdx = Indices::contiNEqIdx
122 using Element =
typename GridView::Traits::template Codim<0>::Entity;
123 using Intersection =
typename GridView::Intersection;
126 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
127 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
128 using PhaseVector = Dune::FieldVector<Scalar, getPropValue<TypeTag, Properties::NumPhases>()>;
149 void getSource(
EntryType& sourceEntry,
const Element& elementI,
const CellData& cellDataI,
const bool first);
151 void getStorage(
EntryType& storageEntry,
const Element& elementI,
const CellData& cellDataI,
const bool first);
153 void getFlux(
EntryType& entries,
const Intersection& intersection,
const CellData& cellDataI,
const bool first);
176 Dune::dinfo <<
" Warning: Regulating Boundary Permeability requires correct subface indices on reference elements!"
190 static constexpr int pressureType = getPropValue<TypeTag, Properties::PressureFormulation>();
193 Implementation &asImp_()
194 {
return *
static_cast<Implementation *
>(
this);}
197 const Implementation &asImp_()
const
198 {
return *
static_cast<const Implementation *
>(
this);}
212template<
class TypeTag>
214 const Element& elementI,
215 const CellData& cellDataI,
220 Scalar volume = elementI.geometry().volume();
223 PrimaryVariables source(NAN);
224 problem().source(source, elementI);
228 source[contiWEqIdx] /= cellDataI.density(wPhaseIdx);
229 source[contiNEqIdx] /= cellDataI.density(nPhaseIdx);
234 const GlobalPosition& globalPos = elementI.geometry().center();
236 if (!cellDataI.hasVolumeDerivatives())
237 asImp_().volumeDerivatives(globalPos, elementI);
239 source[contiWEqIdx] *= cellDataI.dv(wCompIdx);
240 source[contiNEqIdx] *= cellDataI.dv(nCompIdx);
242 sourceEntry[rhs] = volume * (source[contiWEqIdx] + source[contiNEqIdx]);
262template<
class TypeTag>
264 const Element& elementI,
265 const CellData& cellDataI,
270 int eIdxGlobalI = problem().variables().index(elementI);
271 Scalar volume = elementI.geometry().volume();
274 Scalar timestep_ = problem().timeManager().timeStepSize();
277 if (!first && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(timestep_, 0.0, 1.0e-30))
279 Scalar compress_term = cellDataI.dv_dp() / timestep_;
281 storageEntry[matrix] -= compress_term*volume;
284 storageEntry[rhs] -= cellDataI.pressure(pressureType) * compress_term * volume;
288 if (isnan(compress_term) || isinf(compress_term))
289 DUNE_THROW(Dune::MathError,
"Compressibility term leads to NAN matrix entry at index " << eIdxGlobalI);
291 if(!getPropValue<TypeTag, Properties::EnableCompressibility>())
292 DUNE_THROW(Dune::NotImplemented,
"Compressibility is switched off???");
297 if( problem().timeManager().episodeWillBeFinished()
298 || problem().timeManager().willBeFinished())
300 problem().variables().cellData(eIdxGlobalI).errorCorrection() = 0.;
306 problem().variables().cellData(eIdxGlobalI).volumeError() /= timestep_;
307 Scalar erri = fabs(cellDataI.volumeError());
308 Scalar x_lo = ErrorTermLowerBound_;
309 Scalar x_mi = ErrorTermUpperBound_;
310 Scalar fac = ErrorTermFactor_;
312 Scalar hifac = 1.-x_mi;
314 if ((erri*timestep_ > 5e-5) && (erri > x_lo * this->maxError_))
316 if (erri <= x_mi * this->maxError_)
318 problem().variables().cellData(eIdxGlobalI).errorCorrection() =
319 fac* (1-x_mi*(lofac-1)/(x_lo-x_mi) + (lofac-1)/(x_lo-x_mi)*erri/this->maxError_)
320 * cellDataI.volumeError() * volume;
323 problem().variables().cellData(eIdxGlobalI).errorCorrection() =
324 fac * (1 + x_mi - hifac*x_mi/(1-x_mi) + (hifac/(1-x_mi)-1)*erri/this->maxError_)
325 * cellDataI.volumeError() * volume;
328 problem().variables().cellData(eIdxGlobalI).errorCorrection() = 0.;
354template<
class TypeTag>
356 const Intersection& intersection,
357 const CellData& cellDataI,
361 auto elementI = intersection.inside();
362 int eIdxGlobalI = problem().variables().index(elementI);
365 const GlobalPosition& globalPos = elementI.geometry().center();
368 Scalar volume = elementI.geometry().volume();
369 Scalar perimeter = cellDataI.perimeter();
373 const GlobalPosition& gravity_ = problem().gravity();
376 DimMatrix permeabilityI(problem().spatialParams().intrinsicPermeability(elementI));
379 Scalar fractionalWI=0, fractionalNWI=0;
382 fractionalWI = cellDataI.mobility(wPhaseIdx)
383 / (cellDataI.mobility(wPhaseIdx)+ cellDataI.mobility(nPhaseIdx));
384 fractionalNWI = cellDataI.mobility(nPhaseIdx)
385 / (cellDataI.mobility(wPhaseIdx)+ cellDataI.mobility(nPhaseIdx));
389 const GlobalPosition& unitOuterNormal = intersection.centerUnitOuterNormal();
392 Scalar faceArea = intersection.geometry().volume();
395 auto neighbor = intersection.outside();
396 int eIdxGlobalJ = problem().variables().index(neighbor);
397 CellData& cellDataJ = problem().variables().cellData(eIdxGlobalJ);
400 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
403 GlobalPosition distVec = globalPosNeighbor - globalPos;
406 Scalar dist = distVec.two_norm();
408 GlobalPosition unitDistVec(distVec);
411 DimMatrix permeabilityJ
412 = problem().spatialParams().intrinsicPermeability(neighbor);
415 DimMatrix meanPermeability(0);
422 Scalar rhoMeanW = 0.5 * (cellDataI.density(wPhaseIdx) + cellDataJ.density(wPhaseIdx));
423 Scalar rhoMeanNW = 0.5 * (cellDataI.density(nPhaseIdx) + cellDataJ.density(nPhaseIdx));
426 Scalar potentialW = 0;
427 Scalar potentialNW = 0;
432 Scalar fractionalWJ = cellDataJ.mobility(wPhaseIdx)
433 / (cellDataJ.mobility(wPhaseIdx)+ cellDataJ.mobility(nPhaseIdx));
434 Scalar fractionalNWJ = cellDataJ.mobility(nPhaseIdx)
435 / (cellDataJ.mobility(wPhaseIdx)+ cellDataJ.mobility(nPhaseIdx));
438 Scalar lambda = (cellDataI.mobility(wPhaseIdx) + cellDataJ.mobility(wPhaseIdx)) * 0.5
439 + (cellDataI.mobility(nPhaseIdx) + cellDataJ.mobility(nPhaseIdx)) * 0.5;
441 entries[0] = fabs(lambda*faceArea*fabs(
permeability*unitOuterNormal)/(dist));
443 Scalar factor = (fractionalWI + fractionalWJ) * (rhoMeanW) * 0.5
444 + (fractionalNWI + fractionalNWJ) * (rhoMeanNW) * 0.5;
445 entries[1] = factor * lambda * faceArea * fabs(unitOuterNormal*
permeability)
446 * (gravity_ * unitDistVec);
451 if (!cellDataJ.hasVolumeDerivatives())
452 asImp_().volumeDerivatives(globalPosNeighbor, neighbor);
454 Scalar dv_dC1 = (cellDataJ.dv(wPhaseIdx)
455 + cellDataI.dv(wPhaseIdx)) / 2;
456 Scalar dv_dC2 = (cellDataJ.dv(nPhaseIdx)
457 + cellDataI.dv(nPhaseIdx)) / 2;
459 Scalar graddv_dC1 = (cellDataJ.dv(wPhaseIdx)
460 - cellDataI.dv(wPhaseIdx)) / dist;
461 Scalar graddv_dC2 = (cellDataJ.dv(nPhaseIdx)
462 - cellDataI.dv(nPhaseIdx)) / dist;
473 Scalar densityW = rhoMeanW;
474 Scalar densityNW = rhoMeanNW;
476 potentialW = (cellDataI.pressure(wPhaseIdx) - cellDataJ.pressure(wPhaseIdx))/dist;
477 potentialNW = (cellDataI.pressure(nPhaseIdx) - cellDataJ.pressure(nPhaseIdx))/dist;
479 potentialW += densityW * (unitDistVec * gravity_);
480 potentialNW += densityNW * (unitDistVec * gravity_);
483 Scalar lambdaW(0.), lambdaN(0.);
484 Scalar dV_w(0.), dV_n(0.);
485 Scalar gV_w(0.), gV_n(0.);
489 const CellData* upwindWCellData(0);
490 const CellData* upwindNCellData(0);
492 upwindWCellData = &cellDataI;
493 else if (potentialW < 0.)
494 upwindWCellData = &cellDataJ;
497 if(cellDataI.isUpwindCell(intersection.indexInInside(), contiWEqIdx))
498 upwindWCellData = &cellDataI;
499 else if(cellDataJ.isUpwindCell(intersection.indexInOutside(), contiWEqIdx))
500 upwindWCellData = &cellDataJ;
505 if (potentialNW > 0.)
506 upwindNCellData = &cellDataI;
507 else if (potentialNW < 0.)
508 upwindNCellData = &cellDataJ;
511 if(cellDataI.isUpwindCell(intersection.indexInInside(), contiNEqIdx))
512 upwindNCellData = &cellDataI;
513 else if(cellDataJ.isUpwindCell(intersection.indexInOutside(), contiNEqIdx))
514 upwindNCellData = &cellDataJ;
520 if(!upwindWCellData or (cellDataI.wasRefined() && cellDataJ.wasRefined() && elementI.father() == neighbor.father()))
522 if (cellDataI.wasRefined() && cellDataJ.wasRefined())
524 problem().variables().cellData(eIdxGlobalI).setUpwindCell(intersection.indexInInside(), contiWEqIdx,
false);
525 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiWEqIdx,
false);
528 Scalar averagedMassFraction[2];
529 averagedMassFraction[wCompIdx]
530 =
harmonicMean(cellDataI.massFraction(wPhaseIdx, wCompIdx), cellDataJ.massFraction(wPhaseIdx, wCompIdx));
531 averagedMassFraction[nCompIdx]
532 =
harmonicMean(cellDataI.massFraction(wPhaseIdx, nCompIdx), cellDataJ.massFraction(wPhaseIdx, nCompIdx));
533 Scalar averageDensity =
harmonicMean(cellDataI.density(wPhaseIdx), cellDataJ.density(wPhaseIdx));
536 dV_w = dv_dC1 * averagedMassFraction[wCompIdx] + dv_dC2 * averagedMassFraction[nCompIdx];
537 dV_w *= averageDensity;
538 gV_w = graddv_dC1 * averagedMassFraction[wCompIdx] + graddv_dC2 * averagedMassFraction[nCompIdx];
539 gV_w *= averageDensity;
540 lambdaW =
harmonicMean(cellDataI.mobility(wPhaseIdx), cellDataJ.mobility(wPhaseIdx));
544 dV_w = (dv_dC1 * upwindWCellData->massFraction(wPhaseIdx, wCompIdx)
545 + dv_dC2 * upwindWCellData->massFraction(wPhaseIdx, nCompIdx));
546 lambdaW = upwindWCellData->mobility(wPhaseIdx);
547 gV_w = (graddv_dC1 * upwindWCellData->massFraction(wPhaseIdx, wCompIdx)
548 + graddv_dC2 * upwindWCellData->massFraction(wPhaseIdx, nCompIdx));
549 dV_w *= upwindWCellData->density(wPhaseIdx);
550 gV_w *= upwindWCellData->density(wPhaseIdx);
553 if(!upwindNCellData or (cellDataI.wasRefined() && cellDataJ.wasRefined()))
555 if (cellDataI.wasRefined() && cellDataJ.wasRefined())
557 problem().variables().cellData(eIdxGlobalI).setUpwindCell(intersection.indexInInside(), contiNEqIdx,
false);
558 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiNEqIdx,
false);
560 Scalar averagedMassFraction[2];
561 averagedMassFraction[wCompIdx]
562 =
harmonicMean(cellDataI.massFraction(nPhaseIdx, wCompIdx), cellDataJ.massFraction(nPhaseIdx, wCompIdx));
563 averagedMassFraction[nCompIdx]
564 =
harmonicMean(cellDataI.massFraction(nPhaseIdx, nCompIdx), cellDataJ.massFraction(nPhaseIdx, nCompIdx));
565 Scalar averageDensity =
harmonicMean(cellDataI.density(nPhaseIdx), cellDataJ.density(nPhaseIdx));
568 dV_n = dv_dC1 * averagedMassFraction[wCompIdx] + dv_dC2 * averagedMassFraction[nCompIdx];
569 dV_n *= averageDensity;
570 gV_n = graddv_dC1 * averagedMassFraction[wCompIdx] + graddv_dC2 * averagedMassFraction[nCompIdx];
571 gV_n *= averageDensity;
572 lambdaN =
harmonicMean(cellDataI.mobility(nPhaseIdx), cellDataJ.mobility(nPhaseIdx));
576 dV_n = (dv_dC1 * upwindNCellData->massFraction(nPhaseIdx, wCompIdx)
577 + dv_dC2 * upwindNCellData->massFraction(nPhaseIdx, nCompIdx));
578 lambdaN = upwindNCellData->mobility(nPhaseIdx);
579 gV_n = (graddv_dC1 * upwindNCellData->massFraction(nPhaseIdx, wCompIdx)
580 + graddv_dC2 * upwindNCellData->massFraction(nPhaseIdx, nCompIdx));
581 dV_n *= upwindNCellData->density(nPhaseIdx);
582 gV_n *= upwindNCellData->density(nPhaseIdx);
586 entries[matrix] = faceArea * (lambdaW * dV_w + lambdaN * dV_n)
588 if(enableVolumeIntegral)
589 entries[matrix] -= volume * faceArea / perimeter * (lambdaW * gV_w + lambdaN * gV_n)
593 entries[rhs] = faceArea * (densityW * lambdaW * dV_w + densityNW * lambdaN * dV_n);
595 if(enableVolumeIntegral)
596 entries[rhs] -= volume * faceArea / perimeter * (densityW * lambdaW * gV_w + densityNW * lambdaN * gV_n)
598 entries[rhs] *= (gravity_ * unitDistVec);
601 Scalar pCGradient = (cellDataI.capillaryPressure() - cellDataJ.capillaryPressure()) / dist;
604 switch (pressureType)
609 entries[rhs] += lambdaN * dV_n * fabs(
permeability * unitOuterNormal) * pCGradient * faceArea;
610 if(enableVolumeIntegral)
611 entries[rhs]-= lambdaN * gV_n * (
permeability * unitDistVec) * pCGradient * volume * faceArea / perimeter;
617 entries[rhs] -= lambdaW * dV_w * fabs(
permeability * unitOuterNormal) * pCGradient * faceArea;
618 if(enableVolumeIntegral)
619 entries[rhs]+= lambdaW * gV_w * (
permeability * unitDistVec) * pCGradient * volume * faceArea / perimeter;
645template<
class TypeTag>
647 const Intersection& intersection,
const CellData& cellDataI,
const bool first)
651 auto elementI = intersection.inside();
652 const GlobalPosition& globalPos = elementI.geometry().center();
655 const GlobalPosition& unitOuterNormal = intersection.centerUnitOuterNormal();
657 Scalar faceArea = intersection.geometry().volume();
660 Scalar dv_dC1 = cellDataI.dv(wCompIdx);
661 Scalar dv_dC2 = cellDataI.dv(nCompIdx);
664 const GlobalPosition& globalPosFace = intersection.geometry().center();
667 GlobalPosition distVec(globalPosFace - globalPos);
668 Scalar dist = distVec.two_norm();
669 GlobalPosition unitDistVec(distVec);
673 BoundaryTypes bcType;
674 problem().boundaryTypes(bcType, intersection);
677 PhaseVector pressBC(0.);
681 if (bcType.isDirichlet(Indices::pressureEqIdx))
684 DimMatrix permeabilityI(problem().spatialParams().intrinsicPermeability(elementI));
686 if(regulateBoundaryPermeability)
688 int axis = intersection.indexInInside() / 2;
689 if(permeabilityI[axis][axis] < minimalBoundaryPermeability)
690 permeabilityI[axis][axis] = minimalBoundaryPermeability;
692 const GlobalPosition& gravity_ = problem().gravity();
699 FluidState BCfluidState;
702 PrimaryVariables primaryVariablesOnBoundary(NAN);
703 problem().dirichlet(primaryVariablesOnBoundary, intersection);
708 Scalar fractionalWI=0, fractionalNWI=0;
709 fractionalWI = cellDataI.mobility(wPhaseIdx)
710 / (cellDataI.mobility(wPhaseIdx)+ cellDataI.mobility(nPhaseIdx));
711 fractionalNWI = cellDataI.mobility(nPhaseIdx)
712 / (cellDataI.mobility(wPhaseIdx)+ cellDataI.mobility(nPhaseIdx));
714 Scalar lambda = cellDataI.mobility(wPhaseIdx)+cellDataI.mobility(nPhaseIdx);
715 entries[matrix] += lambda * faceArea * fabs(
permeability * unitOuterNormal) / (dist);
716 Scalar pressBoundary = primaryVariablesOnBoundary[Indices::pressureEqIdx];
717 entries[rhs] += lambda * faceArea * pressBoundary * fabs(
permeability * unitOuterNormal) / (dist);
718 Scalar rightentry = (fractionalWI * cellDataI.density(wPhaseIdx)
719 + fractionalNWI * cellDataI.density(nPhaseIdx))
720 * lambda * faceArea * fabs(unitOuterNormal *
permeability)
721 * ( unitDistVec * gravity_);
722 entries[rhs] -= rightentry;
727 problem().transportModel().evalBoundary(globalPosFace,
731 pcBound = pressBC[nPhaseIdx] - pressBC[wPhaseIdx];
734 Scalar lambdaWBound = 0.;
735 Scalar lambdaNWBound = 0.;
737 Scalar densityWBound =
739 Scalar densityNWBound =
741 Scalar viscosityWBound =
743 Scalar viscosityNWBound =
747 if(getPropValue<TypeTag, Properties::BoundaryMobility>() == Indices::satDependent)
749 lambdaWBound = BCfluidState.saturation(wPhaseIdx)
751 lambdaNWBound = BCfluidState.saturation(nPhaseIdx)
754 else if(getPropValue<TypeTag, Properties::BoundaryMobility>() == Indices::permDependent)
757 = MaterialLaw::krw(problem().spatialParams().materialLawParams(elementI),
758 BCfluidState.saturation(wPhaseIdx)) / viscosityWBound;
760 = MaterialLaw::krn(problem().spatialParams().materialLawParams(elementI),
761 BCfluidState.saturation(wPhaseIdx)) / viscosityNWBound;
764 Scalar rhoMeanW = 0.5 * (cellDataI.density(wPhaseIdx) + densityWBound);
765 Scalar rhoMeanNW = 0.5 * (cellDataI.density(nPhaseIdx) + densityNWBound);
767 Scalar potentialW = 0;
768 Scalar potentialNW = 0;
780 Scalar densityW=rhoMeanW;
781 Scalar densityNW=rhoMeanNW;
784 potentialW = (cellDataI.pressure(wPhaseIdx) - pressBC[wPhaseIdx])/dist;
785 potentialNW = (cellDataI.pressure(nPhaseIdx) - pressBC[nPhaseIdx])/dist;
787 potentialW += densityW * (unitDistVec * gravity_);
788 potentialNW += densityNW * (unitDistVec * gravity_);
792 Scalar lambdaW, lambdaNW;
793 Scalar densityW(0.), densityNW(0.);
797 if (potentialW >= 0.)
799 densityW = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialW, 0.0, 1.0e-30)) ? rhoMeanW : cellDataI.density(wPhaseIdx);
800 dV_w = (dv_dC1 * cellDataI.massFraction(wPhaseIdx, wCompIdx)
801 + dv_dC2 * cellDataI.massFraction(wPhaseIdx, nCompIdx));
803 lambdaW = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialW, 0.0, 1.0e-30)) ? 0.5 * (cellDataI.mobility(wPhaseIdx) + lambdaWBound)
804 : cellDataI.mobility(wPhaseIdx);
808 densityW = densityWBound;
809 dV_w = (dv_dC1 * BCfluidState.massFraction(wPhaseIdx, wCompIdx)
810 + dv_dC2 * BCfluidState.massFraction(wPhaseIdx, nCompIdx));
812 lambdaW = lambdaWBound;
814 if (potentialNW >= 0.)
816 densityNW = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialNW, 0.0, 1.0e-30)) ? rhoMeanNW : cellDataI.density(nPhaseIdx);
817 dV_n = (dv_dC1 * cellDataI.massFraction(nPhaseIdx, wCompIdx)
818 + dv_dC2 * cellDataI.massFraction(nPhaseIdx, nCompIdx));
820 lambdaNW = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialNW, 0.0, 1.0e-30)) ? 0.5 * (cellDataI.mobility(nPhaseIdx) + lambdaNWBound)
821 : cellDataI.mobility(nPhaseIdx);
825 densityNW = densityNWBound;
826 dV_n = (dv_dC1 * BCfluidState.massFraction(nPhaseIdx, wCompIdx)
827 + dv_dC2 * BCfluidState.massFraction(nPhaseIdx, nCompIdx));
829 lambdaNW = lambdaNWBound;
833 Scalar entry = (lambdaW * dV_w + lambdaNW * dV_n)
834 * (fabs(unitOuterNormal *
permeability) / dist) * faceArea;
837 Scalar rightEntry = (lambdaW * densityW * dV_w + lambdaNW * densityNW * dV_n)
838 * fabs(unitOuterNormal *
permeability) * (gravity_ * unitDistVec) * faceArea ;
842 Scalar pCGradient = (cellDataI.capillaryPressure() - pcBound) / dist;
843 switch (pressureType)
848 rightEntry += lambdaNW * dV_n * pCGradient * fabs(unitOuterNormal *
permeability) * faceArea;
854 rightEntry -= lambdaW * dV_w * pCGradient * fabs(unitOuterNormal *
permeability) * faceArea;
861 entries[matrix] += entry;
862 entries[rhs] += entry * primaryVariablesOnBoundary[Indices::pressureEqIdx];
863 entries[rhs] -= rightEntry;
870 else if(bcType.isNeumann(Indices::pressureEqIdx))
872 PrimaryVariables J(NAN);
873 problem().neumann(J, intersection);
876 J[contiWEqIdx] /= cellDataI.density(wPhaseIdx);
877 J[contiNEqIdx] /= cellDataI.density(nPhaseIdx);
881 J[contiWEqIdx] *= dv_dC1;
882 J[contiNEqIdx] *= dv_dC2;
885 entries[rhs] -= (J[contiWEqIdx] + J[contiNEqIdx]) * faceArea;
888 DUNE_THROW(Dune::NotImplemented,
"Boundary Condition neither Dirichlet nor Neumann!");
903template<
class TypeTag>
907 GlobalPosition globalPos = element.geometry().center();
910 int eIdxGlobal = problem().variables().index(element);
911 CellData& cellData = problem().variables().cellData(eIdxGlobal);
914 FluidState& fluidState = cellData.manipulateFluidState();
916 Scalar temperature_ = problem().temperatureAtPos(globalPos);
923 Scalar Z0 = cellData.massConcentration(wCompIdx)
924 / (cellData.massConcentration(wCompIdx)
925 + cellData.massConcentration(nCompIdx));
928 if(Z0 < 0. || Z0 > 1.)
930 Dune::dgrave <<
"Feed mass fraction unphysical: Z0 = " << Z0
931 <<
" at global Idx " << eIdxGlobal
932 <<
" , because totalConcentration(wCompIdx) = "
933 << cellData.totalConcentration(wCompIdx)
934 <<
" and totalConcentration(nCompIdx) = "
935 << cellData.totalConcentration(nCompIdx)<< std::endl;
939 cellData.setTotalConcentration(wCompIdx, 0.);
940 problem().transportModel().totalConcentration(wCompIdx, eIdxGlobal) = 0.;
941 Dune::dgrave <<
"Regularize totalConcentration(wCompIdx) = "
942 << cellData.totalConcentration(wCompIdx)<< std::endl;
947 cellData.setTotalConcentration(nCompIdx, 0.);
948 problem().transportModel().totalConcentration(nCompIdx,eIdxGlobal) = 0.;
949 Dune::dgrave <<
"Regularize totalConcentration(eIdxGlobal, nCompIdx) = "
950 << cellData.totalConcentration(nCompIdx)<< std::endl;
956 if(getPropValue<TypeTag, Properties::EnableCapillarity>())
958 unsigned int maxiter = 6;
959 Scalar pc = cellData.capillaryPressure();
961 for (
unsigned int iter = 0; iter < maxiter; iter++)
963 switch (pressureType)
967 pressure[wPhaseIdx] = asImp_().pressure(eIdxGlobal);
968 pressure[nPhaseIdx] = asImp_().pressure(eIdxGlobal) + pc;
973 pressure[wPhaseIdx] = asImp_().pressure(eIdxGlobal) - pc;
974 pressure[nPhaseIdx] = asImp_().pressure(eIdxGlobal);
981 problem().spatialParams().
porosity(element), temperature_);
985 pc = MaterialLaw::pc(problem().spatialParams().materialLawParams(element),
986 fluidState.saturation(wPhaseIdx));
988 if (fabs(oldPc-pc)<10 && iter != 0)
991 if (iter++ == maxiter)
992 Dune::dinfo << iter <<
"times iteration of pc was applied at Idx " << eIdxGlobal
993 <<
", pc delta still " << fabs(oldPc-pc) << std::endl;
998 pressure[wPhaseIdx] =
pressure[nPhaseIdx] = asImp_().pressure()[eIdxGlobal];
1000 problem().spatialParams().
porosity(element), temperature_);
1004 cellData.setMobility(wPhaseIdx, MaterialLaw::krw(problem().spatialParams().materialLawParams(element),
1005 fluidState.saturation(wPhaseIdx))
1006 / cellData.viscosity(wPhaseIdx));
1007 cellData.setMobility(nPhaseIdx, MaterialLaw::krn(problem().spatialParams().materialLawParams(element),
1008 fluidState.saturation(wPhaseIdx))
1009 / cellData.viscosity(nPhaseIdx));
1012 Scalar sumConc = (cellData.totalConcentration(wCompIdx)
1013 + cellData.totalConcentration(nCompIdx));
1014 Scalar massw = sumConc * fluidState.phaseMassFraction(wPhaseIdx);
1015 Scalar massn = sumConc * fluidState.phaseMassFraction(nPhaseIdx);
1017 if (Dune::FloatCmp::eq<Scalar>((cellData.density(wPhaseIdx)*cellData.density(nPhaseIdx)), 0))
1018 DUNE_THROW(Dune::MathError,
"Sequential2p2c::postProcessUpdate: try to divide by 0 density");
1019 Scalar vol = massw / cellData.density(wPhaseIdx) + massn / cellData.density(nPhaseIdx);
1020 if (Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(problem().timeManager().timeStepSize(), 0.0, 1.0e-30))
1022 cellData.volumeError()=(vol - problem().spatialParams().porosity(element));
1025 if (isnan(cellData.volumeError()))
1027 DUNE_THROW(Dune::MathError,
"Sequential2p2c::postProcessUpdate:\n"
1028 <<
"volErr[" << eIdxGlobal <<
"] isnan: vol = " << vol
1029 <<
", massw = " << massw <<
", rho_l = " << cellData.density(wPhaseIdx)
1030 <<
", massn = " << massn <<
", rho_g = " << cellData.density(nPhaseIdx)
1031 <<
", poro = " << problem().spatialParams().
porosity(element)
1032 <<
", dt = " << problem().timeManager().timeStepSize());
1036 cellData.volumeError()=0.;
Define some often used mathematical functions.
Simplifies writing multi-file VTK datasets.
Determines the pressures and saturations of all fluid phases given the total mass of all components.
Base class for compositional pressure equations.
constexpr Scalar harmonicMean(Scalar x, Scalar y, Scalar wx=1.0, Scalar wy=1.0) noexcept
Calculate the (weighted) harmonic mean of two scalar values.
Definition: math.hh:68
void harmonicMeanMatrix(Dune::FieldMatrix< Scalar, m, n > &K, const Dune::FieldMatrix< Scalar, m, n > &Ki, const Dune::FieldMatrix< Scalar, m, n > &Kj)
Calculate the harmonic mean of a fixed-size matrix.
Definition: math.hh:108
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:149
std::string viscosity(int phaseIdx) noexcept
I/O name of viscosity for multiphase systems.
Definition: name.hh:74
std::string permeability() noexcept
I/O name of permeability.
Definition: name.hh:143
std::string pressure(int phaseIdx) noexcept
I/O name of pressure for multiphase systems.
Definition: name.hh:34
std::string density(int phaseIdx) noexcept
I/O name of density for multiphase systems.
Definition: name.hh:65
std::string porosity() noexcept
I/O name of porosity.
Definition: name.hh:139
Flash calculation routines for compositional sequential models.
Definition: compositionalflash.hh:51
static void concentrationFlash2p2c(FluidState &fluidState, const Scalar &Z0, const PhaseVector &phasePressure, const Scalar &porosity, const Scalar &temperature)
2p2c Flash for constant p & T if concentration (feed mass fraction) is given.
Definition: compositionalflash.hh:92
The finite volume model for the solution of the compositional pressure equation.
Definition: fvpressure.hh:73
bool enableVolumeIntegral
Enables the volume integral of the pressure equation.
Definition: fvpressure.hh:183
Scalar ErrorTermLowerBound_
Handling of error term: lower bound for error dampening.
Definition: fvpressure.hh:187
void getSource(EntryType &sourceEntry, const Element &elementI, const CellData &cellDataI, const bool first)
Assembles the source term.
Definition: fvpressure.hh:213
Scalar ErrorTermFactor_
Handling of error term: relaxation factor.
Definition: fvpressure.hh:186
void getFlux(EntryType &entries, const Intersection &intersection, const CellData &cellDataI, const bool first)
Get flux at an interface between two cells.
Definition: fvpressure.hh:355
void getFluxOnBoundary(EntryType &entries, const Intersection &intersection, const CellData &cellDataI, const bool first)
Get flux on Boundary.
Definition: fvpressure.hh:646
const Problem & problem() const
Definition: fvpressure.hh:142
Problem & problem_
Definition: fvpressure.hh:182
static constexpr int pressureType
gives kind of pressure used ( , , )
Definition: fvpressure.hh:190
bool regulateBoundaryPermeability
Enables regulation of permeability in the direction of a Dirichlet Boundary Condition.
Definition: fvpressure.hh:184
Problem & problem()
Definition: fvpressure.hh:138
Scalar minimalBoundaryPermeability
Minimal limit for the boundary permeability.
Definition: fvpressure.hh:185
Dune::FieldVector< Scalar, 2 > EntryType
Definition: fvpressure.hh:136
void getStorage(EntryType &storageEntry, const Element &elementI, const CellData &cellDataI, const bool first)
Assembles the storage term.
Definition: fvpressure.hh:263
Scalar ErrorTermUpperBound_
Definition: fvpressure.hh:188
FVPressure2P2C(Problem &problem)
Constructs a FVPressure2P2C object.
Definition: fvpressure.hh:164
void updateMaterialLawsInElement(const Element &elementI, bool postTimeStep)
Updates secondary variables of one cell.
Definition: fvpressure.hh:904
The finite volume model for the solution of the compositional pressure equation.
Definition: fvpressurecompositional.hh:67
Defines the properties required for the sequential 2p2c models.