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>
73 dim = GridView::dimension, dimWorld = GridView::dimensionworld,
74 NumPhases = getPropValue<TypeTag, Properties::NumPhases>()
78 pw = Indices::pressureW,
79 pn = Indices::pressureN,
80 Sw = Indices::saturationW,
81 Sn = Indices::saturationN
85 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
86 wCompIdx = Indices::wPhaseIdx, nCompIdx = Indices::nPhaseIdx,
87 contiWEqIdx=Indices::contiWEqIdx, contiNEqIdx=Indices::contiNEqIdx
90 using Element =
typename GridView::Traits::template Codim<0>::Entity;
91 using Grid =
typename GridView::Grid;
92 using Intersection =
typename GridView::Intersection;
93 using IntersectionIterator =
typename GridView::IntersectionIterator;
95 using TransmissivityMatrix = Dune::FieldVector<Scalar,dim+1>;
96 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
97 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
98 using PhaseVector = Dune::FieldVector<Scalar, NumPhases>;
106 virtual void update(
const Scalar t, Scalar& dt, TransportSolutionType& updateVec,
109 void getMpfaFlux(Dune::FieldVector<Scalar, 2>&, Dune::FieldVector<Scalar, 2>&,
110 const IntersectionIterator&, CellData&);
124 enableMPFA = getParam<bool>(
"GridAdapt.EnableMultiPointFluxApproximation");
137 static const int pressureType = getPropValue<TypeTag, Properties::PressureFormulation>();
160template<
class TypeTag>
162 TransportSolutionType& updateVec,
bool impet)
164 this->impet_ = impet;
168 this->averagedFaces_ = 0;
171 int size_ = problem_.gridView().size(0);
172 updateVec.resize(getPropValue<TypeTag, Properties::NumComponents>());
173 updateVec[wCompIdx].resize(size_);
174 updateVec[nCompIdx].resize(size_);
175 updateVec[wCompIdx] = 0;
176 updateVec[nCompIdx] = 0;
178 if(this->totalConcentration_.size() != size_)
180 this->totalConcentration_[wCompIdx].resize(size_);
181 this->totalConcentration_[nCompIdx].resize(size_);
184 for (
int i = 0; i< problem().gridView().size(0); i++)
186 CellData& cellDataI = problem().variables().cellData(i);
187 for(
int compIdx = 0; compIdx < getPropValue<TypeTag, Properties::NumComponents>(); compIdx++)
189 this->totalConcentration_[compIdx][i]
190 = cellDataI.totalConcentration(compIdx);
194 if (this->localTimeStepping_)
196 if (this->timeStepData_.size() != size_)
197 this->timeStepData_.resize(size_);
201 int restrictingCell = -1;
203 Dune::FieldVector<Scalar, 2> entries(0.), timestepFlux(0.);
205 for (
const auto& element : elements(problem().gridView()))
208 int globalIdxI = problem().variables().index(element);
209 CellData& cellDataI = problem().variables().cellData(globalIdxI);
211 if(!impet && cellDataI.subdomain()!=2)
215 double sumfactorin = 0;
216 double sumfactorout = 0;
219 const auto isEndIt = problem().gridView().iend(element);
220 for (
auto isIt = problem().gridView().ibegin(element); isIt != isEndIt; ++isIt)
222 const auto& intersection = *isIt;
225 if (intersection.neighbor())
227 if (enableMPFA && intersection.outside().level() != element.level())
228 getMpfaFlux(entries, timestepFlux, isIt, cellDataI);
230 this->getFlux(entries, timestepFlux, intersection, cellDataI);
234 if (intersection.boundary())
236 this->getFluxOnBoundary(entries, timestepFlux, intersection, cellDataI);
239 if (this->localTimeStepping_)
241 int indexInInside = intersection.indexInInside();
243 if (localData.
faceTargetDt[indexInInside] < this->accumulatedDt_ + this->dtThreshold_)
245 localData.
faceFluxes[indexInInside] = entries;
251 updateVec[wCompIdx][globalIdxI] += entries[wCompIdx];
252 updateVec[nCompIdx][globalIdxI] += entries[nCompIdx];
255 sumfactorin += timestepFlux[0];
256 sumfactorout += timestepFlux[1];
260 if (this->localTimeStepping_)
263 for (
int i=0; i < 2*dim; i++)
265 updateVec[wCompIdx][globalIdxI] += localData.
faceFluxes[i][wCompIdx];
266 updateVec[nCompIdx][globalIdxI] += localData.
faceFluxes[i][nCompIdx];
271 PrimaryVariables q(NAN);
272 problem().source(q, element);
273 updateVec[wCompIdx][globalIdxI] += q[contiWEqIdx];
274 updateVec[nCompIdx][globalIdxI] += q[contiNEqIdx];
278 sumfactorin = max(sumfactorin,sumfactorout)
279 / problem().spatialParams().porosity(element);
282 if (this->localTimeStepping_)
284 this->timeStepData_[globalIdxI].dt = 1./sumfactorin;
285 if ( 1./sumfactorin < dt)
288 restrictingCell= globalIdxI;
293 if ( 1./sumfactorin < dt)
296 restrictingCell= globalIdxI;
304 using ElementMapper =
typename SolutionTypes::ElementMapper;
306 for (
int i = 0; i < updateVec.size(); i++)
308 DataHandle dataHandle(problem().variables().elementMapper(), updateVec[i]);
309 problem_.gridView().template communicate<DataHandle>(dataHandle,
310 Dune::InteriorBorder_All_Interface,
311 Dune::ForwardCommunication);
313 dt = problem().gridView().comm().min(dt);
318 Dune::dinfo <<
"Timestep restricted by CellIdx " << restrictingCell <<
" leads to dt = "
319 <<dt * getParam<Scalar>(
"Impet.CFLFactor")<< std::endl;
320 if(this->averagedFaces_ != 0)
321 Dune::dwarn <<
" Averageing done for " << this->averagedFaces_ <<
" faces. "<< std::endl;
343template<
class TypeTag>
345 Dune::FieldVector<Scalar, 2>& timestepFlux,
346 const IntersectionIterator& isIt, CellData& cellDataI)
348 const auto& intersection = *isIt;
353 auto elementI = intersection.inside();
354 int globalIdxI = problem().variables().index(elementI);
357 const GlobalPosition globalPos = elementI.geometry().center();
358 const GlobalPosition& gravity_ = problem().gravity();
360 Scalar
volume = elementI.geometry().volume();
363 Scalar pressI = problem().pressureModel().pressure(globalIdxI);
364 Scalar pcI = cellDataI.capillaryPressure();
366 const auto fluidMatrixInteraction = problem().spatialParams().fluidMatrixInteractionAtPos(elementI.geometry().center());
368 PhaseVector SmobI(0.);
370 SmobI[wPhaseIdx] = max((cellDataI.saturation(wPhaseIdx)
371 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().swr())
373 SmobI[nPhaseIdx] = max((cellDataI.saturation(nPhaseIdx)
374 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().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;
Contains a class to exchange entries of a vector.
Finite volume discretization of the component transport equation.
Defines the properties required for the adaptive sequential 2p2c models.
Define some often used mathematical functions.
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:69
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type GetProp
get the type of a property
Definition: propertysystem.hh:141
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
Scalar volume(Shape shape, Scalar inscribedRadius)
Returns the volume of a given geometry based on the inscribed radius.
Definition: poreproperties.hh:73
A data handle class to exchange entries of a vector.
Definition: vectorcommdatahandle.hh:78
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:161
static const int pressureType
‍Specifies if the MPFA is used on hanging nodes
Definition: fv3dtransportadaptive.hh:137
FV3dTransport2P2CAdaptive(Problem &problem)
Constructs a FV3dTransport2P2CAdaptive object.
Definition: fv3dtransportadaptive.hh:121
Problem & problem_
Definition: fv3dtransportadaptive.hh:132
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:344
virtual ~FV3dTransport2P2CAdaptive()
Definition: fv3dtransportadaptive.hh:127
bool enableMPFA
Definition: fv3dtransportadaptive.hh:134
Compositional transport step in a Finite Volume discretization.
Definition: fvtransport.hh:60
Definition: fvtransport.hh:112
Dune::FieldVector< EntryType, 2 *dim > faceFluxes
Definition: fvtransport.hh:113
Dune::FieldVector< Scalar, 2 *dim > faceTargetDt
Definition: fvtransport.hh:114