3.3.0
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
fv3dtransportadaptive.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*****************************************************************************
4 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
24#ifndef DUMUX_FV3DTRANSPORT2P2C_ADAPTIVE_HH
25#define DUMUX_FV3DTRANSPORT2P2C_ADAPTIVE_HH
26
27#include <dune/grid/common/gridenums.hh>
28#include <dune/common/float_cmp.hh>
29
30#include <dumux/common/math.hh>
32
33#include "adaptiveproperties.hh"
34#include "fvtransport.hh"
35
37
38namespace Dumux {
54template<class TypeTag>
56{
60
62
65
68
70
72
73 enum
74 {
75 dim = GridView::dimension, dimWorld = GridView::dimensionworld,
76 NumPhases = getPropValue<TypeTag, Properties::NumPhases>()
77 };
78 enum
79 {
80 pw = Indices::pressureW,
81 pn = Indices::pressureN,
82 Sw = Indices::saturationW,
83 Sn = Indices::saturationN
84 };
85 enum
86 {
87 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
88 wCompIdx = Indices::wPhaseIdx, nCompIdx = Indices::nPhaseIdx,
89 contiWEqIdx=Indices::contiWEqIdx, contiNEqIdx=Indices::contiNEqIdx
90 };
91
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;
96
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>;
102
104 Problem& problem()
105 { return problem_; }
106
107public:
108 virtual void update(const Scalar t, Scalar& dt, TransportSolutionType& updateVec,
109 bool impes = false);
110
111 void getMpfaFlux(Dune::FieldVector<Scalar, 2>&, Dune::FieldVector<Scalar, 2>&,
112 const IntersectionIterator&, CellData&);
113
123 FV3dTransport2P2CAdaptive(Problem& problem) : FVTransport2P2C<TypeTag>(problem),
124 problem_(problem), enableMPFA(false)
125 {
126 enableMPFA = getParam<bool>("GridAdapt.EnableMultiPointFluxApproximation");
127 }
128
130 {
131 }
132
133protected:
134 Problem& problem_;
135
137
139 static const int pressureType = getPropValue<TypeTag, Properties::PressureFormulation>();
140};
141
162template<class TypeTag>
163void FV3dTransport2P2CAdaptive<TypeTag>::update(const Scalar t, Scalar& dt,
164 TransportSolutionType& updateVec, bool impet)
165{
166 this->impet_ = impet;
167
168 // initialize dt very large
169 dt = 1E100;
170 this->averagedFaces_ = 0;
171
172 // resize update vector and set to zero
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;
179 //also resize PV vector if necessary
180 if(this->totalConcentration_.size() != size_)
181 {
182 this->totalConcentration_[wCompIdx].resize(size_);
183 this->totalConcentration_[nCompIdx].resize(size_);
184 // copy data //TODO: remove this, remove PM Transport Vector!!
185 // loop thorugh all elements
186 for (int i = 0; i< problem().gridView().size(0); i++)
187 {
188 CellData& cellDataI = problem().variables().cellData(i);
189 for(int compIdx = 0; compIdx < getPropValue<TypeTag, Properties::NumComponents>(); compIdx++)
190 {
191 this->totalConcentration_[compIdx][i]
192 = cellDataI.totalConcentration(compIdx);
193 }
194 }
195 }
196 if (this->localTimeStepping_)
197 {
198 if (this->timeStepData_.size() != size_)
199 this->timeStepData_.resize(size_);
200 }
201
202 // Cell which restricts time step size
203 int restrictingCell = -1;
204
205 Dune::FieldVector<Scalar, 2> entries(0.), timestepFlux(0.);
206 // compute update vector
207 for (const auto& element : elements(problem().gridView()))
208 {
209 // get cell infos
210 int globalIdxI = problem().variables().index(element);
211 CellData& cellDataI = problem().variables().cellData(globalIdxI);
212
213 if(!impet && cellDataI.subdomain()!=2) // estimate only necessary in subdomain
214 continue;
215
216 // some variables for time step calculation
217 double sumfactorin = 0;
218 double sumfactorout = 0;
219
220 // run through all intersections with neighbors and boundary
221 const auto isEndIt = problem().gridView().iend(element);
222 for (auto isIt = problem().gridView().ibegin(element); isIt != isEndIt; ++isIt)
223 {
224 const auto& intersection = *isIt;
225
226 // handle interior face
227 if (intersection.neighbor())
228 {
229 if (enableMPFA && intersection.outside().level() != element.level())
230 getMpfaFlux(entries, timestepFlux, isIt, cellDataI);
231 else
232 this->getFlux(entries, timestepFlux, intersection, cellDataI);
233 }
234
235 // Boundary Face
236 if (intersection.boundary())
237 {
238 this->getFluxOnBoundary(entries, timestepFlux, intersection, cellDataI);
239 }
240
241 if (this->localTimeStepping_)
242 {
243 int indexInInside = intersection.indexInInside();
244 typename FVTransport2P2C<TypeTag>::LocalTimesteppingData& localData = this->timeStepData_[globalIdxI];
245 if (localData.faceTargetDt[indexInInside] < this->accumulatedDt_ + this->dtThreshold_)
246 {
247 localData.faceFluxes[indexInInside] = entries;
248 }
249 }
250 else
251 {
252 // add to update vector
253 updateVec[wCompIdx][globalIdxI] += entries[wCompIdx];
254 updateVec[nCompIdx][globalIdxI] += entries[nCompIdx];
255 }
256 // for time step calculation
257 sumfactorin += timestepFlux[0];
258 sumfactorout += timestepFlux[1];
259
260 }// end all intersections
261
262 if (this->localTimeStepping_)
263 {
264 typename FVTransport2P2C<TypeTag>::LocalTimesteppingData& localData = this->timeStepData_[globalIdxI];
265 for (int i=0; i < 2*dim; i++)
266 {
267 updateVec[wCompIdx][globalIdxI] += localData.faceFluxes[i][wCompIdx];
268 updateVec[nCompIdx][globalIdxI] += localData.faceFluxes[i][nCompIdx];
269 }
270 }
271
272 /*********** Handle source term ***************/
273 PrimaryVariables q(NAN);
274 problem().source(q, element);
275 updateVec[wCompIdx][globalIdxI] += q[contiWEqIdx];
276 updateVec[nCompIdx][globalIdxI] += q[contiNEqIdx];
277
278 // account for porosity
279 using std::max;
280 sumfactorin = max(sumfactorin,sumfactorout)
281 / problem().spatialParams().porosity(element);
282
283 //calculate time step
284 if (this->localTimeStepping_)
285 {
286 this->timeStepData_[globalIdxI].dt = 1./sumfactorin;
287 if ( 1./sumfactorin < dt)
288 {
289 dt = 1./sumfactorin;
290 restrictingCell= globalIdxI;
291 }
292 }
293 else
294 {
295 if ( 1./sumfactorin < dt)
296 {
297 dt = 1./sumfactorin;
298 restrictingCell= globalIdxI;
299 }
300 }
301 } // end grid traversal
302
303#if HAVE_MPI
304 // communicate updated values
306 using ElementMapper = typename SolutionTypes::ElementMapper;
308 for (int i = 0; i < updateVec.size(); i++)
309 {
310 DataHandle dataHandle(problem().variables().elementMapper(), updateVec[i]);
311 problem_.gridView().template communicate<DataHandle>(dataHandle,
312 Dune::InteriorBorder_All_Interface,
313 Dune::ForwardCommunication);
314 }
315 dt = problem().gridView().comm().min(dt);
316#endif
317
318 if(impet)
319 {
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;
324 }
325 return;
326}
327
345template<class TypeTag>
346void FV3dTransport2P2CAdaptive<TypeTag>::getMpfaFlux(Dune::FieldVector<Scalar, 2>& fluxEntries,
347 Dune::FieldVector<Scalar, 2>& timestepFlux,
348 const IntersectionIterator& isIt, CellData& cellDataI)
349{
350 const auto& intersection = *isIt;
351
352 fluxEntries = 0.;
353 timestepFlux = 0.;
354 // cell information
355 auto elementI = intersection.inside();
356 int globalIdxI = problem().variables().index(elementI);
357
358 // get position
359 const GlobalPosition globalPos = elementI.geometry().center();
360 const GlobalPosition& gravity_ = problem().gravity();
361 // cell volume, assume linear map here
362 Scalar volume = elementI.geometry().volume();
363
364 // get values of cell I
365 Scalar pressI = problem().pressureModel().pressure(globalIdxI);
366 Scalar pcI = cellDataI.capillaryPressure();
367
368 // old material law interface is deprecated: Replace this by
369 // const auto& fluidMatrixInteraction = problem().spatialParams.fluidMatrixInteractionAtPos(elementI.geometry().center());
370 // after the release of 3.3, when the deprecated interface is no longer supported
371 const auto fluidMatrixInteraction = Deprecated::makePcKrSw(Scalar{}, problem().spatialParams(), elementI);
372
373 PhaseVector SmobI(0.);
374 using std::max;
375 SmobI[wPhaseIdx] = max((cellDataI.saturation(wPhaseIdx)
376 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().swr())
377 , 1e-2);
378 SmobI[nPhaseIdx] = max((cellDataI.saturation(nPhaseIdx)
379 - fluidMatrixInteraction.pcSwCurve().effToAbsParams().snr())
380 , 1e-2);
381
382 Scalar densityWI (0.), densityNWI(0.);
383 densityWI= cellDataI.density(wPhaseIdx);
384 densityNWI = cellDataI.density(nPhaseIdx);
385
386 PhaseVector potential(0.);
387
388 // access neighbor
389 auto neighbor = intersection.outside();
390 int globalIdxJ = problem().variables().index(neighbor);
391 CellData& cellDataJ = problem().variables().cellData(globalIdxJ);
392
393 // neighbor cell center in global coordinates
394 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
395
396 // distance vector between barycenters
397 GlobalPosition distVec = globalPosNeighbor - globalPos;
398 // compute distance between cell centers
399 Scalar dist = distVec.two_norm();
400
401 GlobalPosition unitDistVec(distVec);
402 unitDistVec /= dist;
403
404 // phase densities in neighbor
405 Scalar densityWJ (0.), densityNWJ(0.);
406 densityWJ = cellDataJ.density(wPhaseIdx);
407 densityNWJ = cellDataJ.density(nPhaseIdx);
408
409 // average phase densities with central weighting
410 double densityW_mean = (densityWI + densityWJ) * 0.5;
411 double densityNW_mean = (densityNWI + densityNWJ) * 0.5;
412
413 double pressJ = problem().pressureModel().pressure(globalIdxJ);
414 Scalar pcJ = cellDataJ.capillaryPressure();
415
416 // determine potentials for upwind
418 GlobalPosition globalPos3(0.);
419 int globalIdx3=-1;
420 GlobalPosition globalPos4(0.);
421 int globalIdx4=-1;
422 TransmissivityMatrix T(0.);
423 TransmissivityMatrix additionalT(0.);
424 // prepare second interaction region
425 GlobalPosition globalPosAdditional3(0.);
426 int globalIdxAdditional3=-1;
427 GlobalPosition globalPosAdditional4(0.);
428 int globalIdxAdditional4=-1;
429
430 int halfedgesStored
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 );
435
436 // acess cell 3&4 and prepare mpfa
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_;
447 if(pressureType==pw)
448 {
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];
457 }
458 else if(pressureType==pn)
459 {
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];
468 }
469 // regard more interaction regions, if there are more
470 if(halfedgesStored != 1)
471 {
472 for(int banana = 1; banana < halfedgesStored; banana ++)
473 {
474 // get data for second interaction region
475 problem().variables().getMpfaData3D(intersection, additionalT,
476 globalPosAdditional3, globalIdxAdditional3,
477 globalPosAdditional4, globalIdxAdditional4 ,
478 banana); // offset for second interaction region
479
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);
486
487 if(pressureType==pw)
488 {
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];
495 }
496 else if(pressureType==pn)
497 {
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];
504 }
505 potential[wPhaseIdx] -= gravityContributionAdditonal * densityW_mean;
506 potential[nPhaseIdx] -= gravityContributionAdditonal * densityNW_mean;
507 }
508 } //end of mpfa specific stuff
509
510 // determine upwinding direction, perform upwinding if possible
511 Dune::FieldVector<bool, NumPhases> doUpwinding(true);
512 PhaseVector lambda(0.);
513 for(int phaseIdx = 0; phaseIdx < NumPhases; phaseIdx++)
514 {
515 int contiEqIdx = 0;
516 if(phaseIdx == wPhaseIdx)
517 contiEqIdx = contiWEqIdx;
518 else
519 contiEqIdx = contiNEqIdx;
520
521 if(!this->impet_ or !this->restrictFluxInTransport_) // perform a strict uwpind scheme
522 {
523 if(potential[phaseIdx] > 0.)
524 {
525 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
526 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx, true);
527 }
528 else if(potential[phaseIdx] < 0.)
529 {
530 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
531 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx, false);
532 }
533 else
534 {
535 doUpwinding[phaseIdx] = false;
536 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx, false);
537 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiEqIdx, false);
538 }
539 }
540 else // Transport after PE with check on flow direction
541 {
542 bool cellIwasUpwindCell;
543 //get the information from smaller (higher level) cell, as its IS is unique
544 if(elementI.level()>neighbor.level())
545 cellIwasUpwindCell = cellDataI.isUpwindCell(intersection.indexInInside(), contiEqIdx);
546 else // reverse neighbors information gathered
547 cellIwasUpwindCell = !cellDataJ.isUpwindCell(intersection.indexInOutside(), contiEqIdx);
548
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);
553 // potential direction does not coincide with that of P.E.
554 else if(this->restrictFluxInTransport_ == 2) // perform central averaging for all direction changes
555 doUpwinding[phaseIdx] = false;
556 else // i.e. restrictFluxInTransport == 1
557 {
558 //check if harmonic weithing is necessary
559 if (potential[phaseIdx] > 0. && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(cellDataJ.mobility(phaseIdx), 0.0, 1.0e-30)) // check if outflow induce neglected (i.e. mob=0) phase flux
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)) // check if inflow induce neglected phase flux
562 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
563 else
564 doUpwinding[phaseIdx] = false;
565 }
566
567 // do not perform upwinding if so desired
568 if(!doUpwinding[phaseIdx])
569 {
570 //a) no flux if there wont be any flux regardless how to average/upwind
571 if(cellDataI.mobility(phaseIdx)+cellDataJ.mobility(phaseIdx)==0.)
572 {
573 potential[phaseIdx] = 0;
574 continue;
575 }
576
577 //b) perform harmonic averaging
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));
584 // c) timestep control
585 // for timestep control : influx
586 using std::max;
587 timestepFlux[0] += max(0.,
588 - potential[phaseIdx] / volume
589 * harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx)));
590 // outflux
591 timestepFlux[1] += max(0.,
592 potential[phaseIdx] / volume
593 * harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx))/SmobI[phaseIdx]);
594
595 //d) output (only for one side)
596 this->averagedFaces_++;
597 #if DUNE_MINIMAL_DEBUG_LEVEL < 3
598 // verbose (only for one side)
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;
602 #endif
603
604 //e) stop further standard calculations
605 potential[phaseIdx] = 0;
606 }
607 }
608 }
609
610 // calculate and standardized velocity
611 using std::max;
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);
616
617 // for timestep control
618 timestepFlux[0] += velocityJIw + velocityJIn;
619
620 double foutw = velocityIJw/SmobI[wPhaseIdx];
621 double foutn = velocityIJn/SmobI[nPhaseIdx];
622 using std::isnan;
623 using std::isinf;
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;
627
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;
638 return;
639}
640
641} // end namespace Dumux
642#endif
Helpers for deprecation.
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
Definition: adapt.hh:29
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