3.1-git
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
36namespace Dumux {
52template<class TypeTag>
54{
55 using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
56 using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
57 using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
58
59 using SpatialParams = typename GET_PROP_TYPE(TypeTag, SpatialParams);
60 using MaterialLaw = typename SpatialParams::MaterialLaw;
61
62 using Indices = typename GET_PROP_TYPE(TypeTag, ModelTraits)::Indices;
63 using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
64
65 using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
66 using FluidState = typename GET_PROP_TYPE(TypeTag, FluidState);
67
68 using CellData = typename GET_PROP_TYPE(TypeTag, CellData);
69
70 using TransportSolutionType = typename GET_PROP_TYPE(TypeTag, TransportSolutionType);
71
72 enum
73 {
74 dim = GridView::dimension, dimWorld = GridView::dimensionworld,
75 NumPhases = GET_PROP_VALUE(TypeTag, NumPhases)
76 };
77 enum
78 {
79 pw = Indices::pressureW,
80 pn = Indices::pressureN,
81 Sw = Indices::saturationW,
82 Sn = Indices::saturationN
83 };
84 enum
85 {
86 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
87 wCompIdx = Indices::wPhaseIdx, nCompIdx = Indices::nPhaseIdx,
88 contiWEqIdx=Indices::contiWEqIdx, contiNEqIdx=Indices::contiNEqIdx
89 };
90
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;
95
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>;
100 using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
101
103 Problem& problem()
104 { return problem_; }
105
106public:
107 virtual void update(const Scalar t, Scalar& dt, TransportSolutionType& updateVec,
108 bool impes = false);
109
110 void getMpfaFlux(Dune::FieldVector<Scalar, 2>&, Dune::FieldVector<Scalar, 2>&,
111 const IntersectionIterator&, CellData&);
112
122 FV3dTransport2P2CAdaptive(Problem& problem) : FVTransport2P2C<TypeTag>(problem),
123 problem_(problem), enableMPFA(false)
124 {
125 enableMPFA = getParam<bool>("GridAdapt.EnableMultiPointFluxApproximation");
126 }
127
129 {
130 }
131
132protected:
133 Problem& problem_;
134
136
138 static const int pressureType = GET_PROP_VALUE(TypeTag, PressureFormulation);
139};
140
161template<class TypeTag>
162void FV3dTransport2P2CAdaptive<TypeTag>::update(const Scalar t, Scalar& dt,
163 TransportSolutionType& updateVec, bool impet)
164{
165 this->impet_ = impet;
166
167 // initialize dt very large
168 dt = 1E100;
169 this->averagedFaces_ = 0;
170
171 // resize update vector and set to zero
172 int size_ = problem_.gridView().size(0);
173 updateVec.resize(GET_PROP_VALUE(TypeTag, NumComponents));
174 updateVec[wCompIdx].resize(size_);
175 updateVec[nCompIdx].resize(size_);
176 updateVec[wCompIdx] = 0;
177 updateVec[nCompIdx] = 0;
178 //also resize PV vector if necessary
179 if(this->totalConcentration_.size() != size_)
180 {
181 this->totalConcentration_[wCompIdx].resize(size_);
182 this->totalConcentration_[nCompIdx].resize(size_);
183 // copy data //TODO: remove this, remove PM Transport Vector!!
184 // loop thorugh all elements
185 for (int i = 0; i< problem().gridView().size(0); i++)
186 {
187 CellData& cellDataI = problem().variables().cellData(i);
188 for(int compIdx = 0; compIdx < GET_PROP_VALUE(TypeTag, NumComponents); compIdx++)
189 {
190 this->totalConcentration_[compIdx][i]
191 = cellDataI.totalConcentration(compIdx);
192 }
193 }
194 }
195 if (this->localTimeStepping_)
196 {
197 if (this->timeStepData_.size() != size_)
198 this->timeStepData_.resize(size_);
199 }
200
201 // Cell which restricts time step size
202 int restrictingCell = -1;
203
204 Dune::FieldVector<Scalar, 2> entries(0.), timestepFlux(0.);
205 // compute update vector
206 for (const auto& element : elements(problem().gridView()))
207 {
208 // get cell infos
209 int globalIdxI = problem().variables().index(element);
210 CellData& cellDataI = problem().variables().cellData(globalIdxI);
211
212 if(!impet && cellDataI.subdomain()!=2) // estimate only necessary in subdomain
213 continue;
214
215 // some variables for time step calculation
216 double sumfactorin = 0;
217 double sumfactorout = 0;
218
219 // run through all intersections with neighbors and boundary
220 const auto isEndIt = problem().gridView().iend(element);
221 for (auto isIt = problem().gridView().ibegin(element); isIt != isEndIt; ++isIt)
222 {
223 const auto& intersection = *isIt;
224
225 // handle interior face
226 if (intersection.neighbor())
227 {
228 if (enableMPFA && intersection.outside().level() != element.level())
229 getMpfaFlux(entries, timestepFlux, isIt, cellDataI);
230 else
231 this->getFlux(entries, timestepFlux, intersection, cellDataI);
232 }
233
234 // Boundary Face
235 if (intersection.boundary())
236 {
237 this->getFluxOnBoundary(entries, timestepFlux, intersection, cellDataI);
238 }
239
240 if (this->localTimeStepping_)
241 {
242 int indexInInside = intersection.indexInInside();
243 typename FVTransport2P2C<TypeTag>::LocalTimesteppingData& localData = this->timeStepData_[globalIdxI];
244 if (localData.faceTargetDt[indexInInside] < this->accumulatedDt_ + this->dtThreshold_)
245 {
246 localData.faceFluxes[indexInInside] = entries;
247 }
248 }
249 else
250 {
251 // add to update vector
252 updateVec[wCompIdx][globalIdxI] += entries[wCompIdx];
253 updateVec[nCompIdx][globalIdxI] += entries[nCompIdx];
254 }
255 // for time step calculation
256 sumfactorin += timestepFlux[0];
257 sumfactorout += timestepFlux[1];
258
259 }// end all intersections
260
261 if (this->localTimeStepping_)
262 {
263 typename FVTransport2P2C<TypeTag>::LocalTimesteppingData& localData = this->timeStepData_[globalIdxI];
264 for (int i=0; i < 2*dim; i++)
265 {
266 updateVec[wCompIdx][globalIdxI] += localData.faceFluxes[i][wCompIdx];
267 updateVec[nCompIdx][globalIdxI] += localData.faceFluxes[i][nCompIdx];
268 }
269 }
270
271 /*********** Handle source term ***************/
272 PrimaryVariables q(NAN);
273 problem().source(q, element);
274 updateVec[wCompIdx][globalIdxI] += q[contiWEqIdx];
275 updateVec[nCompIdx][globalIdxI] += q[contiNEqIdx];
276
277 // account for porosity
278 using std::max;
279 sumfactorin = max(sumfactorin,sumfactorout)
280 / problem().spatialParams().porosity(element);
281
282 //calculate time step
283 if (this->localTimeStepping_)
284 {
285 this->timeStepData_[globalIdxI].dt = 1./sumfactorin;
286 if ( 1./sumfactorin < dt)
287 {
288 dt = 1./sumfactorin;
289 restrictingCell= globalIdxI;
290 }
291 }
292 else
293 {
294 if ( 1./sumfactorin < dt)
295 {
296 dt = 1./sumfactorin;
297 restrictingCell= globalIdxI;
298 }
299 }
300 } // end grid traversal
301
302#if HAVE_MPI
303 // communicate updated values
304 using SolutionTypes = typename GET_PROP(TypeTag, SolutionTypes);
305 using ElementMapper = typename SolutionTypes::ElementMapper;
307 for (int i = 0; i < updateVec.size(); i++)
308 {
309 DataHandle dataHandle(problem().variables().elementMapper(), updateVec[i]);
310 problem_.gridView().template communicate<DataHandle>(dataHandle,
311 Dune::InteriorBorder_All_Interface,
312 Dune::ForwardCommunication);
313 }
314 dt = problem().gridView().comm().min(dt);
315#endif
316
317 if(impet)
318 {
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;
323 }
324 return;
325}
326
344template<class TypeTag>
345void FV3dTransport2P2CAdaptive<TypeTag>::getMpfaFlux(Dune::FieldVector<Scalar, 2>& fluxEntries,
346 Dune::FieldVector<Scalar, 2>& timestepFlux,
347 const IntersectionIterator& isIt, CellData& cellDataI)
348{
349 const auto& intersection = *isIt;
350
351 fluxEntries = 0.;
352 timestepFlux = 0.;
353 // cell information
354 auto elementI = intersection.inside();
355 int globalIdxI = problem().variables().index(elementI);
356
357 // get position
358 const GlobalPosition globalPos = elementI.geometry().center();
359 const GlobalPosition& gravity_ = problem().gravity();
360 // cell volume, assume linear map here
361 Scalar volume = elementI.geometry().volume();
362
363 // get values of cell I
364 Scalar pressI = problem().pressureModel().pressure(globalIdxI);
365 Scalar pcI = cellDataI.capillaryPressure();
366 DimMatrix K_I(problem().spatialParams().intrinsicPermeability(elementI));
367
368 PhaseVector SmobI(0.);
369 using std::max;
370 SmobI[wPhaseIdx] = max((cellDataI.saturation(wPhaseIdx)
371 - problem().spatialParams().materialLawParams(elementI).swr())
372 , 1e-2);
373 SmobI[nPhaseIdx] = max((cellDataI.saturation(nPhaseIdx)
374 - problem().spatialParams().materialLawParams(elementI).snr())
375 , 1e-2);
376
377 Scalar densityWI (0.), densityNWI(0.);
378 densityWI= cellDataI.density(wPhaseIdx);
379 densityNWI = cellDataI.density(nPhaseIdx);
380
381 PhaseVector potential(0.);
382
383 // access neighbor
384 auto neighbor = intersection.outside();
385 int globalIdxJ = problem().variables().index(neighbor);
386 CellData& cellDataJ = problem().variables().cellData(globalIdxJ);
387
388 // neighbor cell center in global coordinates
389 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
390
391 // distance vector between barycenters
392 GlobalPosition distVec = globalPosNeighbor - globalPos;
393 // compute distance between cell centers
394 Scalar dist = distVec.two_norm();
395
396 GlobalPosition unitDistVec(distVec);
397 unitDistVec /= dist;
398
399 // phase densities in neighbor
400 Scalar densityWJ (0.), densityNWJ(0.);
401 densityWJ = cellDataJ.density(wPhaseIdx);
402 densityNWJ = cellDataJ.density(nPhaseIdx);
403
404 // average phase densities with central weighting
405 double densityW_mean = (densityWI + densityWJ) * 0.5;
406 double densityNW_mean = (densityNWI + densityNWJ) * 0.5;
407
408 double pressJ = problem().pressureModel().pressure(globalIdxJ);
409 Scalar pcJ = cellDataJ.capillaryPressure();
410
411 // determine potentials for upwind
413 GlobalPosition globalPos3(0.);
414 int globalIdx3=-1;
415 GlobalPosition globalPos4(0.);
416 int globalIdx4=-1;
417 TransmissivityMatrix T(0.);
418 TransmissivityMatrix additionalT(0.);
419 // prepare second interaction region
420 GlobalPosition globalPosAdditional3(0.);
421 int globalIdxAdditional3=-1;
422 GlobalPosition globalPosAdditional4(0.);
423 int globalIdxAdditional4=-1;
424
425 int halfedgesStored
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 );
430
431 // acess cell 3&4 and prepare mpfa
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_;
442 if(pressureType==pw)
443 {
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];
452 }
453 else if(pressureType==pn)
454 {
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];
463 }
464 // regard more interaction regions, if there are more
465 if(halfedgesStored != 1)
466 {
467 for(int banana = 1; banana < halfedgesStored; banana ++)
468 {
469 // get data for second interaction region
470 problem().variables().getMpfaData3D(intersection, additionalT,
471 globalPosAdditional3, globalIdxAdditional3,
472 globalPosAdditional4, globalIdxAdditional4 ,
473 banana); // offset for second interaction region
474
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);
481
482 if(pressureType==pw)
483 {
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];
490 }
491 else if(pressureType==pn)
492 {
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];
499 }
500 potential[wPhaseIdx] -= gravityContributionAdditonal * densityW_mean;
501 potential[nPhaseIdx] -= gravityContributionAdditonal * densityNW_mean;
502 }
503 } //end of mpfa specific stuff
504
505 // determine upwinding direction, perform upwinding if possible
506 Dune::FieldVector<bool, NumPhases> doUpwinding(true);
507 PhaseVector lambda(0.);
508 for(int phaseIdx = 0; phaseIdx < NumPhases; phaseIdx++)
509 {
510 int contiEqIdx = 0;
511 if(phaseIdx == wPhaseIdx)
512 contiEqIdx = contiWEqIdx;
513 else
514 contiEqIdx = contiNEqIdx;
515
516 if(!this->impet_ or !this->restrictFluxInTransport_) // perform a strict uwpind scheme
517 {
518 if(potential[phaseIdx] > 0.)
519 {
520 lambda[phaseIdx] = cellDataI.mobility(phaseIdx);
521 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx, true);
522 }
523 else if(potential[phaseIdx] < 0.)
524 {
525 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
526 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx, false);
527 }
528 else
529 {
530 doUpwinding[phaseIdx] = false;
531 cellDataI.setUpwindCell(intersection.indexInInside(), contiEqIdx, false);
532 cellDataJ.setUpwindCell(intersection.indexInOutside(), contiEqIdx, false);
533 }
534 }
535 else // Transport after PE with check on flow direction
536 {
537 bool cellIwasUpwindCell;
538 //get the information from smaller (higher level) cell, as its IS is unique
539 if(elementI.level()>neighbor.level())
540 cellIwasUpwindCell = cellDataI.isUpwindCell(intersection.indexInInside(), contiEqIdx);
541 else // reverse neighbors information gathered
542 cellIwasUpwindCell = !cellDataJ.isUpwindCell(intersection.indexInOutside(), contiEqIdx);
543
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);
548 // potential direction does not coincide with that of P.E.
549 else if(this->restrictFluxInTransport_ == 2) // perform central averaging for all direction changes
550 doUpwinding[phaseIdx] = false;
551 else // i.e. restrictFluxInTransport == 1
552 {
553 //check if harmonic weithing is necessary
554 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
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)) // check if inflow induce neglected phase flux
557 lambda[phaseIdx] = cellDataJ.mobility(phaseIdx);
558 else
559 doUpwinding[phaseIdx] = false;
560 }
561
562 // do not perform upwinding if so desired
563 if(!doUpwinding[phaseIdx])
564 {
565 //a) no flux if there wont be any flux regardless how to average/upwind
566 if(cellDataI.mobility(phaseIdx)+cellDataJ.mobility(phaseIdx)==0.)
567 {
568 potential[phaseIdx] = 0;
569 continue;
570 }
571
572 //b) perform harmonic averaging
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));
579 // c) timestep control
580 // for timestep control : influx
581 using std::max;
582 timestepFlux[0] += max(0.,
583 - potential[phaseIdx] / volume
584 * harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx)));
585 // outflux
586 timestepFlux[1] += max(0.,
587 potential[phaseIdx] / volume
588 * harmonicMean(cellDataI.mobility(phaseIdx),cellDataJ.mobility(phaseIdx))/SmobI[phaseIdx]);
589
590 //d) output (only for one side)
591 this->averagedFaces_++;
592 #if DUNE_MINIMAL_DEBUG_LEVEL < 3
593 // verbose (only for one side)
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;
597 #endif
598
599 //e) stop further standard calculations
600 potential[phaseIdx] = 0;
601 }
602 }
603 }
604
605 // calculate and standardized velocity
606 using std::max;
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);
611
612 // for timestep control
613 timestepFlux[0] += velocityJIw + velocityJIn;
614
615 double foutw = velocityIJw/SmobI[wPhaseIdx];
616 double foutn = velocityIJn/SmobI[nPhaseIdx];
617 using std::isnan;
618 using std::isinf;
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;
622
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;
633 return;
634}
635
636} // end namespace Dumux
637#endif
#define GET_PROP_VALUE(TypeTag, PropTagName)
Definition: propertysystemmacros.hh:282
#define GET_PROP(TypeTag, PropTagName)
Definition: propertysystemmacros.hh:281
#define GET_PROP_TYPE(TypeTag, PropTagName)
Definition: propertysystemmacros.hh:283
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
make the local view function available whenever we use the grid geometry
Definition: adapt.hh:29
Property tag NumComponents
Number of components in the system.
Definition: porousmediumflow/sequential/properties.hh:70
Property tag NumPhases
Number of phases in the system.
Definition: porousmediumflow/sequential/properties.hh:69
Property tag SolutionTypes
Definition: porousmediumflow/sequential/properties.hh:58
A data handle class to exchange entries of a vector.
Definition: vectorexchange.hh:40
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