24#ifndef DUMUX_FVTRANSPORT2P2C_HH
25#define DUMUX_FVTRANSPORT2P2C_HH
28#include <unordered_map>
30#include <dune/grid/common/gridenums.hh>
31#include <dune/common/float_cmp.hh>
60template<
class TypeTag>
82 dim = GridView::dimension, dimWorld = GridView::dimensionworld
86 pw = Indices::pressureW,
87 pn = Indices::pressureN
91 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
92 wCompIdx = Indices::wPhaseIdx, nCompIdx = Indices::nPhaseIdx,
93 contiWEqIdx=Indices::contiWEqIdx, contiNEqIdx=Indices::contiNEqIdx,
94 NumPhases = getPropValue<TypeTag, Properties::NumPhases>(),
95 NumComponents = getPropValue<TypeTag, Properties::NumComponents>()
98 using Element =
typename GridView::Traits::template Codim<0>::Entity;
99 using Intersection =
typename GridView::Intersection;
101 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
102 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
103 using PhaseVector = Dune::FieldVector<Scalar, NumPhases>;
104 using ComponentVector = Dune::FieldVector<Scalar, NumComponents>;
126 void innerUpdate(TransportSolutionType& updateVec);
129 virtual void update(
const Scalar t, Scalar& dt, TransportSolutionType& updateVec,
bool impet =
false);
139 const Intersection& intersection, CellData& cellDataI);
143 const Intersection& intersection,
const CellData& cellDataI);
146 const Intersection& intersection,
147 FluidState& BCfluidState,
148 PhaseVector& pressBound);
158 int transportedQuantities = getPropValue<TypeTag, Properties::NumEq>() - 1;
160 for (
int eqNumber = 0; eqNumber < transportedQuantities; eqNumber++)
171 template<
class MultiWriter>
174 if(
problem().vtkOutputLevel()>3)
177 int size =
problem_.gridView().size(0);
178 ScalarSolutionType *totalC1PV = writer.allocateManagedBuffer(size);
179 ScalarSolutionType *totalC2PV = writer.allocateManagedBuffer(size);
182 writer.attachCellData(*totalC1PV,
"total Concentration w-Comp - vector");
183 writer.attachCellData(*totalC2PV,
"total Concentration n-Comp - vector");
190 int eIdxGlobal =
problem().variables().index(element);
197 int eIdxGlobal =
problem().variables().index(element);
198 CellData& cellData =
problem().variables().cellData(eIdxGlobal);
216 transportedQuantity.resize((getPropValue<TypeTag, Properties::NumEq>() - 1));
217 for(
int compIdx = 0; compIdx < (getPropValue<TypeTag, Properties::NumEq>() - 1); compIdx++)
218 transportedQuantity[compIdx].resize(
problem_.gridView().size(0));
246 template<
class DataEntry>
249 int numComp = getPropValue<TypeTag, Properties::NumEq>() - 1;
250 for(
int compIdx = 0; compIdx < numComp; compIdx++)
252 if (entry[compIdx] < -1.0e-6)
284 Scalar cFLFactor = getParam<Scalar>(
"Impet.CFLFactor");
286 subCFLFactor_ = min(getParam<Scalar>(
"Impet.SubCFLFactor"), cFLFactor);
287 verbosity_ = getParam<int>(
"TimeManager.SubTimestepVerbosity");
292 std::cout<<
"max CFL-Number of "<<cFLFactor<<
", max Sub-CFL-Number of "
293 <<
subCFLFactor_<<
": Enable local time-stepping!" << std::endl;
307 static const int pressureType = getPropValue<TypeTag, Properties::PressureFormulation>();
337 Implementation &asImp_()
338 {
return *
static_cast<Implementation *
>(
this); }
341 const Implementation &asImp_()
const
342 {
return *
static_cast<const Implementation *
>(
this); }
363template<
class TypeTag>
365 TransportSolutionType& updateVec,
bool impet)
370 unsigned int size = problem_.gridView().size(0);
371 if (localTimeStepping_)
373 if (this->timeStepData_.size() != size)
374 this->timeStepData_.resize(size);
381 updateVec.resize(getPropValue<TypeTag, Properties::NumComponents>());
382 updateVec[wCompIdx].resize(problem_.gridView().size(0));
383 updateVec[nCompIdx].resize(problem_.gridView().size(0));
384 updateVec[wCompIdx] = 0;
385 updateVec[nCompIdx] = 0;
388 int restrictingCell = -1;
390 ComponentVector entries(0.);
393 for (
const auto& element : elements(problem().gridView()))
396 int eIdxGlobalI = problem().variables().index(element);
397 CellData& cellDataI = problem().variables().cellData(eIdxGlobalI);
400 double sumfactorin = 0;
401 double sumfactorout = 0;
404 for (
const auto& intersection : intersections(problem().gridView(), element))
406 int indexInInside = intersection.indexInInside();
409 if (intersection.neighbor())
410 asImp_().getFlux(entries, timestepFlux, intersection, cellDataI);
413 if (intersection.boundary())
414 asImp_().getFluxOnBoundary(entries, timestepFlux, intersection, cellDataI);
417 if (localTimeStepping_)
420 if (localData.
faceTargetDt[indexInInside] < accumulatedDt_ + dtThreshold_)
422 localData.
faceFluxes[indexInInside] = entries;
428 updateVec[wCompIdx][eIdxGlobalI] += entries[wCompIdx];
429 updateVec[nCompIdx][eIdxGlobalI] += entries[nCompIdx];
433 sumfactorin += timestepFlux[0];
434 sumfactorout += timestepFlux[1];
438 if (localTimeStepping_)
441 for (
int i=0; i < 2*dim; i++)
443 updateVec[wCompIdx][eIdxGlobalI] += localData.
faceFluxes[i][wCompIdx];
444 updateVec[nCompIdx][eIdxGlobalI] += localData.
faceFluxes[i][nCompIdx];
449 PrimaryVariables q(NAN);
450 problem().source(q, element);
451 updateVec[wCompIdx][eIdxGlobalI] += q[contiWEqIdx];
452 updateVec[nCompIdx][eIdxGlobalI] += q[contiNEqIdx];
456 sumfactorin = max(sumfactorin,sumfactorout)
457 / problem().spatialParams().porosity(element);
460 if (localTimeStepping_)
462 timeStepData_[eIdxGlobalI].dt = 1./sumfactorin;
463 if ( 1./sumfactorin < dt)
466 restrictingCell= eIdxGlobalI;
471 if ( 1./sumfactorin < dt)
474 restrictingCell= eIdxGlobalI;
482 using ElementMapper =
typename SolutionTypes::ElementMapper;
484 for (
int i = 0; i < updateVec.size(); i++)
486 DataHandle dataHandle(problem_.variables().elementMapper(), updateVec[i]);
487 problem_.gridView().template communicate<DataHandle>(dataHandle,
488 Dune::InteriorBorder_All_Interface,
489 Dune::ForwardCommunication);
492 if (localTimeStepping_)
496 TimeDataHandle timeDataHandle(problem_.elementMapper(), timeStepData_);
497 problem_.gridView().template communicate<TimeDataHandle>(timeDataHandle,
498 Dune::InteriorBorder_All_Interface,
499 Dune::ForwardCommunication);
502 dt = problem_.gridView().comm().min(dt);
507 Dune::dinfo <<
"Timestep restricted by CellIdx " << restrictingCell <<
" leads to dt = "
508 <<dt * getParam<Scalar>(
"Impet.CFLFactor")<< std::endl;
509 if (averagedFaces_ != 0)
510 Dune::dinfo <<
" Averageing done for " << averagedFaces_ <<
" faces. "<< std::endl;
519template<
class TypeTag>
522 if (this->enableLocalTimeStepping())
523 this->innerUpdate(updateVector);
525 updateConcentrations(updateVector, problem().timeManager().timeStepSize());
535template<
class TypeTag>
538 updateConcentrations(updateVector, dt);
548template<
class TypeTag>
552 for (
int i = 0; i< problem().gridView().size(0); i++)
554 CellData& cellDataI = problem().variables().cellData(i);
555 for(
int compIdx = 0; compIdx < getPropValue<TypeTag, Properties::NumComponents>(); compIdx++)
557 totalConcentration_[compIdx][i] += (updateVector[compIdx][i]*=dt);
558 cellDataI.setMassConcentration(compIdx, totalConcentration_[compIdx][i]);
579template<
class TypeTag>
581 Dune::FieldVector<Scalar, 2>& timestepFlux,
582 const Intersection& intersection,
588 auto elementI = intersection.inside();
589 int eIdxGlobalI = problem().variables().index(elementI);
592 const GlobalPosition globalPos = elementI.geometry().center();
593 const GlobalPosition& gravity_ = problem().gravity();
595 Scalar volume = elementI.geometry().volume();
598 Scalar pressI = problem().pressureModel().pressure(eIdxGlobalI);
599 Scalar pcI = cellDataI.capillaryPressure();
600 DimMatrix K_I(problem().spatialParams().intrinsicPermeability(elementI));
605 const auto fluidMatrixInteraction = Deprecated::makePcKrSw(Scalar{}, problem().spatialParams(), elementI);
607 PhaseVector SmobI(0.);
609 SmobI[wPhaseIdx] = max((cellDataI.saturation(wPhaseIdx)
610 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().swr())
612 SmobI[nPhaseIdx] = max((cellDataI.saturation(nPhaseIdx)
613 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().snr())
616 Scalar densityWI (0.), densityNWI(0.);
617 densityWI= cellDataI.density(wPhaseIdx);
618 densityNWI = cellDataI.density(nPhaseIdx);
621 GlobalPosition unitOuterNormal = intersection.centerUnitOuterNormal();
623 unitOuterNormal *= -1.0;
624 Scalar faceArea = intersection.geometry().volume();
631 Dune::FieldVector<Scalar, 2> factor (0.);
632 Dune::FieldVector<Scalar, 2> updFactor (0.);
634 PhaseVector potential(0.);
637 auto neighbor = intersection.outside();
638 int eIdxGlobalJ = problem().variables().index(neighbor);
639 CellData& cellDataJ = problem().variables().cellData(eIdxGlobalJ);
642 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
645 GlobalPosition distVec = globalPosNeighbor - globalPos;
647 Scalar dist = distVec.two_norm();
649 GlobalPosition unitDistVec(distVec);
653 Scalar densityWJ (0.), densityNWJ(0.);
654 densityWJ = cellDataJ.density(wPhaseIdx);
655 densityNWJ = cellDataJ.density(nPhaseIdx);
658 double densityW_mean = (densityWI + densityWJ) * 0.5;
659 double densityNW_mean = (densityNWI + densityNWJ) * 0.5;
661 double pressJ = problem().pressureModel().pressure(eIdxGlobalJ);
662 Scalar pcJ = cellDataJ.capillaryPressure();
665 DimMatrix meanK_(0.);
668 problem().spatialParams().intrinsicPermeability(neighbor));
669 Dune::FieldVector<Scalar,dim> K(0);
670 meanK_.umv(unitDistVec,K);
673 switch (pressureType)
677 potential[wPhaseIdx] = (pressI - pressJ) / (dist);
678 potential[nPhaseIdx] = (pressI - pressJ + pcI - pcJ) / (dist);
683 potential[wPhaseIdx] = (pressI - pressJ - pcI + pcJ) / (dist);
684 potential[nPhaseIdx] = (pressI - pressJ) / (dist);
689 potential[nPhaseIdx] += (gravity_ * unitDistVec) * densityNW_mean;
690 potential[wPhaseIdx] += (gravity_ * unitDistVec) * densityW_mean;
692 potential[wPhaseIdx] *= fabs(K * unitOuterNormal);
693 potential[nPhaseIdx] *= fabs(K * unitOuterNormal);
696 Dune::FieldVector<bool, NumPhases> doUpwinding(
true);
697 PhaseVector lambda(0.);
698 for(
int phaseIdx = 0; phaseIdx < NumPhases; phaseIdx++)
701 if(phaseIdx == wPhaseIdx)
702 contiEqIdx = contiWEqIdx;
704 contiEqIdx = contiNEqIdx;
706 if(!impet_ || restrictFluxInTransport_==0)
708 if (potential[phaseIdx] > 0.)
710 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
711 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
true);
714 else if(potential[phaseIdx] < 0.)
716 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
717 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
false);
721 doUpwinding[phaseIdx] =
false;
722 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
false);
723 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiEqIdx,
false);
728 bool wasUpwindCell = cellDataI.isUpwindCell(intersection.indexInInside(), contiEqIdx);
730 if (potential[phaseIdx] > 0. && wasUpwindCell)
731 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
732 else if (potential[phaseIdx] < 0. && !wasUpwindCell)
733 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
735 else if(restrictFluxInTransport_ == 2)
736 doUpwinding[phaseIdx] =
false;
740 if (potential[phaseIdx] > 0. && (Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellDataJ.mobility(phaseIdx), 0.0, 1.0e-30)
741 || (cellDataI.wasRefined() && cellDataJ.wasRefined() && elementI.father() == neighbor.father())))
742 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
743 else if (potential[phaseIdx] < 0. && (Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellDataI.mobility(phaseIdx), 0.0, 1.0e-30)
744 || (cellDataI.wasRefined() && cellDataJ.wasRefined() && elementI.father() == neighbor.father())))
745 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
747 doUpwinding[phaseIdx] =
false;
753 if(!doUpwinding[phaseIdx])
756 if(cellDataI.mobility(phaseIdx)+cellDataJ.mobility(phaseIdx)==0.)
758 potential[phaseIdx] = 0;
763 fluxEntries[wCompIdx] -= potential[phaseIdx] * faceArea / volume
764 *
harmonicMean(cellDataI.massFraction(phaseIdx, wCompIdx) * cellDataI.mobility(phaseIdx) * cellDataI.density(phaseIdx),
765 cellDataJ.massFraction(phaseIdx, wCompIdx) * cellDataJ.mobility(phaseIdx) * cellDataJ.density(phaseIdx));
766 fluxEntries[nCompIdx] -= potential[phaseIdx] * faceArea / volume
767 *
harmonicMean(cellDataI.massFraction(phaseIdx, nCompIdx) * cellDataI.mobility(phaseIdx) * cellDataI.density(phaseIdx),
768 cellDataJ.massFraction(phaseIdx, nCompIdx) * cellDataJ.mobility(phaseIdx) * cellDataJ.density(phaseIdx));
772 timestepFlux[0] += max(0.,
773 - potential[phaseIdx] * faceArea / volume
774 *
harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx)));
776 timestepFlux[1] += max(0.,
777 potential[phaseIdx] * faceArea / volume
778 *
harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx))/SmobI[phaseIdx]);
781 if(!(cellDataI.wasRefined() && cellDataJ.wasRefined() && elementI.father() == neighbor.father())
782 && eIdxGlobalI > eIdxGlobalJ)
785 #if DUNE_MINIMAL_DEBUG_LEVEL < 3
787 if(eIdxGlobalI > eIdxGlobalJ)
788 Dune::dinfo <<
"harmonicMean flux of phase" << phaseIdx <<
" used from cell" << eIdxGlobalI<<
" into " << eIdxGlobalJ
789 <<
" ; TE upwind I = "<< cellDataI.isUpwindCell(intersection.indexInInside(), contiEqIdx)
790 <<
" but pot = "<< potential[phaseIdx] << std::endl;
795 potential[phaseIdx] = 0;
801 double velocityJIw = max((-lambda[wPhaseIdx] * potential[wPhaseIdx]) * faceArea / volume, 0.0);
802 double velocityIJw = max(( lambda[wPhaseIdx] * potential[wPhaseIdx]) * faceArea / volume, 0.0);
803 double velocityJIn = max((-lambda[nPhaseIdx] * potential[nPhaseIdx]) * faceArea / volume, 0.0);
804 double velocityIJn = max(( lambda[nPhaseIdx] * potential[nPhaseIdx]) * faceArea / volume, 0.0);
807 timestepFlux[0] += velocityJIw + velocityJIn;
809 double foutw = velocityIJw/SmobI[wPhaseIdx];
810 double foutn = velocityIJn/SmobI[nPhaseIdx];
813 if (isnan(foutw) || isinf(foutw) || foutw < 0) foutw = 0;
814 if (isnan(foutn) || isinf(foutn) || foutn < 0) foutn = 0;
815 timestepFlux[1] += foutw + foutn;
817 fluxEntries[wCompIdx] +=
818 velocityJIw * cellDataJ.massFraction(wPhaseIdx, wCompIdx) * densityWJ
819 - velocityIJw * cellDataI.massFraction(wPhaseIdx, wCompIdx) * densityWI
820 + velocityJIn * cellDataJ.massFraction(nPhaseIdx, wCompIdx) * densityNWJ
821 - velocityIJn * cellDataI.massFraction(nPhaseIdx, wCompIdx) * densityNWI;
822 fluxEntries[nCompIdx] +=
823 velocityJIw * cellDataJ.massFraction(wPhaseIdx, nCompIdx) * densityWJ
824 - velocityIJw * cellDataI.massFraction(wPhaseIdx, nCompIdx) * densityWI
825 + velocityJIn * cellDataJ.massFraction(nPhaseIdx, nCompIdx) * densityNWJ
826 - velocityIJn * cellDataI.massFraction(nPhaseIdx, nCompIdx) * densityNWI;
889template<
class TypeTag>
891 Dune::FieldVector<Scalar, 2>& timestepFlux,
892 const Intersection& intersection,
893 const CellData& cellDataI)
897 auto elementI = intersection.inside();
898 int eIdxGlobalI = problem().variables().index(elementI);
901 const GlobalPosition globalPos = elementI.geometry().center();
904 Scalar volume = elementI.geometry().volume();
905 const GlobalPosition& gravity_ = problem().gravity();
907 Scalar pressI = problem().pressureModel().pressure(eIdxGlobalI);
908 Scalar pcI = cellDataI.capillaryPressure();
909 DimMatrix K_I(problem().spatialParams().intrinsicPermeability(elementI));
911 if(regulateBoundaryPermeability)
913 int axis = intersection.indexInInside() / 2;
914 if(K_I[axis][axis] < minimalBoundaryPermeability)
915 K_I[axis][axis] = minimalBoundaryPermeability;
921 const auto fluidMatrixInteraction = Deprecated::makePcKrSw(Scalar{}, problem().spatialParams(), elementI);
923 Scalar SwmobI = max((cellDataI.saturation(wPhaseIdx)
924 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().swr())
926 Scalar SnmobI = max((cellDataI.saturation(nPhaseIdx)
927 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().snr())
930 Scalar densityWI (0.), densityNWI(0.);
931 densityWI= cellDataI.density(wPhaseIdx);
932 densityNWI = cellDataI.density(nPhaseIdx);
935 GlobalPosition unitOuterNormal = intersection.centerUnitOuterNormal();
937 unitOuterNormal *= -1.0;
938 Scalar faceArea = intersection.geometry().volume();
941 Dune::FieldVector<Scalar, 2> factor (0.);
942 Dune::FieldVector<Scalar, 2> updFactor (0.);
944 PhaseVector potential(0.);
946 const GlobalPosition& globalPosFace = intersection.geometry().center();
949 GlobalPosition distVec = globalPosFace - globalPos;
951 Scalar dist = distVec.two_norm();
953 GlobalPosition unitDistVec(distVec);
957 FluidState BCfluidState;
960 BoundaryTypes bcTypes;
961 problem().boundaryTypes(bcTypes, intersection);
964 if (bcTypes.isDirichlet(contiWEqIdx))
967 PhaseVector pressBound(0.);
971 this->evalBoundary(globalPosFace,
977 Scalar densityWBound = BCfluidState.density(wPhaseIdx);
978 Scalar densityNWBound = BCfluidState.density(nPhaseIdx);
981 if(getPropValue<TypeTag, Properties::EnableCapillarity>())
982 pcBound = (BCfluidState.pressure(nPhaseIdx) - BCfluidState.pressure(wPhaseIdx));
984 double densityW_mean = (densityWI + densityWBound) / 2;
985 double densityNW_mean = (densityNWI + densityNWBound) / 2;
988 Dune::FieldVector<Scalar,dim> K(0);
989 K_I.umv(unitDistVec,K);
992 switch (pressureType)
996 potential[wPhaseIdx] = (pressI - pressBound[wPhaseIdx]) / dist;
997 potential[nPhaseIdx] = (pressI + pcI - pressBound[wPhaseIdx] - pcBound)
1003 potential[wPhaseIdx] = (pressI - pcI - pressBound[nPhaseIdx] + pcBound)
1005 potential[nPhaseIdx] = (pressI - pressBound[nPhaseIdx]) / dist;
1009 potential[wPhaseIdx] += (gravity_ * unitDistVec) * densityW_mean;
1010 potential[nPhaseIdx] += (gravity_ * unitDistVec) * densityNW_mean;
1012 potential[wPhaseIdx] *= fabs(K * unitOuterNormal);
1013 potential[nPhaseIdx] *= fabs(K * unitOuterNormal);
1018 const auto fluidMatrixInteraction = Deprecated::makePcKrSw(Scalar{}, problem().spatialParams(), elementI);
1021 PhaseVector lambda(0.);
1022 if (potential[wPhaseIdx] >= 0.)
1023 lambda[wPhaseIdx] = cellDataI.mobility(wPhaseIdx);
1026 if(getPropValue<TypeTag, Properties::BoundaryMobility>()==Indices::satDependent)
1027 lambda[wPhaseIdx] = BCfluidState.saturation(wPhaseIdx) / viscosityWBound;
1029 lambda[wPhaseIdx] = fluidMatrixInteraction.krw(BCfluidState.saturation(wPhaseIdx)) / viscosityWBound;
1031 if (potential[nPhaseIdx] >= 0.)
1032 lambda[nPhaseIdx] = cellDataI.mobility(nPhaseIdx);
1035 if(getPropValue<TypeTag, Properties::BoundaryMobility>()==Indices::satDependent)
1036 lambda[nPhaseIdx] = BCfluidState.saturation(nPhaseIdx) / viscosityNWBound;
1038 lambda[nPhaseIdx] = fluidMatrixInteraction.krn(BCfluidState.saturation(wPhaseIdx)) / viscosityNWBound;
1042 double velocityJIw = max((-lambda[wPhaseIdx] * potential[wPhaseIdx]) * faceArea / volume, 0.0);
1043 double velocityIJw = max(( lambda[wPhaseIdx] * potential[wPhaseIdx]) * faceArea / volume, 0.0);
1044 double velocityJIn = max((-lambda[nPhaseIdx] * potential[nPhaseIdx]) * faceArea / volume, 0.0);
1045 double velocityIJn = max(( lambda[nPhaseIdx] * potential[nPhaseIdx]) * faceArea / volume, 0.0);
1048 timestepFlux[0] = velocityJIw + velocityJIn;
1050 double foutw = velocityIJw/SwmobI;
1051 double foutn = velocityIJn/SnmobI;
1054 if (isnan(foutw) || isinf(foutw) || foutw < 0) foutw = 0;
1055 if (isnan(foutn) || isinf(foutn) || foutn < 0) foutn = 0;
1056 timestepFlux[1] = foutw + foutn;
1058 fluxEntries[wCompIdx] =
1059 + velocityJIw * BCfluidState.massFraction(wPhaseIdx, wCompIdx) * densityWBound
1060 - velocityIJw * cellDataI.massFraction(wPhaseIdx, wCompIdx) * densityWI
1061 + velocityJIn * BCfluidState.massFraction(nPhaseIdx, wCompIdx) * densityNWBound
1062 - velocityIJn * cellDataI.massFraction(nPhaseIdx, wCompIdx) * densityNWI ;
1063 fluxEntries[nCompIdx] =
1064 velocityJIw * BCfluidState.massFraction(wPhaseIdx, nCompIdx) * densityWBound
1065 - velocityIJw * cellDataI.massFraction(wPhaseIdx, nCompIdx) * densityWI
1066 + velocityJIn * BCfluidState.massFraction(nPhaseIdx, nCompIdx) * densityNWBound
1067 - velocityIJn * cellDataI.massFraction(nPhaseIdx, nCompIdx) * densityNWI ;
1069 else if (bcTypes.isNeumann(contiWEqIdx))
1072 PrimaryVariables J(NAN);
1073 problem().neumann(J, intersection);
1074 fluxEntries[wCompIdx] = - J[contiWEqIdx] * faceArea / volume;
1075 fluxEntries[nCompIdx] = - J[contiNEqIdx] * faceArea / volume;
1078 #define cflIgnoresNeumann
1079 #ifdef cflIgnoresNeumann
1080 timestepFlux[0] = 0;
1081 timestepFlux[1] = 0;
1083 double inflow = updFactor[wCompIdx] / densityW + updFactor[nCompIdx] / densityNW;
1086 timestepFlux[0] = updFactor[wCompIdx] / densityW
1087 + updFactor[nCompIdx] / densityNW;
1088 timestepFlux[1] = -(updFactor[wCompIdx] / densityW /SwmobI
1089 + updFactor[nCompIdx] / densityNW / SnmobI);
1093 timestepFlux[0] = -(updFactor[wCompIdx] / densityW
1094 + updFactor[nCompIdx] / densityNW);
1095 timestepFlux[1] = updFactor[wCompIdx] / densityW /SwmobI
1096 + updFactor[nCompIdx] / densityNW / SnmobI;
1118template<
class TypeTag>
1120 const Intersection& intersection,
1121 FluidState &BCfluidState,
1122 PhaseVector &pressBound)
1127 auto element = intersection.inside();
1129 PrimaryVariables primaryVariablesOnBoundary(0.);
1130 problem().dirichlet(primaryVariablesOnBoundary, intersection);
1135 const auto fluidMatrixInteraction = Deprecated::makePcKrSw(Scalar{}, problem().spatialParams(), element);
1138 typename Indices::BoundaryFormulation bcType;
1139 problem().boundaryFormulation(bcType, intersection);
1142 Scalar satBound = primaryVariablesOnBoundary[contiWEqIdx];
1144 if(getPropValue<TypeTag, Properties::EnableCapillarity>())
1146 Scalar pcBound = fluidMatrixInteraction.pc(satBound);
1147 switch (pressureType)
1151 pressBound[wPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx];
1152 pressBound[nPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx] + pcBound;
1157 pressBound[wPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx] - pcBound;
1158 pressBound[nPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx];
1164 pressBound[wPhaseIdx] = pressBound[nPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx];
1167 problem().temperatureAtPos(globalPosFace));
1169 else if (bcType == Indices::concentration)
1172 pressBound[wPhaseIdx] = pressBound[nPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx];
1173 Scalar Z0Bound = primaryVariablesOnBoundary[contiWEqIdx];
1175 problem().temperatureAtPos(globalPosFace));
1177 if(getPropValue<TypeTag, Properties::EnableCapillarity>())
1179 Scalar pcBound = fluidMatrixInteraction.pc(BCfluidState.saturation(wPhaseIdx));
1182 for(
int iter=0; iter < maxiter; iter++)
1185 switch (pressureType)
1189 pressBound[wPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx];
1190 pressBound[nPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx]
1196 pressBound[wPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx]
1198 pressBound[nPhaseIdx] = primaryVariablesOnBoundary[Indices::pressureEqIdx];
1204 Scalar oldPc = pcBound;
1207 problem().temperatureAtPos(globalPosFace));
1208 pcBound = fluidMatrixInteraction.pc(BCfluidState.saturation(wPhaseIdx));
1212 if (abs(oldPc - pcBound) < 10.0)
1218 DUNE_THROW(Dune::NotImplemented,
"Boundary Formulation neither Concentration nor Saturation??");
1221template<
class TypeTag>
1224 dt = std::numeric_limits<Scalar>::max();
1227 for (
const auto& element : elements(problem_.gridView()))
1230 if (element.partitionType() != Dune::InteriorEntity)
1237 int eIdxGlobalI = problem_.variables().index(element);
1242 using FaceDt = std::unordered_map<int, Scalar>;
1246 for (
const auto& intersection : intersections(problem_.gridView(), element))
1248 int indexInInside = intersection.indexInInside();
1250 if (intersection.neighbor())
1252 auto neighbor = intersection.outside();
1253 int eIdxGlobalJ = problem_.variables().index(neighbor);
1255 int levelI = element.level();
1256 int levelJ = neighbor.level();
1259 if (eIdxGlobalI < eIdxGlobalJ && levelI <= levelJ)
1263 int indexInOutside = intersection.indexInOutside();
1265 if (localDataI.
faceTargetDt[indexInInside] < accumulatedDt_ + dtThreshold_
1266 || localDataJ.
faceTargetDt[indexInOutside] < accumulatedDt_ + dtThreshold_)
1268 Scalar timeStep = min(localDataI.
dt, localDataJ.
dt);
1270 if (levelI < levelJ)
1272 typename FaceDt::iterator it = faceDt.find(indexInInside);
1273 if (it != faceDt.end())
1275 it->second = min(it->second, timeStep);
1279 faceDt.insert(std::make_pair(indexInInside, timeStep));
1284 localDataI.
faceTargetDt[indexInInside] += subCFLFactor_ * timeStep;
1285 localDataJ.
faceTargetDt[indexInOutside] += subCFLFactor_ * timeStep;
1288 dt = min(dt, timeStep);
1292 else if (intersection.boundary())
1294 if (localDataI.
faceTargetDt[indexInInside] < accumulatedDt_ + dtThreshold_)
1296 localDataI.
faceTargetDt[indexInInside] += subCFLFactor_ * localDataI.
dt;
1297 dt = min(dt, subCFLFactor_ * localDataI.
dt);
1301 if (faceDt.size() > 0)
1303 typename FaceDt::iterator it = faceDt.begin();
1304 for (;it != faceDt.end();++it)
1306 localDataI.
faceTargetDt[it->first] += subCFLFactor_ * it->second;
1309 for (
const auto& intersection : intersections(problem_.gridView(), element))
1311 if (intersection.neighbor())
1313 int indexInInside = intersection.indexInInside();
1315 it = faceDt.find(indexInInside);
1316 if (it != faceDt.end())
1318 auto neighbor = intersection.outside();
1319 int eIdxGlobalJ = problem_.variables().index(neighbor);
1323 int indexInOutside = intersection.indexInOutside();
1325 localDataJ.
faceTargetDt[indexInOutside] += subCFLFactor_ * it->second;
1335 using ElementMapper =
typename SolutionTypes::ElementMapper;
1338 TimeDataHandle timeDataHandle(problem_.elementMapper(), timeStepData_);
1339 problem_.gridView().template communicate<TimeDataHandle>(timeDataHandle,
1340 Dune::InteriorBorder_All_Interface,
1341 Dune::ForwardCommunication);
1343 dt = problem_.gridView().comm().min(dt);
1347template<
class TypeTag>
1350 if (localTimeStepping_)
1352 Scalar realDt = problem_.timeManager().timeStepSize();
1354 Scalar subDt = realDt;
1356 updatedTargetDt_(subDt);
1358 Scalar accumulatedDtOld = accumulatedDt_;
1359 accumulatedDt_ += subDt;
1361 Scalar t = problem_.timeManager().time();
1363 if (accumulatedDt_ < realDt)
1368 Scalar dtCorrection = min(0.0, realDt - accumulatedDt_);
1369 subDt += dtCorrection;
1372 std::cout<<
" Sub-time-step size: "<<subDt<< std::endl;
1374 bool stopTimeStep =
false;
1375 int size = problem_.gridView().size(0);
1376 for (
int i = 0; i < size; i++)
1379 int transportedQuantities = getPropValue<TypeTag, Properties::NumEq>() - 1;
1380 for (
int eqNumber = 0; eqNumber < transportedQuantities; eqNumber++)
1382 newVal[eqNumber] = totalConcentration_[eqNumber][i];
1383 newVal[eqNumber] += updateVec[eqNumber][i] * subDt;
1385 if (!asImp_().inPhysicalRange(newVal))
1387 stopTimeStep =
true;
1396 rank = problem_.gridView().comm().rank();
1398 rank = problem_.gridView().comm().max(rank);
1399 problem_.gridView().comm().broadcast(&stopTimeStep,1,rank);
1403 if (stopTimeStep && accumulatedDtOld > dtThreshold_)
1405 problem_.timeManager().setTimeStepSize(accumulatedDtOld);
1410 asImp_().updateTransportedQuantity(updateVec, subDt);
1414 if (accumulatedDt_ >= realDt)
1419 problem_.pressureModel().updateMaterialLaws();
1420 problem_.model().updateTransport(t, subDt, updateVec);
1422 updatedTargetDt_(subDt);
1424 accumulatedDtOld = accumulatedDt_;
1425 accumulatedDt_ += subDt;
1430 asImp_().updateTransportedQuantity(updateVec, realDt);
1433 resetTimeStepData_();
Define some often used mathematical functions.
Determines the pressures and saturations of all fluid phases given the total mass of all components.
Contains a class to exchange entries of a vector.
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
T getParam(Args &&... args)
A free function to get a parameter from the parameter tree singleton.
Definition: parameters.hh:364
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type GetProp
get the type of a property (equivalent to old macro GET_PROP(...))
Definition: propertysystem.hh:140
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 saturation(int phaseIdx) noexcept
I/O name of saturation for multiphase systems.
Definition: name.hh:43
std::string viscosity(int phaseIdx) noexcept
I/O name of viscosity for multiphase systems.
Definition: name.hh:74
Flash calculation routines for compositional sequential models.
Definition: compositionalflash.hh:51
static void saturationFlash2p2c(FluidState &fluidState, const Scalar &saturation, const PhaseVector &phasePressure, const Scalar &porosity, const Scalar &temperature)
Definition: compositionalflash.hh:219
static void concentrationFlash2p2c(FluidState &fluidState, const Scalar &Z0, const PhaseVector &phasePressure, const Scalar &porosity, const Scalar &temperature)
Definition: compositionalflash.hh:71
A data handle class to exchange entries of a vector.
Definition: vectorcommdatahandle.hh:78
Compositional transport step in a Finite Volume discretization.
Definition: fvtransport.hh:62
virtual void update(const Scalar t, Scalar &dt, TransportSolutionType &updateVec, bool impet=false)
Calculate the update vector and determine timestep size This method calculates the update vector of ...
Definition: fvtransport.hh:364
void evalBoundary(GlobalPosition globalPosFace, const Intersection &intersection, FluidState &BCfluidState, PhaseVector &pressBound)
Evaluate the boundary conditions.
Definition: fvtransport.hh:1119
void deserializeEntity(std::istream &instream, const Element &element)
Function needed for restart option of the transport model: Read in.
Definition: fvtransport.hh:195
bool regulateBoundaryPermeability
Enables regulation of permeability in the direction of a Dirichlet Boundary Condition.
Definition: fvtransport.hh:311
void updateConcentrations(TransportSolutionType &updateVector, Scalar dt)
Updates the concentrations once an update is calculated.
Definition: fvtransport.hh:549
bool localTimeStepping_
Definition: fvtransport.hh:331
Scalar subCFLFactor_
Definition: fvtransport.hh:330
int restrictFluxInTransport_
Restriction of flux on new pressure field if direction reverses from the pressure equation.
Definition: fvtransport.hh:309
FVTransport2P2C(Problem &problem)
Constructs a FVTransport2P2C object Currently, the compositional transport scheme can not be applied ...
Definition: fvtransport.hh:274
const Scalar dtThreshold_
Threshold for sub-time-stepping routine.
Definition: fvtransport.hh:318
void initialize()
Set the initial values before the first pressure equation This method is called before first pressure...
Definition: fvtransport.hh:155
void addOutputVtkFields(MultiWriter &writer)
Write transport variables into the output files.
Definition: fvtransport.hh:172
void getSource(Scalar &update, const Element &element, CellData &cellDataI)
Definition: fvtransport.hh:237
Scalar & totalConcentration(int compIdx, int eIdxGlobal)
Return the the total concentration stored in the transport vector To get real cell values,...
Definition: fvtransport.hh:232
Problem & problem_
Definition: fvtransport.hh:302
void innerUpdate(TransportSolutionType &updateVec)
Definition: fvtransport.hh:1348
int averagedFaces_
number of faces were flux was restricted
Definition: fvtransport.hh:304
void updatedTargetDt_(Scalar &dt)
Definition: fvtransport.hh:1222
void resetTimeStepData_()
Definition: fvtransport.hh:324
Dune::FieldVector< Scalar, 2 > EntryType
Definition: fvtransport.hh:109
bool impet_
indicating if we are in an estimate (false) or real impet (true) step.
Definition: fvtransport.hh:303
void serializeEntity(std::ostream &outstream, const Element &element)
Function needed for restart option of the transport model: Write out.
Definition: fvtransport.hh:188
void getTransportedQuantity(TransportSolutionType &transportedQuantity)
Return the vector of the transported quantity For an immiscible IMPES scheme, this is the saturation....
Definition: fvtransport.hh:213
void getFlux(ComponentVector &fluxEntries, EntryType ×tepFlux, const Intersection &intersection, CellData &cellDataI)
Get flux at an interface between two cells The flux through is calculated according to the underlyin...
Definition: fvtransport.hh:580
Problem & problem()
Acess function for the current problem.
Definition: fvtransport.hh:123
std::vector< LocalTimesteppingData > timeStepData_
Stores data for sub-time-stepping.
Definition: fvtransport.hh:320
int verbosity_
Definition: fvtransport.hh:332
bool inPhysicalRange(DataEntry &entry)
Function to control the abort of the transport-sub-time-stepping depending on a physical parameter ra...
Definition: fvtransport.hh:247
TransportSolutionType totalConcentration_
private vector of transported primary variables
Definition: fvtransport.hh:301
Scalar accumulatedDt_
Current time-interval in sub-time-stepping routine.
Definition: fvtransport.hh:316
virtual ~FVTransport2P2C()
Definition: fvtransport.hh:296
void updateTransportedQuantity(TransportSolutionType &updateVector)
Updates the transported quantity once an update is calculated.
Definition: fvtransport.hh:520
void getFluxOnBoundary(ComponentVector &fluxEntries, EntryType ×tepFlux, const Intersection &intersection, const CellData &cellDataI)
Get flux on Boundary.
Definition: fvtransport.hh:890
static const int pressureType
gives kind of pressure used ( , , )
Definition: fvtransport.hh:307
bool switchNormals
Definition: fvtransport.hh:314
bool enableLocalTimeStepping()
Function to check if local time stepping is activated.
Definition: fvtransport.hh:261
Dune::FieldVector< Scalar, 2 > TimeStepFluxType
Definition: fvtransport.hh:110
Scalar minimalBoundaryPermeability
Minimal limit for the boundary permeability.
Definition: fvtransport.hh:313
Definition: fvtransport.hh:114
Dune::FieldVector< EntryType, 2 *dim > faceFluxes
Definition: fvtransport.hh:115
Dune::FieldVector< Scalar, 2 *dim > faceTargetDt
Definition: fvtransport.hh:116
LocalTimesteppingData()
Definition: fvtransport.hh:118
Scalar dt
Definition: fvtransport.hh:117
Defines the properties required for the sequential 2p2c models.