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>
60 using MaterialLaw =
typename SpatialParams::MaterialLaw;
74 dim = GridView::dimension, dimWorld = GridView::dimensionworld,
75 NumPhases = getPropValue<TypeTag, Properties::NumPhases>()
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>;
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");
138 static const int pressureType = getPropValue<TypeTag, Properties::PressureFormulation>();
161template<
class TypeTag>
163 TransportSolutionType& updateVec,
bool impet)
165 this->impet_ = impet;
169 this->averagedFaces_ = 0;
172 int size_ = problem_.gridView().size(0);
173 updateVec.resize(getPropValue<TypeTag, Properties::NumComponents>());
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);
188 for(
int compIdx = 0; compIdx < getPropValue<TypeTag, Properties::NumComponents>(); compIdx++)
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();
367 PhaseVector SmobI(0.);
369 SmobI[wPhaseIdx] = max((cellDataI.saturation(wPhaseIdx)
370 - problem().spatialParams().materialLawParams(elementI).swr())
372 SmobI[nPhaseIdx] = max((cellDataI.saturation(nPhaseIdx)
373 - problem().spatialParams().materialLawParams(elementI).snr())
376 Scalar densityWI (0.), densityNWI(0.);
377 densityWI= cellDataI.density(wPhaseIdx);
378 densityNWI = cellDataI.density(nPhaseIdx);
380 PhaseVector potential(0.);
383 auto neighbor = intersection.outside();
384 int globalIdxJ = problem().variables().index(neighbor);
385 CellData& cellDataJ = problem().variables().cellData(globalIdxJ);
388 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
391 GlobalPosition distVec = globalPosNeighbor - globalPos;
393 Scalar dist = distVec.two_norm();
395 GlobalPosition unitDistVec(distVec);
399 Scalar densityWJ (0.), densityNWJ(0.);
400 densityWJ = cellDataJ.density(wPhaseIdx);
401 densityNWJ = cellDataJ.density(nPhaseIdx);
404 double densityW_mean = (densityWI + densityWJ) * 0.5;
405 double densityNW_mean = (densityNWI + densityNWJ) * 0.5;
407 double pressJ = problem().pressureModel().pressure(globalIdxJ);
408 Scalar pcJ = cellDataJ.capillaryPressure();
412 GlobalPosition globalPos3(0.);
414 GlobalPosition globalPos4(0.);
416 TransmissivityMatrix T(0.);
417 TransmissivityMatrix additionalT(0.);
419 GlobalPosition globalPosAdditional3(0.);
420 int globalIdxAdditional3=-1;
421 GlobalPosition globalPosAdditional4(0.);
422 int globalIdxAdditional4=-1;
425 = problem().variables().getMpfaData3D(intersection, T, globalPos3, globalIdx3, globalPos4, globalIdx4 );
426 if (halfedgesStored == 0)
427 halfedgesStored = problem().pressureModel().computeTransmissibilities(isIt,T,
428 globalPos3, globalIdx3, globalPos4, globalIdx4 );
431 Scalar press3 = problem().pressureModel().pressure(globalIdx3);
432 CellData& cellData3 = problem().variables().cellData(globalIdx3);
433 Scalar pc3 = cellData3.capillaryPressure();
434 Scalar press4 = problem().pressureModel().pressure(globalIdx4);
435 CellData& cellData4 = problem().variables().cellData(globalIdx4);
436 Scalar pc4 = cellData4.capillaryPressure();
437 Scalar temp1 = globalPos * gravity_;
438 Scalar temp2 = globalPosNeighbor * gravity_;
439 Scalar temp3 = globalPos3 * gravity_;
440 Scalar temp4 = globalPos4 * gravity_;
443 potential[wPhaseIdx] += (pressI-temp1*densityW_mean) * T[0]
444 +(pressJ-temp2*densityW_mean) * T[1]
445 +(press3- temp3*densityW_mean) * T[2]
446 +(press4- temp4*densityW_mean) * T[3];
447 potential[nPhaseIdx] += (pressI+pcI-temp1*densityNW_mean) * T[0]
448 +(pressJ+pcJ-temp2*densityNW_mean) * T[1]
449 +(press3+pc3- temp3*densityNW_mean) * T[2]
450 +(press4+pc4- temp4*densityNW_mean) * T[3];
452 else if(pressureType==pn)
454 potential[wPhaseIdx] += (pressI-pcI-temp1*densityW_mean) * T[0]
455 + (pressJ-pcJ-temp2*densityW_mean) * T[1]
456 + (press3-pc3- temp3*densityW_mean) * T[2]
457 + (press4-pc4- temp4*densityW_mean) * T[3];
458 potential[nPhaseIdx] += (pressI-temp1*densityNW_mean) * T[0]
459 + (pressJ-temp2*densityNW_mean) * T[1]
460 + (press3-temp3*densityNW_mean) * T[2]
461 + (press4-temp4*densityNW_mean) * T[3];
464 if(halfedgesStored != 1)
466 for(
int banana = 1; banana < halfedgesStored; banana ++)
469 problem().variables().getMpfaData3D(intersection, additionalT,
470 globalPosAdditional3, globalIdxAdditional3,
471 globalPosAdditional4, globalIdxAdditional4 ,
474 Scalar gravityContributionAdditonal
475 = temp1 * additionalT[0] + temp2 * additionalT[1]
476 + globalPosAdditional3*gravity_ * additionalT[2]
477 + globalPosAdditional4*gravity_ * additionalT[3];
478 CellData& cellDataA3 = problem().variables().cellData(globalIdxAdditional3);
479 CellData& cellDataA4 = problem().variables().cellData(globalIdxAdditional4);
483 potential[wPhaseIdx] += pressI * additionalT[0] + pressJ * additionalT[1]
484 +problem().pressureModel().pressure(globalIdxAdditional3) * additionalT[2]
485 +problem().pressureModel().pressure(globalIdxAdditional4)* additionalT[3];
486 potential[nPhaseIdx] += (pressI+pcI) * additionalT[0] + (pressJ+pcJ) * additionalT[1]
487 +(problem().pressureModel().pressure(globalIdxAdditional3)+cellDataA3.capillaryPressure()) * additionalT[2]
488 +(problem().pressureModel().pressure(globalIdxAdditional4)+cellDataA4.capillaryPressure()) * additionalT[3];
490 else if(pressureType==pn)
492 potential[wPhaseIdx] += (pressI-pcI) * additionalT[0] + (pressJ-pcJ) * additionalT[1]
493 + (problem().pressureModel().pressure(globalIdxAdditional3)-cellDataA3.capillaryPressure()) * additionalT[2]
494 + (problem().pressureModel().pressure(globalIdxAdditional4)-cellDataA4.capillaryPressure()) * additionalT[3];
495 potential[nPhaseIdx] += pressI * additionalT[0] + pressJ * additionalT[1]
496 + problem().pressureModel().pressure(globalIdxAdditional3) * additionalT[2]
497 + problem().pressureModel().pressure(globalIdxAdditional4) * additionalT[3];
499 potential[wPhaseIdx] -= gravityContributionAdditonal * densityW_mean;
500 potential[nPhaseIdx] -= gravityContributionAdditonal * densityNW_mean;
505 Dune::FieldVector<bool, NumPhases> doUpwinding(
true);
506 PhaseVector lambda(0.);
507 for(
int phaseIdx = 0; phaseIdx < NumPhases; phaseIdx++)
510 if(phaseIdx == wPhaseIdx)
511 contiEqIdx = contiWEqIdx;
513 contiEqIdx = contiNEqIdx;
515 if(!this->impet_ or !this->restrictFluxInTransport_)
517 if(potential[phaseIdx] > 0.)
519 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
520 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
true);
522 else if(potential[phaseIdx] < 0.)
524 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
525 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
false);
529 doUpwinding[phaseIdx] =
false;
530 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
false);
531 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiEqIdx,
false);
536 bool cellIwasUpwindCell;
538 if(elementI.level()>neighbor.level())
539 cellIwasUpwindCell = cellDataI.isUpwindCell(intersection.indexInInside(), contiEqIdx);
541 cellIwasUpwindCell = !cellDataJ.isUpwindCell(intersection.indexInOutside(), contiEqIdx);
543 if (potential[phaseIdx] > 0. && cellIwasUpwindCell)
544 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
545 else if (potential[phaseIdx] < 0. && !cellIwasUpwindCell)
546 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
548 else if(this->restrictFluxInTransport_ == 2)
549 doUpwinding[phaseIdx] =
false;
553 if (potential[phaseIdx] > 0. && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellDataJ.mobility(phaseIdx), 0.0, 1.0e-30))
554 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
555 else if (potential[phaseIdx] < 0. && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellDataI.mobility(phaseIdx), 0.0, 1.0e-30))
556 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
558 doUpwinding[phaseIdx] =
false;
562 if(!doUpwinding[phaseIdx])
565 if(cellDataI.mobility(phaseIdx)+cellDataJ.mobility(phaseIdx)==0.)
567 potential[phaseIdx] = 0;
572 fluxEntries[wCompIdx] -= potential[phaseIdx] / volume
573 *
harmonicMean(cellDataI.massFraction(phaseIdx, wCompIdx) * cellDataI.mobility(phaseIdx) * cellDataI.density(phaseIdx),
574 cellDataJ.massFraction(phaseIdx, wCompIdx) * cellDataJ.mobility(phaseIdx) * cellDataJ.density(phaseIdx));
575 fluxEntries[nCompIdx] -= potential[phaseIdx] / volume
576 *
harmonicMean(cellDataI.massFraction(phaseIdx, nCompIdx) * cellDataI.mobility(phaseIdx) * cellDataI.density(phaseIdx),
577 cellDataJ.massFraction(phaseIdx, nCompIdx) * cellDataJ.mobility(phaseIdx) * cellDataJ.density(phaseIdx));
581 timestepFlux[0] += max(0.,
582 - potential[phaseIdx] / volume
583 *
harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx)));
585 timestepFlux[1] += max(0.,
586 potential[phaseIdx] / volume
587 *
harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx))/SmobI[phaseIdx]);
590 this->averagedFaces_++;
591 #if DUNE_MINIMAL_DEBUG_LEVEL < 3
593 if(globalIdxI > globalIdxJ)
594 Dune::dinfo <<
"harmonicMean flux of phase" << phaseIdx <<
" used from cell" << globalIdxI<<
" into " << globalIdxJ
595 <<
" ; TE upwind I = "<< cellIwasUpwindCell <<
" but pot = "<< potential[phaseIdx] << std::endl;
599 potential[phaseIdx] = 0;
606 double velocityJIw = max((-lambda[wPhaseIdx] * potential[wPhaseIdx]) / volume, 0.0);
607 double velocityIJw = max(( lambda[wPhaseIdx] * potential[wPhaseIdx]) / volume, 0.0);
608 double velocityJIn = max((-lambda[nPhaseIdx] * potential[nPhaseIdx]) / volume, 0.0);
609 double velocityIJn = max(( lambda[nPhaseIdx] * potential[nPhaseIdx]) / volume, 0.0);
612 timestepFlux[0] += velocityJIw + velocityJIn;
614 double foutw = velocityIJw/SmobI[wPhaseIdx];
615 double foutn = velocityIJn/SmobI[nPhaseIdx];
618 if (isnan(foutw) || isinf(foutw) || foutw < 0) foutw = 0;
619 if (isnan(foutn) || isinf(foutn) || foutn < 0) foutn = 0;
620 timestepFlux[1] += foutw + foutn;
622 fluxEntries[wCompIdx] +=
623 velocityJIw * cellDataJ.massFraction(wPhaseIdx, wCompIdx) * densityWJ
624 - velocityIJw * cellDataI.massFraction(wPhaseIdx, wCompIdx) * densityWI
625 + velocityJIn * cellDataJ.massFraction(nPhaseIdx, wCompIdx) * densityNWJ
626 - velocityIJn * cellDataI.massFraction(nPhaseIdx, wCompIdx) * densityNWI;
627 fluxEntries[nCompIdx] +=
628 velocityJIw * cellDataJ.massFraction(wPhaseIdx, nCompIdx) * densityWJ
629 - velocityIJw * cellDataI.massFraction(wPhaseIdx, nCompIdx) * densityWI
630 + velocityJIn * cellDataJ.massFraction(nPhaseIdx, nCompIdx) * densityNWJ
631 - velocityIJn * cellDataI.massFraction(nPhaseIdx, nCompIdx) * densityNWI;
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.
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:68
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
A data handle class to exchange entries of a vector.
Definition: vectorcommdatahandle.hh:79
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