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
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.
Helpers for deprecation.
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