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>
54template<
class TypeTag>
75 dim = GridView::dimension, dimWorld = GridView::dimensionworld,
76 NumPhases = getPropValue<TypeTag, Properties::NumPhases>()
80 pw = Indices::pressureW,
81 pn = Indices::pressureN,
82 Sw = Indices::saturationW,
83 Sn = Indices::saturationN
87 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
88 wCompIdx = Indices::wPhaseIdx, nCompIdx = Indices::nPhaseIdx,
89 contiWEqIdx=Indices::contiWEqIdx, contiNEqIdx=Indices::contiNEqIdx
92 using Element =
typename GridView::Traits::template Codim<0>::Entity;
93 using Grid =
typename GridView::Grid;
94 using Intersection =
typename GridView::Intersection;
95 using IntersectionIterator =
typename GridView::IntersectionIterator;
97 using TransmissivityMatrix = Dune::FieldVector<Scalar,dim+1>;
98 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
99 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
100 using PhaseVector = Dune::FieldVector<Scalar, NumPhases>;
108 virtual void update(
const Scalar t, Scalar& dt, TransportSolutionType& updateVec,
111 void getMpfaFlux(Dune::FieldVector<Scalar, 2>&, Dune::FieldVector<Scalar, 2>&,
112 const IntersectionIterator&, CellData&);
126 enableMPFA = getParam<bool>(
"GridAdapt.EnableMultiPointFluxApproximation");
139 static const int pressureType = getPropValue<TypeTag, Properties::PressureFormulation>();
162template<
class TypeTag>
164 TransportSolutionType& updateVec,
bool impet)
166 this->impet_ = impet;
170 this->averagedFaces_ = 0;
173 int size_ = problem_.gridView().size(0);
174 updateVec.resize(getPropValue<TypeTag, Properties::NumComponents>());
175 updateVec[wCompIdx].resize(size_);
176 updateVec[nCompIdx].resize(size_);
177 updateVec[wCompIdx] = 0;
178 updateVec[nCompIdx] = 0;
180 if(this->totalConcentration_.size() != size_)
182 this->totalConcentration_[wCompIdx].resize(size_);
183 this->totalConcentration_[nCompIdx].resize(size_);
186 for (
int i = 0; i< problem().gridView().size(0); i++)
188 CellData& cellDataI = problem().variables().cellData(i);
189 for(
int compIdx = 0; compIdx < getPropValue<TypeTag, Properties::NumComponents>(); compIdx++)
191 this->totalConcentration_[compIdx][i]
192 = cellDataI.totalConcentration(compIdx);
196 if (this->localTimeStepping_)
198 if (this->timeStepData_.size() != size_)
199 this->timeStepData_.resize(size_);
203 int restrictingCell = -1;
205 Dune::FieldVector<Scalar, 2> entries(0.), timestepFlux(0.);
207 for (
const auto& element : elements(problem().gridView()))
210 int globalIdxI = problem().variables().index(element);
211 CellData& cellDataI = problem().variables().cellData(globalIdxI);
213 if(!impet && cellDataI.subdomain()!=2)
217 double sumfactorin = 0;
218 double sumfactorout = 0;
221 const auto isEndIt = problem().gridView().iend(element);
222 for (
auto isIt = problem().gridView().ibegin(element); isIt != isEndIt; ++isIt)
224 const auto& intersection = *isIt;
227 if (intersection.neighbor())
229 if (enableMPFA && intersection.outside().level() != element.level())
230 getMpfaFlux(entries, timestepFlux, isIt, cellDataI);
232 this->getFlux(entries, timestepFlux, intersection, cellDataI);
236 if (intersection.boundary())
238 this->getFluxOnBoundary(entries, timestepFlux, intersection, cellDataI);
241 if (this->localTimeStepping_)
243 int indexInInside = intersection.indexInInside();
245 if (localData.
faceTargetDt[indexInInside] < this->accumulatedDt_ + this->dtThreshold_)
247 localData.
faceFluxes[indexInInside] = entries;
253 updateVec[wCompIdx][globalIdxI] += entries[wCompIdx];
254 updateVec[nCompIdx][globalIdxI] += entries[nCompIdx];
257 sumfactorin += timestepFlux[0];
258 sumfactorout += timestepFlux[1];
262 if (this->localTimeStepping_)
265 for (
int i=0; i < 2*dim; i++)
267 updateVec[wCompIdx][globalIdxI] += localData.
faceFluxes[i][wCompIdx];
268 updateVec[nCompIdx][globalIdxI] += localData.
faceFluxes[i][nCompIdx];
273 PrimaryVariables q(NAN);
274 problem().source(q, element);
275 updateVec[wCompIdx][globalIdxI] += q[contiWEqIdx];
276 updateVec[nCompIdx][globalIdxI] += q[contiNEqIdx];
280 sumfactorin = max(sumfactorin,sumfactorout)
281 / problem().spatialParams().porosity(element);
284 if (this->localTimeStepping_)
286 this->timeStepData_[globalIdxI].dt = 1./sumfactorin;
287 if ( 1./sumfactorin < dt)
290 restrictingCell= globalIdxI;
295 if ( 1./sumfactorin < dt)
298 restrictingCell= globalIdxI;
306 using ElementMapper =
typename SolutionTypes::ElementMapper;
308 for (
int i = 0; i < updateVec.size(); i++)
310 DataHandle dataHandle(problem().variables().elementMapper(), updateVec[i]);
311 problem_.gridView().template communicate<DataHandle>(dataHandle,
312 Dune::InteriorBorder_All_Interface,
313 Dune::ForwardCommunication);
315 dt = problem().gridView().comm().min(dt);
320 Dune::dinfo <<
"Timestep restricted by CellIdx " << restrictingCell <<
" leads to dt = "
321 <<dt * getParam<Scalar>(
"Impet.CFLFactor")<< std::endl;
322 if(this->averagedFaces_ != 0)
323 Dune::dwarn <<
" Averageing done for " << this->averagedFaces_ <<
" faces. "<< std::endl;
345template<
class TypeTag>
347 Dune::FieldVector<Scalar, 2>& timestepFlux,
348 const IntersectionIterator& isIt, CellData& cellDataI)
350 const auto& intersection = *isIt;
355 auto elementI = intersection.inside();
356 int globalIdxI = problem().variables().index(elementI);
359 const GlobalPosition globalPos = elementI.geometry().center();
360 const GlobalPosition& gravity_ = problem().gravity();
362 Scalar volume = elementI.geometry().volume();
365 Scalar pressI = problem().pressureModel().pressure(globalIdxI);
366 Scalar pcI = cellDataI.capillaryPressure();
371 const auto fluidMatrixInteraction = Deprecated::makePcKrSw(Scalar{}, problem().spatialParams(), elementI);
373 PhaseVector SmobI(0.);
375 SmobI[wPhaseIdx] = max((cellDataI.saturation(wPhaseIdx)
376 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().swr())
378 SmobI[nPhaseIdx] = max((cellDataI.saturation(nPhaseIdx)
379 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().snr())
382 Scalar densityWI (0.), densityNWI(0.);
383 densityWI= cellDataI.density(wPhaseIdx);
384 densityNWI = cellDataI.density(nPhaseIdx);
386 PhaseVector potential(0.);
389 auto neighbor = intersection.outside();
390 int globalIdxJ = problem().variables().index(neighbor);
391 CellData& cellDataJ = problem().variables().cellData(globalIdxJ);
394 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
397 GlobalPosition distVec = globalPosNeighbor - globalPos;
399 Scalar dist = distVec.two_norm();
401 GlobalPosition unitDistVec(distVec);
405 Scalar densityWJ (0.), densityNWJ(0.);
406 densityWJ = cellDataJ.density(wPhaseIdx);
407 densityNWJ = cellDataJ.density(nPhaseIdx);
410 double densityW_mean = (densityWI + densityWJ) * 0.5;
411 double densityNW_mean = (densityNWI + densityNWJ) * 0.5;
413 double pressJ = problem().pressureModel().pressure(globalIdxJ);
414 Scalar pcJ = cellDataJ.capillaryPressure();
418 GlobalPosition globalPos3(0.);
420 GlobalPosition globalPos4(0.);
422 TransmissivityMatrix T(0.);
423 TransmissivityMatrix additionalT(0.);
425 GlobalPosition globalPosAdditional3(0.);
426 int globalIdxAdditional3=-1;
427 GlobalPosition globalPosAdditional4(0.);
428 int globalIdxAdditional4=-1;
431 = problem().variables().getMpfaData3D(intersection, T, globalPos3, globalIdx3, globalPos4, globalIdx4 );
432 if (halfedgesStored == 0)
433 halfedgesStored = problem().pressureModel().computeTransmissibilities(isIt,T,
434 globalPos3, globalIdx3, globalPos4, globalIdx4 );
437 Scalar press3 = problem().pressureModel().pressure(globalIdx3);
438 CellData& cellData3 = problem().variables().cellData(globalIdx3);
439 Scalar pc3 = cellData3.capillaryPressure();
440 Scalar press4 = problem().pressureModel().pressure(globalIdx4);
441 CellData& cellData4 = problem().variables().cellData(globalIdx4);
442 Scalar pc4 = cellData4.capillaryPressure();
443 Scalar temp1 = globalPos * gravity_;
444 Scalar temp2 = globalPosNeighbor * gravity_;
445 Scalar temp3 = globalPos3 * gravity_;
446 Scalar temp4 = globalPos4 * gravity_;
449 potential[wPhaseIdx] += (pressI-temp1*densityW_mean) * T[0]
450 +(pressJ-temp2*densityW_mean) * T[1]
451 +(press3- temp3*densityW_mean) * T[2]
452 +(press4- temp4*densityW_mean) * T[3];
453 potential[nPhaseIdx] += (pressI+pcI-temp1*densityNW_mean) * T[0]
454 +(pressJ+pcJ-temp2*densityNW_mean) * T[1]
455 +(press3+pc3- temp3*densityNW_mean) * T[2]
456 +(press4+pc4- temp4*densityNW_mean) * T[3];
458 else if(pressureType==pn)
460 potential[wPhaseIdx] += (pressI-pcI-temp1*densityW_mean) * T[0]
461 + (pressJ-pcJ-temp2*densityW_mean) * T[1]
462 + (press3-pc3- temp3*densityW_mean) * T[2]
463 + (press4-pc4- temp4*densityW_mean) * T[3];
464 potential[nPhaseIdx] += (pressI-temp1*densityNW_mean) * T[0]
465 + (pressJ-temp2*densityNW_mean) * T[1]
466 + (press3-temp3*densityNW_mean) * T[2]
467 + (press4-temp4*densityNW_mean) * T[3];
470 if(halfedgesStored != 1)
472 for(
int banana = 1; banana < halfedgesStored; banana ++)
475 problem().variables().getMpfaData3D(intersection, additionalT,
476 globalPosAdditional3, globalIdxAdditional3,
477 globalPosAdditional4, globalIdxAdditional4 ,
480 Scalar gravityContributionAdditonal
481 = temp1 * additionalT[0] + temp2 * additionalT[1]
482 + globalPosAdditional3*gravity_ * additionalT[2]
483 + globalPosAdditional4*gravity_ * additionalT[3];
484 CellData& cellDataA3 = problem().variables().cellData(globalIdxAdditional3);
485 CellData& cellDataA4 = problem().variables().cellData(globalIdxAdditional4);
489 potential[wPhaseIdx] += pressI * additionalT[0] + pressJ * additionalT[1]
490 +problem().pressureModel().pressure(globalIdxAdditional3) * additionalT[2]
491 +problem().pressureModel().pressure(globalIdxAdditional4)* additionalT[3];
492 potential[nPhaseIdx] += (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];
496 else if(pressureType==pn)
498 potential[wPhaseIdx] += (pressI-pcI) * additionalT[0] + (pressJ-pcJ) * additionalT[1]
499 + (problem().pressureModel().pressure(globalIdxAdditional3)-cellDataA3.capillaryPressure()) * additionalT[2]
500 + (problem().pressureModel().pressure(globalIdxAdditional4)-cellDataA4.capillaryPressure()) * additionalT[3];
501 potential[nPhaseIdx] += pressI * additionalT[0] + pressJ * additionalT[1]
502 + problem().pressureModel().pressure(globalIdxAdditional3) * additionalT[2]
503 + problem().pressureModel().pressure(globalIdxAdditional4) * additionalT[3];
505 potential[wPhaseIdx] -= gravityContributionAdditonal * densityW_mean;
506 potential[nPhaseIdx] -= gravityContributionAdditonal * densityNW_mean;
511 Dune::FieldVector<bool, NumPhases> doUpwinding(
true);
512 PhaseVector lambda(0.);
513 for(
int phaseIdx = 0; phaseIdx < NumPhases; phaseIdx++)
516 if(phaseIdx == wPhaseIdx)
517 contiEqIdx = contiWEqIdx;
519 contiEqIdx = contiNEqIdx;
521 if(!this->impet_ or !this->restrictFluxInTransport_)
523 if(potential[phaseIdx] > 0.)
525 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
526 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
true);
528 else if(potential[phaseIdx] < 0.)
530 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
531 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
false);
535 doUpwinding[phaseIdx] =
false;
536 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx,
false);
537 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiEqIdx,
false);
542 bool cellIwasUpwindCell;
544 if(elementI.level()>neighbor.level())
545 cellIwasUpwindCell = cellDataI.isUpwindCell(intersection.indexInInside(), contiEqIdx);
547 cellIwasUpwindCell = !cellDataJ.isUpwindCell(intersection.indexInOutside(), contiEqIdx);
549 if (potential[phaseIdx] > 0. && cellIwasUpwindCell)
550 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
551 else if (potential[phaseIdx] < 0. && !cellIwasUpwindCell)
552 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
554 else if(this->restrictFluxInTransport_ == 2)
555 doUpwinding[phaseIdx] =
false;
559 if (potential[phaseIdx] > 0. && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellDataJ.mobility(phaseIdx), 0.0, 1.0e-30))
560 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
561 else if (potential[phaseIdx] < 0. && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellDataI.mobility(phaseIdx), 0.0, 1.0e-30))
562 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
564 doUpwinding[phaseIdx] =
false;
568 if(!doUpwinding[phaseIdx])
571 if(cellDataI.mobility(phaseIdx)+cellDataJ.mobility(phaseIdx)==0.)
573 potential[phaseIdx] = 0;
578 fluxEntries[wCompIdx] -= potential[phaseIdx] / volume
579 *
harmonicMean(cellDataI.massFraction(phaseIdx, wCompIdx) * cellDataI.mobility(phaseIdx) * cellDataI.density(phaseIdx),
580 cellDataJ.massFraction(phaseIdx, wCompIdx) * cellDataJ.mobility(phaseIdx) * cellDataJ.density(phaseIdx));
581 fluxEntries[nCompIdx] -= potential[phaseIdx] / volume
582 *
harmonicMean(cellDataI.massFraction(phaseIdx, nCompIdx) * cellDataI.mobility(phaseIdx) * cellDataI.density(phaseIdx),
583 cellDataJ.massFraction(phaseIdx, nCompIdx) * cellDataJ.mobility(phaseIdx) * cellDataJ.density(phaseIdx));
587 timestepFlux[0] += max(0.,
588 - potential[phaseIdx] / volume
589 *
harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx)));
591 timestepFlux[1] += max(0.,
592 potential[phaseIdx] / volume
593 *
harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx))/SmobI[phaseIdx]);
596 this->averagedFaces_++;
597 #if DUNE_MINIMAL_DEBUG_LEVEL < 3
599 if(globalIdxI > globalIdxJ)
600 Dune::dinfo <<
"harmonicMean flux of phase" << phaseIdx <<
" used from cell" << globalIdxI<<
" into " << globalIdxJ
601 <<
" ; TE upwind I = "<< cellIwasUpwindCell <<
" but pot = "<< potential[phaseIdx] << std::endl;
605 potential[phaseIdx] = 0;
612 double velocityJIw = max((-lambda[wPhaseIdx] * potential[wPhaseIdx]) / volume, 0.0);
613 double velocityIJw = max(( lambda[wPhaseIdx] * potential[wPhaseIdx]) / volume, 0.0);
614 double velocityJIn = max((-lambda[nPhaseIdx] * potential[nPhaseIdx]) / volume, 0.0);
615 double velocityIJn = max(( lambda[nPhaseIdx] * potential[nPhaseIdx]) / volume, 0.0);
618 timestepFlux[0] += velocityJIw + velocityJIn;
620 double foutw = velocityIJw/SmobI[wPhaseIdx];
621 double foutn = velocityIJn/SmobI[nPhaseIdx];
624 if (isnan(foutw) || isinf(foutw) || foutw < 0) foutw = 0;
625 if (isnan(foutn) || isinf(foutn) || foutn < 0) foutn = 0;
626 timestepFlux[1] += foutw + foutn;
628 fluxEntries[wCompIdx] +=
629 velocityJIw * cellDataJ.massFraction(wPhaseIdx, wCompIdx) * densityWJ
630 - velocityIJw * cellDataI.massFraction(wPhaseIdx, wCompIdx) * densityWI
631 + velocityJIn * cellDataJ.massFraction(nPhaseIdx, wCompIdx) * densityNWJ
632 - velocityIJn * cellDataI.massFraction(nPhaseIdx, wCompIdx) * densityNWI;
633 fluxEntries[nCompIdx] +=
634 velocityJIw * cellDataJ.massFraction(wPhaseIdx, nCompIdx) * densityWJ
635 - velocityIJw * cellDataI.massFraction(wPhaseIdx, nCompIdx) * densityWI
636 + velocityJIn * cellDataJ.massFraction(nPhaseIdx, nCompIdx) * densityNWJ
637 - 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:78
Compositional transport step in a finite volume discretization.
Definition: fv3dtransportadaptive.hh:56
virtual void update(const Scalar t, Scalar &dt, TransportSolutionType &updateVec, bool impes=false)
Calculate the update vector and determine timestep size.
Definition: fv3dtransportadaptive.hh:163
static const int pressureType
‍Specifies if the MPFA is used on hanging nodes
Definition: fv3dtransportadaptive.hh:139
FV3dTransport2P2CAdaptive(Problem &problem)
Constructs a FV3dTransport2P2CAdaptive object.
Definition: fv3dtransportadaptive.hh:123
Problem & problem_
Definition: fv3dtransportadaptive.hh:134
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:346
virtual ~FV3dTransport2P2CAdaptive()
Definition: fv3dtransportadaptive.hh:129
bool enableMPFA
Definition: fv3dtransportadaptive.hh:136
Compositional transport step in a Finite Volume discretization.
Definition: fvtransport.hh:62
Definition: fvtransport.hh:114
Dune::FieldVector< EntryType, 2 *dim > faceFluxes
Definition: fvtransport.hh:115
Dune::FieldVector< Scalar, 2 *dim > faceTargetDt
Definition: fvtransport.hh:116