24#ifndef DUMUX_FV3DTRANSPORT2P2C_ADAPTIVE_HH
25#define DUMUX_FV3DTRANSPORT2P2C_ADAPTIVE_HH
27#include <dune/grid/common/gridenums.hh>
28#include <dune/common/float_cmp.hh>
52template<
class TypeTag>
59 using SpatialParams =
typename GET_PROP_TYPE(TypeTag, SpatialParams);
60 using MaterialLaw =
typename SpatialParams::MaterialLaw;
62 using Indices =
typename GET_PROP_TYPE(TypeTag, ModelTraits)::Indices;
63 using BoundaryTypes =
typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
65 using FluidSystem =
typename GET_PROP_TYPE(TypeTag, FluidSystem);
66 using FluidState =
typename GET_PROP_TYPE(TypeTag, FluidState);
70 using TransportSolutionType =
typename GET_PROP_TYPE(TypeTag, TransportSolutionType);
74 dim = GridView::dimension, dimWorld = GridView::dimensionworld,
79 pw = Indices::pressureW,
80 pn = Indices::pressureN,
81 Sw = Indices::saturationW,
82 Sn = Indices::saturationN
86 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
87 wCompIdx = Indices::wPhaseIdx, nCompIdx = Indices::nPhaseIdx,
88 contiWEqIdx=Indices::contiWEqIdx, contiNEqIdx=Indices::contiNEqIdx
91 using Element =
typename GridView::Traits::template Codim<0>::Entity;
92 using Grid =
typename GridView::Grid;
93 using Intersection =
typename GridView::Intersection;
94 using IntersectionIterator =
typename GridView::IntersectionIterator;
96 using TransmissivityMatrix = Dune::FieldVector<Scalar,dim+1>;
97 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
98 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
99 using PhaseVector = Dune::FieldVector<Scalar, NumPhases>;
100 using PrimaryVariables =
typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
107 virtual void update(
const Scalar t, Scalar& dt, TransportSolutionType& updateVec,
110 void getMpfaFlux(Dune::FieldVector<Scalar, 2>&, Dune::FieldVector<Scalar, 2>&,
111 const IntersectionIterator&, CellData&);
125 enableMPFA = getParam<bool>(
"GridAdapt.EnableMultiPointFluxApproximation");
161template<
class TypeTag>
163 TransportSolutionType& updateVec,
bool impet)
165 this->impet_ = impet;
169 this->averagedFaces_ = 0;
172 int size_ = problem_.gridView().size(0);
174 updateVec[wCompIdx].resize(size_);
175 updateVec[nCompIdx].resize(size_);
176 updateVec[wCompIdx] = 0;
177 updateVec[nCompIdx] = 0;
179 if(this->totalConcentration_.size() != size_)
181 this->totalConcentration_[wCompIdx].resize(size_);
182 this->totalConcentration_[nCompIdx].resize(size_);
185 for (
int i = 0; i< problem().gridView().size(0); i++)
187 CellData& cellDataI = problem().variables().cellData(i);
190 this->totalConcentration_[compIdx][i]
191 = cellDataI.totalConcentration(compIdx);
195 if (this->localTimeStepping_)
197 if (this->timeStepData_.size() != size_)
198 this->timeStepData_.resize(size_);
202 int restrictingCell = -1;
204 Dune::FieldVector<Scalar, 2> entries(0.), timestepFlux(0.);
206 for (
const auto& element : elements(problem().gridView()))
209 int globalIdxI = problem().variables().index(element);
210 CellData& cellDataI = problem().variables().cellData(globalIdxI);
212 if(!impet && cellDataI.subdomain()!=2)
216 double sumfactorin = 0;
217 double sumfactorout = 0;
220 const auto isEndIt = problem().gridView().iend(element);
221 for (
auto isIt = problem().gridView().ibegin(element); isIt != isEndIt; ++isIt)
223 const auto& intersection = *isIt;
226 if (intersection.neighbor())
228 if (enableMPFA && intersection.outside().level() != element.level())
229 getMpfaFlux(entries, timestepFlux, isIt, cellDataI);
231 this->getFlux(entries, timestepFlux, intersection, cellDataI);
235 if (intersection.boundary())
237 this->getFluxOnBoundary(entries, timestepFlux, intersection, cellDataI);
240 if (this->localTimeStepping_)
242 int indexInInside = intersection.indexInInside();
244 if (localData.
faceTargetDt[indexInInside] < this->accumulatedDt_ + this->dtThreshold_)
246 localData.
faceFluxes[indexInInside] = entries;
252 updateVec[wCompIdx][globalIdxI] += entries[wCompIdx];
253 updateVec[nCompIdx][globalIdxI] += entries[nCompIdx];
256 sumfactorin += timestepFlux[0];
257 sumfactorout += timestepFlux[1];
261 if (this->localTimeStepping_)
264 for (
int i=0; i < 2*dim; i++)
266 updateVec[wCompIdx][globalIdxI] += localData.
faceFluxes[i][wCompIdx];
267 updateVec[nCompIdx][globalIdxI] += localData.
faceFluxes[i][nCompIdx];
272 PrimaryVariables q(NAN);
273 problem().source(q, element);
274 updateVec[wCompIdx][globalIdxI] += q[contiWEqIdx];
275 updateVec[nCompIdx][globalIdxI] += q[contiNEqIdx];
279 sumfactorin = max(sumfactorin,sumfactorout)
280 / problem().spatialParams().porosity(element);
283 if (this->localTimeStepping_)
285 this->timeStepData_[globalIdxI].dt = 1./sumfactorin;
286 if ( 1./sumfactorin < dt)
289 restrictingCell= globalIdxI;
294 if ( 1./sumfactorin < dt)
297 restrictingCell= globalIdxI;
305 using ElementMapper =
typename SolutionTypes::ElementMapper;
307 for (
int i = 0; i < updateVec.size(); i++)
309 DataHandle dataHandle(problem().variables().elementMapper(), updateVec[i]);
310 problem_.gridView().template communicate<DataHandle>(dataHandle,
311 Dune::InteriorBorder_All_Interface,
312 Dune::ForwardCommunication);
314 dt = problem().gridView().comm().min(dt);
319 Dune::dinfo <<
"Timestep restricted by CellIdx " << restrictingCell <<
" leads to dt = "
320 <<dt * getParam<Scalar>(
"Impet.CFLFactor")<< std::endl;
321 if(this->averagedFaces_ != 0)
322 Dune::dwarn <<
" Averageing done for " << this->averagedFaces_ <<
" faces. "<< std::endl;
344template<
class TypeTag>
346 Dune::FieldVector<Scalar, 2>& timestepFlux,
347 const IntersectionIterator& isIt, CellData& cellDataI)
349 const auto& intersection = *isIt;
354 auto elementI = intersection.inside();
355 int globalIdxI = problem().variables().index(elementI);
358 const GlobalPosition globalPos = elementI.geometry().center();
359 const GlobalPosition& gravity_ = problem().gravity();
361 Scalar volume = elementI.geometry().volume();
364 Scalar pressI = problem().pressureModel().pressure(globalIdxI);
365 Scalar pcI = cellDataI.capillaryPressure();
366 DimMatrix K_I(problem().spatialParams().intrinsicPermeability(elementI));
368 PhaseVector SmobI(0.);
370 SmobI[wPhaseIdx] = max((cellDataI.saturation(wPhaseIdx)
371 - problem().spatialParams().materialLawParams(elementI).swr())
373 SmobI[nPhaseIdx] = max((cellDataI.saturation(nPhaseIdx)
374 - problem().spatialParams().materialLawParams(elementI).snr())
377 Scalar densityWI (0.), densityNWI(0.);
378 densityWI= cellDataI.density(wPhaseIdx);
379 densityNWI = cellDataI.density(nPhaseIdx);
381 PhaseVector potential(0.);
384 auto neighbor = intersection.outside();
385 int globalIdxJ = problem().variables().index(neighbor);
386 CellData& cellDataJ = problem().variables().cellData(globalIdxJ);
389 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
392 GlobalPosition distVec = globalPosNeighbor - globalPos;
394 Scalar dist = distVec.two_norm();
396 GlobalPosition unitDistVec(distVec);
400 Scalar densityWJ (0.), densityNWJ(0.);
401 densityWJ = cellDataJ.density(wPhaseIdx);
402 densityNWJ = cellDataJ.density(nPhaseIdx);
405 double densityW_mean = (densityWI + densityWJ) * 0.5;
406 double densityNW_mean = (densityNWI + densityNWJ) * 0.5;
408 double pressJ = problem().pressureModel().pressure(globalIdxJ);
409 Scalar pcJ = cellDataJ.capillaryPressure();
413 GlobalPosition globalPos3(0.);
415 GlobalPosition globalPos4(0.);
417 TransmissivityMatrix T(0.);
418 TransmissivityMatrix additionalT(0.);
420 GlobalPosition globalPosAdditional3(0.);
421 int globalIdxAdditional3=-1;
422 GlobalPosition globalPosAdditional4(0.);
423 int globalIdxAdditional4=-1;
426 = problem().variables().getMpfaData3D(intersection, T, globalPos3, globalIdx3, globalPos4, globalIdx4 );
427 if (halfedgesStored == 0)
428 halfedgesStored = problem().pressureModel().computeTransmissibilities(isIt,T,
429 globalPos3, globalIdx3, globalPos4, globalIdx4 );
432 Scalar press3 = problem().pressureModel().pressure(globalIdx3);
433 CellData& cellData3 = problem().variables().cellData(globalIdx3);
434 Scalar pc3 = cellData3.capillaryPressure();
435 Scalar press4 = problem().pressureModel().pressure(globalIdx4);
436 CellData& cellData4 = problem().variables().cellData(globalIdx4);
437 Scalar pc4 = cellData4.capillaryPressure();
438 Scalar temp1 = globalPos * gravity_;
439 Scalar temp2 = globalPosNeighbor * gravity_;
440 Scalar temp3 = globalPos3 * gravity_;
441 Scalar temp4 = globalPos4 * gravity_;
444 potential[wPhaseIdx] += (pressI-temp1*densityW_mean) * T[0]
445 +(pressJ-temp2*densityW_mean) * T[1]
446 +(press3- temp3*densityW_mean) * T[2]
447 +(press4- temp4*densityW_mean) * T[3];
448 potential[nPhaseIdx] += (pressI+pcI-temp1*densityNW_mean) * T[0]
449 +(pressJ+pcJ-temp2*densityNW_mean) * T[1]
450 +(press3+pc3- temp3*densityNW_mean) * T[2]
451 +(press4+pc4- temp4*densityNW_mean) * T[3];
453 else if(pressureType==pn)
455 potential[wPhaseIdx] += (pressI-pcI-temp1*densityW_mean) * T[0]
456 + (pressJ-pcJ-temp2*densityW_mean) * T[1]
457 + (press3-pc3- temp3*densityW_mean) * T[2]
458 + (press4-pc4- temp4*densityW_mean) * T[3];
459 potential[nPhaseIdx] += (pressI-temp1*densityNW_mean) * T[0]
460 + (pressJ-temp2*densityNW_mean) * T[1]
461 + (press3-temp3*densityNW_mean) * T[2]
462 + (press4-temp4*densityNW_mean) * T[3];
465 if(halfedgesStored != 1)
467 for(
int banana = 1; banana < halfedgesStored; banana ++)
470 problem().variables().getMpfaData3D(intersection, additionalT,
471 globalPosAdditional3, globalIdxAdditional3,
472 globalPosAdditional4, globalIdxAdditional4 ,
475 Scalar gravityContributionAdditonal
476 = temp1 * additionalT[0] + temp2 * additionalT[1]
477 + globalPosAdditional3*gravity_ * additionalT[2]
478 + globalPosAdditional4*gravity_ * additionalT[3];
479 CellData& cellDataA3 = problem().variables().cellData(globalIdxAdditional3);
480 CellData& cellDataA4 = problem().variables().cellData(globalIdxAdditional4);
484 potential[wPhaseIdx] += pressI * additionalT[0] + pressJ * additionalT[1]
485 +problem().pressureModel().pressure(globalIdxAdditional3) * additionalT[2]
486 +problem().pressureModel().pressure(globalIdxAdditional4)* additionalT[3];
487 potential[nPhaseIdx] += (pressI+pcI) * additionalT[0] + (pressJ+pcJ) * additionalT[1]
488 +(problem().pressureModel().pressure(globalIdxAdditional3)+cellDataA3.capillaryPressure()) * additionalT[2]
489 +(problem().pressureModel().pressure(globalIdxAdditional4)+cellDataA4.capillaryPressure()) * additionalT[3];
491 else if(pressureType==pn)
493 potential[wPhaseIdx] += (pressI-pcI) * additionalT[0] + (pressJ-pcJ) * additionalT[1]
494 + (problem().pressureModel().pressure(globalIdxAdditional3)-cellDataA3.capillaryPressure()) * additionalT[2]
495 + (problem().pressureModel().pressure(globalIdxAdditional4)-cellDataA4.capillaryPressure()) * additionalT[3];
496 potential[nPhaseIdx] += pressI * additionalT[0] + pressJ * additionalT[1]
497 + problem().pressureModel().pressure(globalIdxAdditional3) * additionalT[2]
498 + problem().pressureModel().pressure(globalIdxAdditional4) * additionalT[3];
500 potential[wPhaseIdx] -= gravityContributionAdditonal * densityW_mean;
501 potential[nPhaseIdx] -= gravityContributionAdditonal * densityNW_mean;
506 Dune::FieldVector<bool, NumPhases> doUpwinding(
true);
507 PhaseVector lambda(0.);
508 for(
int phaseIdx = 0; phaseIdx <
NumPhases; phaseIdx++)
511 if(phaseIdx == wPhaseIdx)
512 contiEqIdx = contiWEqIdx;
514 contiEqIdx = contiNEqIdx;
516 if(!this->impet_ or !this->restrictFluxInTransport_)
518 if(potential[phaseIdx] > 0.)
520 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
521 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
true);
523 else if(potential[phaseIdx] < 0.)
525 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
526 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
false);
530 doUpwinding[phaseIdx] =
false;
531 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
false);
532 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiEqIdx,
false);
537 bool cellIwasUpwindCell;
539 if(elementI.level()>neighbor.level())
540 cellIwasUpwindCell = cellDataI.isUpwindCell(intersection.indexInInside(), contiEqIdx);
542 cellIwasUpwindCell = !cellDataJ.isUpwindCell(intersection.indexInOutside(), contiEqIdx);
544 if (potential[phaseIdx] > 0. && cellIwasUpwindCell)
545 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
546 else if (potential[phaseIdx] < 0. && !cellIwasUpwindCell)
547 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
549 else if(this->restrictFluxInTransport_ == 2)
550 doUpwinding[phaseIdx] =
false;
554 if (potential[phaseIdx] > 0. && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellDataJ.mobility(phaseIdx), 0.0, 1.0e-30))
555 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
556 else if (potential[phaseIdx] < 0. && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellDataI.mobility(phaseIdx), 0.0, 1.0e-30))
557 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
559 doUpwinding[phaseIdx] =
false;
563 if(!doUpwinding[phaseIdx])
566 if(cellDataI.mobility(phaseIdx)+cellDataJ.mobility(phaseIdx)==0.)
568 potential[phaseIdx] = 0;
573 fluxEntries[wCompIdx] -= potential[phaseIdx] / volume
574 *
harmonicMean(cellDataI.massFraction(phaseIdx, wCompIdx) * cellDataI.mobility(phaseIdx) * cellDataI.density(phaseIdx),
575 cellDataJ.massFraction(phaseIdx, wCompIdx) * cellDataJ.mobility(phaseIdx) * cellDataJ.density(phaseIdx));
576 fluxEntries[nCompIdx] -= potential[phaseIdx] / volume
577 *
harmonicMean(cellDataI.massFraction(phaseIdx, nCompIdx) * cellDataI.mobility(phaseIdx) * cellDataI.density(phaseIdx),
578 cellDataJ.massFraction(phaseIdx, nCompIdx) * cellDataJ.mobility(phaseIdx) * cellDataJ.density(phaseIdx));
582 timestepFlux[0] += max(0.,
583 - potential[phaseIdx] / volume
584 *
harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx)));
586 timestepFlux[1] += max(0.,
587 potential[phaseIdx] / volume
588 *
harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx))/SmobI[phaseIdx]);
591 this->averagedFaces_++;
592 #if DUNE_MINIMAL_DEBUG_LEVEL < 3
594 if(globalIdxI > globalIdxJ)
595 Dune::dinfo <<
"harmonicMean flux of phase" << phaseIdx <<
" used from cell" << globalIdxI<<
" into " << globalIdxJ
596 <<
" ; TE upwind I = "<< cellIwasUpwindCell <<
" but pot = "<< potential[phaseIdx] << std::endl;
600 potential[phaseIdx] = 0;
607 double velocityJIw = max((-lambda[wPhaseIdx] * potential[wPhaseIdx]) / volume, 0.0);
608 double velocityIJw = max(( lambda[wPhaseIdx] * potential[wPhaseIdx]) / volume, 0.0);
609 double velocityJIn = max((-lambda[nPhaseIdx] * potential[nPhaseIdx]) / volume, 0.0);
610 double velocityIJn = max(( lambda[nPhaseIdx] * potential[nPhaseIdx]) / volume, 0.0);
613 timestepFlux[0] += velocityJIw + velocityJIn;
615 double foutw = velocityIJw/SmobI[wPhaseIdx];
616 double foutn = velocityIJn/SmobI[nPhaseIdx];
619 if (isnan(foutw) || isinf(foutw) || foutw < 0) foutw = 0;
620 if (isnan(foutn) || isinf(foutn) || foutn < 0) foutn = 0;
621 timestepFlux[1] += foutw + foutn;
623 fluxEntries[wCompIdx] +=
624 velocityJIw * cellDataJ.massFraction(wPhaseIdx, wCompIdx) * densityWJ
625 - velocityIJw * cellDataI.massFraction(wPhaseIdx, wCompIdx) * densityWI
626 + velocityJIn * cellDataJ.massFraction(nPhaseIdx, wCompIdx) * densityNWJ
627 - velocityIJn * cellDataI.massFraction(nPhaseIdx, wCompIdx) * densityNWI;
628 fluxEntries[nCompIdx] +=
629 velocityJIw * cellDataJ.massFraction(wPhaseIdx, nCompIdx) * densityWJ
630 - velocityIJw * cellDataI.massFraction(wPhaseIdx, nCompIdx) * densityWI
631 + velocityJIn * cellDataJ.massFraction(nPhaseIdx, nCompIdx) * densityNWJ
632 - velocityIJn * cellDataI.massFraction(nPhaseIdx, nCompIdx) * densityNWI;
#define GET_PROP_VALUE(TypeTag, PropTagName)
Definition: propertysystemmacros.hh:282
#define GET_PROP(TypeTag, PropTagName)
Definition: propertysystemmacros.hh:281
#define GET_PROP_TYPE(TypeTag, PropTagName)
Definition: propertysystemmacros.hh:283
Define some often used mathematical functions.
Contains a class to exchange entries of a vector.
Defines the properties required for the adaptive sequential 2p2c models.
Finite volume discretization of the component transport equation.
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
make the local view function available whenever we use the grid geometry
Definition: adapt.hh:29
Property tag NumComponents
Number of components in the system.
Definition: porousmediumflow/sequential/properties.hh:70
Property tag NumPhases
Number of phases in the system.
Definition: porousmediumflow/sequential/properties.hh:69
Property tag SolutionTypes
Definition: porousmediumflow/sequential/properties.hh:58
A data handle class to exchange entries of a vector.
Definition: vectorexchange.hh:40
Compositional transport step in a finite volume discretization.
Definition: fv3dtransportadaptive.hh:54
virtual void update(const Scalar t, Scalar &dt, TransportSolutionType &updateVec, bool impes=false)
Calculate the update vector and determine timestep size.
Definition: fv3dtransportadaptive.hh:162
static const int pressureType
ā€¨Specifies if the MPFA is used on hanging nodes
Definition: fv3dtransportadaptive.hh:138
FV3dTransport2P2CAdaptive(Problem &problem)
Constructs a FV3dTransport2P2CAdaptive object.
Definition: fv3dtransportadaptive.hh:122
Problem & problem_
Definition: fv3dtransportadaptive.hh:133
void getMpfaFlux(Dune::FieldVector< Scalar, 2 > &, Dune::FieldVector< Scalar, 2 > &, const IntersectionIterator &, CellData &)
Compute flux over an irregular interface using a mpfa method.
Definition: fv3dtransportadaptive.hh:345
virtual ~FV3dTransport2P2CAdaptive()
Definition: fv3dtransportadaptive.hh:128
bool enableMPFA
Definition: fv3dtransportadaptive.hh:135
Compositional transport step in a Finite Volume discretization.
Definition: fvtransport.hh:60
Definition: fvtransport.hh:113
Dune::FieldVector< EntryType, 2 *dim > faceFluxes
Definition: fvtransport.hh:114
Dune::FieldVector< Scalar, 2 *dim > faceTargetDt
Definition: fvtransport.hh:115