3.2-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
2p/sequential/diffusion/cellcentered/pressure.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_FVPRESSURE2P_HH
25#define DUMUX_FVPRESSURE2P_HH
26
27#include <dune/common/float_cmp.hh>
28
29// dumux environment
32
33namespace Dumux {
112template<class TypeTag> class FVPressure2P: public FVPressure<TypeTag>
113{
115
116 //the model implementation
118
122
124 using MaterialLaw = typename SpatialParams::MaterialLaw;
125
127
130
133 using PrimaryVariables = typename SolutionTypes::PrimaryVariables;
136
137 using ScalarSolutionType = typename SolutionTypes::ScalarSolution;
138
139 enum
140 {
141 dim = GridView::dimension, dimWorld = GridView::dimensionworld
142 };
143 enum
144 {
145 pw = Indices::pressureW,
146 pn = Indices::pressureNw,
147 pGlobal = Indices::pressureGlobal,
148 sw = Indices::saturationW,
149 sn = Indices::saturationNw,
150 pressureIdx = Indices::pressureIdx,
151 saturationIdx = Indices::saturationIdx,
152 eqIdxPress = Indices::pressureEqIdx,
153 eqIdxSat = Indices::satEqIdx
154 };
155 enum
156 {
157 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx, numPhases = getPropValue<TypeTag, Properties::NumPhases>()
158 };
159
160 using Element = typename GridView::Traits::template Codim<0>::Entity;
161 using Intersection = typename GridView::Intersection;
162
163 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
164 using GravityVector = Dune::FieldVector<Scalar, dimWorld>;
165 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
166
167protected:
169 using EntryType = typename ParentType::EntryType;
170 enum
171 {
173 };
175
176public:
178 void getSource(EntryType& entry, const Element& element, const CellData& cellData, const bool first);
179
181 void getStorage(EntryType& entry, const Element& element, const CellData& cellData, const bool first);
182
184 void getFlux(EntryType& entry, const Intersection& intersection, const CellData& cellData, const bool first);
185
187 void getFluxOnBoundary(EntryType& entry,
188 const Intersection& intersection, const CellData& cellData, const bool first);
189
191 void updateMaterialLaws();
192
200 void initialize(bool solveTwice = true)
201 {
203
204 if (!compressibility_)
205 {
206 const auto element = *problem_.gridView().template begin<0>();
207 FluidState fluidState;
208 fluidState.setPressure(wPhaseIdx, problem_.referencePressure(element));
209 fluidState.setPressure(nPhaseIdx, problem_.referencePressure(element));
210 fluidState.setTemperature(problem_.temperature(element));
211 fluidState.setSaturation(wPhaseIdx, 1.);
212 fluidState.setSaturation(nPhaseIdx, 0.);
213 density_[wPhaseIdx] = FluidSystem::density(fluidState, wPhaseIdx);
214 density_[nPhaseIdx] = FluidSystem::density(fluidState, nPhaseIdx);
215 viscosity_[wPhaseIdx] = FluidSystem::viscosity(fluidState, wPhaseIdx);
216 viscosity_[nPhaseIdx] = FluidSystem::viscosity(fluidState, nPhaseIdx);
217 }
218
221
222 this->assemble(true);
223 this->solve();
224 if (solveTwice)
225 {
226 PressureSolutionVector pressureOld(this->pressure());
227
228 this->assemble(false);
229 this->solve();
230
231 PressureSolutionVector pressureDiff(pressureOld);
232 pressureDiff -= this->pressure();
233 pressureOld = this->pressure();
234 Scalar pressureNorm = pressureDiff.infinity_norm();
235 pressureNorm /= pressureOld.infinity_norm();
236 int numIter = 0;
237 while (pressureNorm > 1e-5 && numIter < 10)
238 {
240 this->assemble(false);
241 this->solve();
242
243 pressureDiff = pressureOld;
244 pressureDiff -= this->pressure();
245 pressureNorm = pressureDiff.infinity_norm();
246 pressureOld = this->pressure();
247 pressureNorm /= pressureOld.infinity_norm();
248
249 numIter++;
250 }
251 // std::cout<<"Pressure defect = "<<pressureNorm<<"; "<<
252 // numIter<<" Iterations needed for initial pressure field"<<std::endl;
253 }
254
256 }
257
263 void update()
264 {
265 timeStep_ = problem_.timeManager().timeStepSize();
266 //error bounds for error term for incompressible models
267 //to correct unphysical saturation over/undershoots due to saturation transport
268 if (!compressibility_)
269 {
270 maxError_ = 0.0;
271 int size = problem_.gridView().size(0);
272 for (int i = 0; i < size; i++)
273 {
274 Scalar sat = 0;
275 switch (saturationType_)
276 {
277 case sw:
278 sat = problem_.variables().cellData(i).saturation(wPhaseIdx);
279 break;
280 case sn:
281 sat = problem_.variables().cellData(i).saturation(nPhaseIdx);
282 break;
283 }
284 if (sat > 1.0)
285 {
286 using std::max;
287 maxError_ = max(maxError_, (sat - 1.0) / timeStep_);
288 }
289 if (sat < 0.0)
290 {
291 using std::max;
292 maxError_ = max(maxError_, (-sat) / timeStep_);
293 }
294 }
295 }
296
298
300 }
301
308 {
310
311 //reset velocities
312 int size = problem_.gridView().size(0);
313 for (int i = 0; i < size; i++)
314 {
315 CellData& cellData = problem_.variables().cellData(i);
316 cellData.fluxData().resetVelocity();
317 }
318 }
319
322 {
323 // iterate through leaf grid
324 for (const auto& element : elements(problem_.gridView()))
325 {
326 asImp_().storePressureSolution(element);
327 }
328 }
329
337 void storePressureSolution(const Element& element)
338 {
339 int eIdxGlobal = problem_.variables().index(element);
340 CellData& cellData = problem_.variables().cellData(eIdxGlobal);
341
342 if (compressibility_)
343 {
344 density_[wPhaseIdx] = cellData.density(wPhaseIdx);
345 density_[nPhaseIdx] = cellData.density(nPhaseIdx);
346 }
347
348 switch (pressureType_)
349 {
350 case pw:
351 {
352 Scalar pressW = this->pressure()[eIdxGlobal];
353 Scalar pc = cellData.capillaryPressure();
354
355 cellData.setPressure(wPhaseIdx, pressW);
356 cellData.setPressure(nPhaseIdx, pressW + pc);
357
358 Scalar gravityDiff = (problem_.bBoxMax() - element.geometry().center()) * gravity_;
359 Scalar potW = pressW + gravityDiff * density_[wPhaseIdx];
360 Scalar potNw = pressW + pc + gravityDiff * density_[nPhaseIdx];
361
362 cellData.setPotential(wPhaseIdx, potW);
363 cellData.setPotential(nPhaseIdx, potNw);
364
365 break;
366 }
367 case pn:
368 {
369 Scalar pressNw = this->pressure()[eIdxGlobal];
370 Scalar pc = cellData.capillaryPressure();
371
372 cellData.setPressure(nPhaseIdx, pressNw);
373 cellData.setPressure(wPhaseIdx, pressNw - pc);
374
375 Scalar gravityDiff = (problem_.bBoxMax() - element.geometry().center()) * gravity_;
376 Scalar potW = pressNw - pc + gravityDiff * density_[wPhaseIdx];
377 Scalar potNw = pressNw + gravityDiff * density_[nPhaseIdx];
378
379 cellData.setPotential(wPhaseIdx, potW);
380 cellData.setPotential(nPhaseIdx, potNw);
381
382 break;
383 }
384 case pGlobal:
385 {
386 Scalar press = this->pressure()[eIdxGlobal];
387 cellData.setGlobalPressure(press);
388
389 Scalar pc = cellData.capillaryPressure();
390 Scalar gravityDiff = (problem_.bBoxMax() - element.geometry().center()) * gravity_;
391
392 //This is only an estimation!!! -> only used for uwind directions and time-step estimation!!!
393 Scalar potW = press - cellData.fracFlowFunc(nPhaseIdx) * pc + gravityDiff * density_[wPhaseIdx];
394 Scalar potNw = press - cellData.fracFlowFunc(wPhaseIdx) * pc + gravityDiff * density_[nPhaseIdx];
395
396 cellData.setPotential(wPhaseIdx, potW);
397 cellData.setPotential(nPhaseIdx, potNw);
398
399 break;
400 }
401 }
402 cellData.fluxData().resetVelocity();
403 }
404
414 template<class MultiWriter>
415 void addOutputVtkFields(MultiWriter &writer)
416 {
417 int size = problem_.gridView().size(0);
418 ScalarSolutionType *pressure = writer.allocateManagedBuffer(size);
419 ScalarSolutionType *pressureSecond = 0;
420 ScalarSolutionType *pc = 0;
421 ScalarSolutionType *potentialW = 0;
422 ScalarSolutionType *potentialNw = 0;
423 ScalarSolutionType *mobilityW = 0;
424 ScalarSolutionType *mobilityNW = 0;
425
426 if (vtkOutputLevel_ > 0)
427 {
428 pressureSecond = writer.allocateManagedBuffer(size);
429 pc = writer.allocateManagedBuffer(size);
430 mobilityW = writer.allocateManagedBuffer(size);
431 mobilityNW = writer.allocateManagedBuffer(size);
432 }
433 if (vtkOutputLevel_ > 1)
434 {
435 potentialW = writer.allocateManagedBuffer(size);
436 potentialNw = writer.allocateManagedBuffer(size);
437 }
438
439 for (int i = 0; i < size; i++)
440 {
441 CellData& cellData = problem_.variables().cellData(i);
442
443 if (pressureType_ == pw)
444 {
445 (*pressure)[i] = cellData.pressure(wPhaseIdx);
446 if (vtkOutputLevel_ > 0)
447 {
448 (*pressureSecond)[i] = cellData.pressure(nPhaseIdx);
449 }
450 }
451 else if (pressureType_ == pn)
452 {
453 (*pressure)[i] = cellData.pressure(nPhaseIdx);
454 if (vtkOutputLevel_ > 0)
455 {
456 (*pressureSecond)[i] = cellData.pressure(wPhaseIdx);
457 }
458 }
459 else if (pressureType_ == pGlobal)
460 {
461 (*pressure)[i] = cellData.globalPressure();
462 }
463 if (vtkOutputLevel_ > 0)
464 {
465 (*pc)[i] = cellData.capillaryPressure();
466 (*mobilityW)[i] = cellData.mobility(wPhaseIdx);
467 (*mobilityNW)[i] = cellData.mobility(nPhaseIdx);
468 if (compressibility_)
469 {
470 (*mobilityW)[i] = (*mobilityW)[i]/cellData.density(wPhaseIdx);
471 (*mobilityNW)[i] = (*mobilityNW)[i]/cellData.density(nPhaseIdx);
472 }
473 }
474 if (vtkOutputLevel_ > 1)
475 {
476 (*potentialW)[i] = cellData.potential(wPhaseIdx);
477 (*potentialNw)[i] = cellData.potential(nPhaseIdx);
478 }
479 }
480
481 if (pressureType_ == pw)
482 {
483 writer.attachCellData(*pressure, "wetting pressure");
484 if (vtkOutputLevel_ > 0)
485 {
486 writer.attachCellData(*pressureSecond, "nonwetting pressure");
487 }
488 }
489 else if (pressureType_ == pn)
490 {
491 writer.attachCellData(*pressure, "nonwetting pressure");
492 if (vtkOutputLevel_ > 0)
493 {
494 writer.attachCellData(*pressureSecond, "wetting pressure");
495 }
496 }
497 if (pressureType_ == pGlobal)
498 {
499
500 writer.attachCellData(*pressure, "global pressure");
501 }
502
503 if (vtkOutputLevel_ > 0)
504 {
505 writer.attachCellData(*pc, "capillary pressure");
506 writer.attachCellData(*mobilityW, "wetting mobility");
507 writer.attachCellData(*mobilityNW, "nonwetting mobility");
508 }
509 if (vtkOutputLevel_ > 1)
510 {
511 writer.attachCellData(*potentialW, "wetting potential");
512 writer.attachCellData(*potentialNw, "nonwetting potential");
513 }
514
515 if (compressibility_)
516 {
517 if (vtkOutputLevel_ > 0)
518 {
519 ScalarSolutionType *densityWetting = writer.allocateManagedBuffer(size);
520 ScalarSolutionType *densityNonwetting = writer.allocateManagedBuffer(size);
521 ScalarSolutionType *viscosityWetting = writer.allocateManagedBuffer(size);
522 ScalarSolutionType *viscosityNonwetting = writer.allocateManagedBuffer(size);
523
524 for (int i = 0; i < size; i++)
525 {
526 CellData& cellData = problem_.variables().cellData(i);
527 (*densityWetting)[i] = cellData.density(wPhaseIdx);
528 (*densityNonwetting)[i] = cellData.density(nPhaseIdx);
529 (*viscosityWetting)[i] = cellData.viscosity(wPhaseIdx);
530 (*viscosityNonwetting)[i] = cellData.viscosity(nPhaseIdx);
531 }
532
533 writer.attachCellData(*densityWetting, "wetting density");
534 writer.attachCellData(*densityNonwetting, "nonwetting density");
535 writer.attachCellData(*viscosityWetting, "wetting viscosity");
536 writer.attachCellData(*viscosityNonwetting, "nonwetting viscosity");
537 }
538 }
539 }
540
546 FVPressure2P(Problem& problem) :
547 ParentType(problem), problem_(problem), gravity_(problem.gravity()), maxError_(0.), timeStep_(1.)
548 {
549 if (pressureType_ != pw && pressureType_ != pn && pressureType_ != pGlobal)
550 {
551 DUNE_THROW(Dune::NotImplemented, "Pressure type not supported!");
552 }
553 if (pressureType_ == pGlobal && compressibility_)
554 {
555 DUNE_THROW(Dune::NotImplemented, "Compressibility not supported for global pressure!");
556 }
557 if (saturationType_ != sw && saturationType_ != sn)
558 {
559 DUNE_THROW(Dune::NotImplemented, "Saturation type not supported!");
560 }
561
562 ErrorTermFactor_ = getParam<Scalar>("Impet.ErrorTermFactor");
563 ErrorTermLowerBound_ = getParam<Scalar>("Impet.ErrorTermLowerBound");
564 ErrorTermUpperBound_ = getParam<Scalar>("Impet.ErrorTermUpperBound");
565
566 density_[wPhaseIdx] = 0.;
567 density_[nPhaseIdx] = 0.;
568 viscosity_[wPhaseIdx] = 0.;
569 viscosity_[nPhaseIdx] = 0.;
570
571 vtkOutputLevel_ = getParam<int>("Vtk.OutputLevel");
572 }
573
574private:
576 Implementation &asImp_()
577 { return *static_cast<Implementation *>(this); }
578
580 const Implementation &asImp_() const
581 { return *static_cast<const Implementation *>(this); }
582
583 Problem& problem_;
584 const GravityVector& gravity_;
585
586 Scalar maxError_;
587 Scalar timeStep_;
588 Scalar ErrorTermFactor_;
589 Scalar ErrorTermLowerBound_;
590 Scalar ErrorTermUpperBound_;
591
592 Scalar density_[numPhases];
593 Scalar viscosity_[numPhases];
594
595 int vtkOutputLevel_;
596
597 static const bool compressibility_ = getPropValue<TypeTag, Properties::EnableCompressibility>();
599 static const int pressureType_ = getPropValue<TypeTag, Properties::PressureFormulation>();
601 static const int saturationType_ = getPropValue<TypeTag, Properties::SaturationFormulation>();
602};
603
611template<class TypeTag>
612void FVPressure2P<TypeTag>::getSource(EntryType& entry, const Element& element
613 , const CellData& cellData, const bool first)
614{
615 // cell volume, assume linear map here
616 Scalar volume = element.geometry().volume();
617
618 // get sources from problem
619 PrimaryVariables sourcePhase(0.0);
620 problem_.source(sourcePhase, element);
621
622 if (!compressibility_)
623 {
624 sourcePhase[wPhaseIdx] /= density_[wPhaseIdx];
625 sourcePhase[nPhaseIdx] /= density_[nPhaseIdx];
626 }
627
628 entry[rhs] = volume * (sourcePhase[wPhaseIdx] + sourcePhase[nPhaseIdx]);
629}
630
655template<class TypeTag>
656void FVPressure2P<TypeTag>::getStorage(EntryType& entry, const Element& element
657 , const CellData& cellData, const bool first)
658{
659 //volume correction due to density differences
660 if (compressibility_ && !first)
661 {
662 // cell volume, assume linear map here
663 Scalar volume = element.geometry().volume();
664
665 Scalar porosity = problem_.spatialParams().porosity(element);
666
667 switch (saturationType_)
668 {
669 case sw:
670 {
671 entry[rhs] = -(cellData.volumeCorrection()/timeStep_ * porosity * volume
672 * (cellData.density(wPhaseIdx) - cellData.density(nPhaseIdx)));
673 break;
674 }
675 case sn:
676 {
677 entry[rhs] = -(cellData.volumeCorrection()/timeStep_ * porosity * volume
678 * (cellData.density(nPhaseIdx) - cellData.density(wPhaseIdx)));
679 break;
680 }
681 }
682 }
683 else if (!compressibility_ && !first)
684 {
685 // error term for incompressible models to correct non-physical saturation over/undershoots due to saturation transport
686 // error reduction routine: volumetric error is damped and inserted to right hand side
687 Scalar sat = 0;
688 switch (saturationType_)
689 {
690 case sw:
691 sat = cellData.saturation(wPhaseIdx);
692 break;
693 case sn:
694 sat = cellData.saturation(nPhaseIdx);
695 break;
696 }
697
698 Scalar volume = element.geometry().volume();
699
700 Scalar error = (sat > 1.0) ? sat - 1.0 : 0.0;
701 if (sat < 0.0) {error = sat;}
702 error /= timeStep_;
703
704 using std::abs;
705 Scalar errorAbs = abs(error);
706
707 if ((errorAbs*timeStep_ > 1e-6) && (errorAbs > ErrorTermLowerBound_ * maxError_) && (!problem_.timeManager().willBeFinished()))
708 {
709 entry[rhs] = ErrorTermFactor_ * error * volume;
710 }
711 }
712}
713
719template<class TypeTag>
720void FVPressure2P<TypeTag>::getFlux(EntryType& entry, const Intersection& intersection
721 , const CellData& cellData, const bool first)
722{
723 auto elementI = intersection.inside();
724 auto elementJ = intersection.outside();
725
726 const CellData& cellDataJ = problem_.variables().cellData(problem_.variables().index(elementJ));
727
728 // get global coordinates of cell centers
729 const GlobalPosition& globalPosI = elementI.geometry().center();
730 const GlobalPosition& globalPosJ = elementJ.geometry().center();
731
732 // get mobilities and fractional flow factors
733 Scalar lambdaWI = cellData.mobility(wPhaseIdx);
734 Scalar lambdaNwI = cellData.mobility(nPhaseIdx);
735 Scalar lambdaWJ = cellDataJ.mobility(wPhaseIdx);
736 Scalar lambdaNwJ = cellDataJ.mobility(nPhaseIdx);
737
738 // get capillary pressure
739 Scalar pcI = cellData.capillaryPressure();
740 Scalar pcJ = cellDataJ.capillaryPressure();
741
742 // get face normal
743 const Dune::FieldVector<Scalar, dim>& unitOuterNormal = intersection.centerUnitOuterNormal();
744
745 // get face area
746 Scalar faceArea = intersection.geometry().volume();
747
748 // distance vector between barycenters
749 GlobalPosition distVec = globalPosJ - globalPosI;
750
751 // compute distance between cell centers
752 Scalar dist = distVec.two_norm();
753
754 // compute vectorized permeabilities
755 DimMatrix meanPermeability(0);
756
757 problem_.spatialParams().meanK(meanPermeability, problem_.spatialParams().intrinsicPermeability(elementI),
758 problem_.spatialParams().intrinsicPermeability(elementJ));
759
760 Dune::FieldVector<Scalar, dim> permeability(0);
761 meanPermeability.mv(unitOuterNormal, permeability);
762
763 Scalar rhoMeanW = 0;
764 Scalar rhoMeanNw = 0;
765 if (compressibility_)
766 {
767 rhoMeanW = 0.5 * (cellData.density(wPhaseIdx) + cellDataJ.density(wPhaseIdx));
768 rhoMeanNw = 0.5 * (cellData.density(nPhaseIdx) + cellDataJ.density(nPhaseIdx));
769 }
770
771 // calculate potential gradients
772 Scalar potentialDiffW = 0;
773 Scalar potentialDiffNw = 0;
774
775 // if we are at the very first iteration we can't calculate phase potentials
776 if (!first)
777 {
778 potentialDiffW = cellData.potential(wPhaseIdx) - cellDataJ.potential(wPhaseIdx);
779 potentialDiffNw = cellData.potential(nPhaseIdx) - cellDataJ.potential(nPhaseIdx);
780
781 if (compressibility_)
782 {
783 density_[wPhaseIdx] = (potentialDiffW > 0.) ? cellData.density(wPhaseIdx) : cellDataJ.density(wPhaseIdx);
784 density_[nPhaseIdx] = (potentialDiffNw > 0.) ? cellData.density(nPhaseIdx) : cellDataJ.density(nPhaseIdx);
785
786 density_[wPhaseIdx] = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? rhoMeanW : density_[wPhaseIdx];
787 density_[nPhaseIdx] = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? rhoMeanNw : density_[nPhaseIdx];
788
789 potentialDiffW = cellData.pressure(wPhaseIdx) - cellDataJ.pressure(wPhaseIdx);
790 potentialDiffNw = cellData.pressure(nPhaseIdx) - cellDataJ.pressure(nPhaseIdx);
791
792 potentialDiffW += density_[wPhaseIdx] * (distVec * gravity_);
793 potentialDiffNw += density_[nPhaseIdx] * (distVec * gravity_);
794 }
795 }
796
797 // do the upwinding of the mobility depending on the phase potentials
798 Scalar lambdaW = (potentialDiffW > 0.) ? lambdaWI : lambdaWJ;
799 lambdaW = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? 0.5 * (lambdaWI + lambdaWJ) : lambdaW;
800 Scalar lambdaNw = (potentialDiffNw > 0) ? lambdaNwI : lambdaNwJ;
801 lambdaNw = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? 0.5 * (lambdaNwI + lambdaNwJ) : lambdaNw;
802
803 if (compressibility_)
804 {
805 density_[wPhaseIdx] = (potentialDiffW > 0.) ? cellData.density(wPhaseIdx) : cellDataJ.density(wPhaseIdx);
806 density_[nPhaseIdx] = (potentialDiffNw > 0.) ? cellData.density(nPhaseIdx) : cellDataJ.density(nPhaseIdx);
807
808 density_[wPhaseIdx] = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? rhoMeanW : density_[wPhaseIdx];
809 density_[nPhaseIdx] = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? rhoMeanNw : density_[nPhaseIdx];
810 }
811
812 Scalar scalarPerm = permeability.two_norm();
813 // calculate current matrix entry
814 entry[matrix] = (lambdaW + lambdaNw) * scalarPerm / dist * faceArea;
815
816 // calculate right hand side
817 // calculate unit distVec
818 distVec /= dist;
819 Scalar areaScaling = (unitOuterNormal * distVec);
820 // this treatment of g allows to account for gravity flux through faces where the face normal has no z component (e.g. parallelepiped grids)
821 entry[rhs] = (lambdaW * density_[wPhaseIdx] + lambdaNw * density_[nPhaseIdx]) * scalarPerm * (gravity_ * distVec) * faceArea * areaScaling;
822
823 if (pressureType_ == pw)
824 {
825 // add capillary pressure term to right hand side
826 entry[rhs] += 0.5 * (lambdaNwI + lambdaNwJ) * scalarPerm * (pcI - pcJ) / dist * faceArea;
827 }
828 else if (pressureType_ == pn)
829 {
830 // add capillary pressure term to right hand side
831 entry[rhs] -= 0.5 * (lambdaWI + lambdaWJ) * scalarPerm * (pcI - pcJ) / dist * faceArea;
832 }
833}
834
843template<class TypeTag>
845const Intersection& intersection, const CellData& cellData, const bool first)
846{
847 auto element = intersection.inside();
848
849 // get global coordinates of cell centers
850 const GlobalPosition& globalPosI = element.geometry().center();
851
852 // center of face in global coordinates
853 const GlobalPosition& globalPosJ = intersection.geometry().center();
854
855 // get mobilities and fractional flow factors
856 Scalar lambdaWI = cellData.mobility(wPhaseIdx);
857 Scalar lambdaNwI = cellData.mobility(nPhaseIdx);
858 Scalar fractionalWI = cellData.fracFlowFunc(wPhaseIdx);
859 Scalar fractionalNwI = cellData.fracFlowFunc(nPhaseIdx);
860
861 // get capillary pressure
862 Scalar pcI = cellData.capillaryPressure();
863
864 // get face index
865 int isIndexI = intersection.indexInInside();
866
867 // get face normal
868 const Dune::FieldVector<Scalar, dim>& unitOuterNormal = intersection.centerUnitOuterNormal();
869
870 // get face area
871 Scalar faceArea = intersection.geometry().volume();
872
873 // distance vector between barycenters
874 GlobalPosition distVec = globalPosJ - globalPosI;
875
876 // compute distance between cell centers
877 Scalar dist = distVec.two_norm();
878
879 BoundaryTypes bcType;
880 problem_.boundaryTypes(bcType, intersection);
881 PrimaryVariables boundValues(0.0);
882
883 if (bcType.isDirichlet(eqIdxPress))
884 {
885 problem_.dirichlet(boundValues, intersection);
886
887 //permeability vector at boundary
888 // compute vectorized permeabilities
889 DimMatrix meanPermeability(0);
890
891 problem_.spatialParams().meanK(meanPermeability,
892 problem_.spatialParams().intrinsicPermeability(element));
893
894 Dune::FieldVector<Scalar, dim> permeability(0);
895 meanPermeability.mv(unitOuterNormal, permeability);
896
897 // determine saturation at the boundary -> if no saturation is known directly at the boundary use the cell saturation
898 Scalar satW = 0;
899 Scalar satNw = 0;
900 if (bcType.isDirichlet(eqIdxSat))
901 {
902 switch (saturationType_)
903 {
904 case sw:
905 {
906 satW = boundValues[saturationIdx];
907 satNw = 1 - boundValues[saturationIdx];
908 break;
909 }
910 case sn:
911 {
912 satW = 1 - boundValues[saturationIdx];
913 satNw = boundValues[saturationIdx];
914 break;
915 }
916 }
917 }
918 else
919 {
920 satW = cellData.saturation(wPhaseIdx);
921 satNw = cellData.saturation(nPhaseIdx);
922 }
923 Scalar temperature = problem_.temperature(element);
924
925 // get Dirichlet pressure boundary condition
926 Scalar pressBound = boundValues[pressureIdx];
927
928 //calculate constitutive relations depending on the kind of saturation used
929 Scalar pcBound = MaterialLaw::pc(problem_.spatialParams().materialLawParams(element), satW);
930
931 // determine phase pressures from primary pressure variable
932 Scalar pressW = 0;
933 Scalar pressNw = 0;
934 if (pressureType_ == pw)
935 {
936 pressW = pressBound;
937 pressNw = pressBound + pcBound;
938 }
939 else if (pressureType_ == pn)
940 {
941 pressW = pressBound - pcBound;
942 pressNw = pressBound;
943 }
944
945 Scalar densityWBound = density_[wPhaseIdx];
946 Scalar densityNwBound = density_[nPhaseIdx];
947 Scalar viscosityWBound = viscosity_[wPhaseIdx];
948 Scalar viscosityNwBound = viscosity_[nPhaseIdx];
949 Scalar rhoMeanW = 0;
950 Scalar rhoMeanNw = 0;
951
952 if (compressibility_)
953 {
954 FluidState fluidState;
955 fluidState.setSaturation(wPhaseIdx, satW);
956 fluidState.setSaturation(nPhaseIdx, satNw);
957 fluidState.setTemperature(temperature);
958 fluidState.setPressure(wPhaseIdx, pressW);
959 fluidState.setPressure(nPhaseIdx, pressNw);
960
961 densityWBound = FluidSystem::density(fluidState, wPhaseIdx);
962 densityNwBound = FluidSystem::density(fluidState, nPhaseIdx);
963 viscosityWBound = FluidSystem::viscosity(fluidState, wPhaseIdx) / densityWBound;
964 viscosityNwBound = FluidSystem::viscosity(fluidState, nPhaseIdx) / densityNwBound;
965
966 rhoMeanW = 0.5 * (cellData.density(wPhaseIdx) + densityWBound);
967 rhoMeanNw = 0.5 * (cellData.density(nPhaseIdx) + densityNwBound);
968 }
969
970 Scalar lambdaWBound = MaterialLaw::krw(problem_.spatialParams().materialLawParams(element), satW)
971 / viscosityWBound;
972 Scalar lambdaNwBound = MaterialLaw::krn(problem_.spatialParams().materialLawParams(element), satW)
973 / viscosityNwBound;
974
975 Scalar fractionalWBound = lambdaWBound / (lambdaWBound + lambdaNwBound);
976 Scalar fractionalNwBound = lambdaNwBound / (lambdaWBound + lambdaNwBound);
977
978 Scalar fMeanW = 0.5 * (fractionalWI + fractionalWBound);
979 Scalar fMeanNw = 0.5 * (fractionalNwI + fractionalNwBound);
980
981 Scalar potentialDiffW = 0;
982 Scalar potentialDiffNw = 0;
983
984 if (!first)
985 {
986 potentialDiffW = cellData.fluxData().upwindPotential(wPhaseIdx, isIndexI);
987 potentialDiffNw = cellData.fluxData().upwindPotential(nPhaseIdx, isIndexI);
988
989 if (compressibility_)
990 {
991 density_[wPhaseIdx] = (potentialDiffW > 0.) ? cellData.density(wPhaseIdx) : densityWBound;
992 density_[nPhaseIdx] = (potentialDiffNw > 0.) ? cellData.density(nPhaseIdx) : densityNwBound;
993
994 density_[wPhaseIdx] = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? rhoMeanW : density_[wPhaseIdx];
995 density_[nPhaseIdx] = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? rhoMeanNw : density_[nPhaseIdx];
996 }
997
998 // calculate potential gradient
999 switch (pressureType_)
1000 {
1001 case pw:
1002 {
1003 potentialDiffW = (cellData.pressure(wPhaseIdx) - pressBound);
1004 potentialDiffNw = (cellData.pressure(nPhaseIdx) - pressBound - pcBound);
1005 break;
1006 }
1007 case pn:
1008 {
1009 potentialDiffW = (cellData.pressure(wPhaseIdx) - pressBound + pcBound);
1010 potentialDiffNw = (cellData.pressure(nPhaseIdx) - pressBound);
1011 break;
1012 }
1013 case pGlobal:
1014 {
1015 potentialDiffW = (cellData.globalPressure() - pressBound - fMeanNw * (pcI - pcBound));
1016 potentialDiffNw = (cellData.globalPressure() - pressBound + fMeanW * (pcI - pcBound));
1017 break;
1018 }
1019 }
1020
1021 potentialDiffW += density_[wPhaseIdx] * (distVec * gravity_);
1022 potentialDiffNw += density_[nPhaseIdx] * (distVec * gravity_);
1023 }
1024
1025 // do the upwinding of the mobility depending on the phase potentials
1026 Scalar lambdaW = (potentialDiffW > 0.) ? lambdaWI : lambdaWBound;
1027 lambdaW = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? 0.5 * (lambdaWI + lambdaWBound) : lambdaW;
1028 Scalar lambdaNw = (potentialDiffNw > 0.) ? lambdaNwI : lambdaNwBound;
1029 lambdaNw = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? 0.5 * (lambdaNwI + lambdaNwBound) : lambdaNw;
1030
1031 if (compressibility_)
1032 {
1033 density_[wPhaseIdx] = (potentialDiffW > 0.) ? cellData.density(wPhaseIdx) : densityWBound;
1034 density_[wPhaseIdx] = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? rhoMeanW : density_[wPhaseIdx];
1035 density_[nPhaseIdx] = (potentialDiffNw > 0.) ? cellData.density(nPhaseIdx) : densityNwBound;
1036 density_[nPhaseIdx] = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? rhoMeanNw : density_[nPhaseIdx];
1037 }
1038
1039 Scalar scalarPerm = permeability.two_norm();
1040 // calculate current matrix entry
1041 entry[matrix] = (lambdaW + lambdaNw) * scalarPerm / dist * faceArea;
1042 entry[rhs] = entry[matrix] * pressBound;
1043
1044 // calculate right hand side
1045 // calculate unit distVec
1046 distVec /= dist;
1047 Scalar areaScaling = (unitOuterNormal * distVec);
1048 // this treatment of g allows to account for gravity flux through faces where the face normal has no z component (e.g. parallelepiped grids)
1049 entry[rhs] -= (lambdaW * density_[wPhaseIdx] + lambdaNw * density_[nPhaseIdx]) * scalarPerm * (gravity_ * distVec)
1050 * faceArea * areaScaling;
1051
1052 if (pressureType_ == pw)
1053 {
1054 //add capillary pressure term to right hand side
1055 entry[rhs] -= 0.5 * (lambdaNwI + lambdaNwBound) * scalarPerm * (pcI - pcBound) / dist * faceArea;
1056 }
1057 else if (pressureType_ == pn)
1058 {
1059 //add capillary pressure term to right hand side
1060 entry[rhs] += 0.5 * (lambdaWI + lambdaWBound) * scalarPerm * (pcI - pcBound) / dist * faceArea;
1061 }
1062 }
1063 // set Neumann boundary condition
1064 else if (bcType.isNeumann(eqIdxPress))
1065 {
1066 problem_.neumann(boundValues, intersection);
1067
1068 if (!compressibility_)
1069 {
1070 boundValues[wPhaseIdx] /= density_[wPhaseIdx];
1071 boundValues[nPhaseIdx] /= density_[nPhaseIdx];
1072 }
1073 entry[rhs] = -(boundValues[wPhaseIdx] + boundValues[nPhaseIdx]) * faceArea;
1074 }
1075 else
1076 {
1077 DUNE_THROW(Dune::NotImplemented, "No valid boundary condition type defined for pressure equation!");
1078 }
1079}
1080
1089template<class TypeTag>
1091{
1092 for (const auto& element : elements(problem_.gridView()))
1093 {
1094 int eIdxGlobal = problem_.variables().index(element);
1095
1096 CellData& cellData = problem_.variables().cellData(eIdxGlobal);
1097
1098 Scalar temperature = problem_.temperature(element);
1099
1100 // determine phase saturations from primary saturation variable
1101
1102 Scalar satW = cellData.saturation(wPhaseIdx);
1103
1104 Scalar pc = MaterialLaw::pc(problem_.spatialParams().materialLawParams(element), satW);
1105
1106 // determine phase pressures from primary pressure variable
1107 Scalar pressW = 0;
1108 Scalar pressNw = 0;
1109 if (pressureType_ == pw)
1110 {
1111 pressW = cellData.pressure(wPhaseIdx);
1112 pressNw = pressW + pc;
1113 }
1114 else if (pressureType_ == pn)
1115 {
1116 pressNw = cellData.pressure(nPhaseIdx);
1117 pressW = pressNw - pc;
1118 }
1119
1120 if (compressibility_)
1121 {
1122 FluidState& fluidState = cellData.fluidState();
1123 fluidState.setTemperature(temperature);
1124
1125 fluidState.setPressure(wPhaseIdx, pressW);
1126 fluidState.setPressure(nPhaseIdx, pressNw);
1127
1128 density_[wPhaseIdx] = FluidSystem::density(fluidState, wPhaseIdx);
1129 density_[nPhaseIdx] = FluidSystem::density(fluidState, nPhaseIdx);
1130
1131 viscosity_[wPhaseIdx]= FluidSystem::viscosity(fluidState, wPhaseIdx);
1132 viscosity_[nPhaseIdx] = FluidSystem::viscosity(fluidState, nPhaseIdx);
1133
1134 //store density
1135 fluidState.setDensity(wPhaseIdx, density_[wPhaseIdx]);
1136 fluidState.setDensity(nPhaseIdx, density_[nPhaseIdx]);
1137
1138 //store viscosity
1139 fluidState.setViscosity(wPhaseIdx, viscosity_[wPhaseIdx]);
1140 fluidState.setViscosity(nPhaseIdx, viscosity_[nPhaseIdx]);
1141 }
1142 else
1143 {
1144 cellData.setCapillaryPressure(pc);
1145
1146 if (pressureType_ != pGlobal)
1147 {
1148 cellData.setPressure(wPhaseIdx, pressW);
1149 cellData.setPressure(nPhaseIdx, pressNw);
1150 }
1151 }
1152
1153 // initialize mobilities
1154 Scalar mobilityW = MaterialLaw::krw(problem_.spatialParams().materialLawParams(element), satW) / viscosity_[wPhaseIdx];
1155 Scalar mobilityNw = MaterialLaw::krn(problem_.spatialParams().materialLawParams(element), satW) / viscosity_[nPhaseIdx];
1156
1157 if (compressibility_)
1158 {
1159 mobilityW *= density_[wPhaseIdx];
1160 mobilityNw *= density_[nPhaseIdx];
1161 }
1162
1163 // initialize mobilities
1164 cellData.setMobility(wPhaseIdx, mobilityW);
1165 cellData.setMobility(nPhaseIdx, mobilityNw);
1166
1167 // initialize fractional flow functions
1168 cellData.setFracFlowFunc(wPhaseIdx, mobilityW / (mobilityW + mobilityNw));
1169 cellData.setFracFlowFunc(nPhaseIdx, mobilityNw / (mobilityW + mobilityNw));
1170
1171 Scalar gravityDiff = (problem_.bBoxMax() - element.geometry().center()) * gravity_;
1172
1173 Scalar potW = pressW + gravityDiff * density_[wPhaseIdx];
1174 Scalar potNw = pressNw + gravityDiff * density_[nPhaseIdx];
1175
1176 if (pressureType_ == pGlobal)
1177 {
1178 potW = cellData.globalPressure() - cellData.fracFlowFunc(nPhaseIdx) * pc + gravityDiff * density_[wPhaseIdx];
1179 potNw = cellData.globalPressure() - cellData.fracFlowFunc(wPhaseIdx) * pc + gravityDiff * density_[nPhaseIdx];
1180 }
1181
1182 cellData.setPotential(wPhaseIdx, potW);
1183 cellData.setPotential(nPhaseIdx, potNw);
1184 }
1185}
1186
1187} // end namespace Dumux
1188#endif
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
std::string temperature() noexcept
I/O name of temperature for equilibrium models.
Definition: name.hh:51
std::string viscosity(int phaseIdx) noexcept
I/O name of viscosity for multiphase systems.
Definition: name.hh:74
std::string permeability() noexcept
I/O name of permeability.
Definition: name.hh:143
std::string density(int phaseIdx) noexcept
I/O name of density for multiphase systems.
Definition: name.hh:65
std::string porosity() noexcept
I/O name of porosity.
Definition: name.hh:139
Finite Volume discretization of a two-phase flow pressure equation of the sequential IMPES model.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:113
void storePressureSolution(const Element &element)
Stores the pressure solution of a cell.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:337
void storePressureSolution()
Globally stores the pressure solution.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:321
void getFlux(EntryType &entry, const Intersection &intersection, const CellData &cellData, const bool first)
Function which calculates the flux entry.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:720
FVPressure2P(Problem &problem)
Constructs a FVPressure2P object.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:546
void updateMaterialLaws()
Updates and stores constitutive relations.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:1090
void getFluxOnBoundary(EntryType &entry, const Intersection &intersection, const CellData &cellData, const bool first)
Function which calculates the boundary flux entry.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:844
void initialize(bool solveTwice=true)
Initializes the pressure model.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:200
void getSource(EntryType &entry, const Element &element, const CellData &cellData, const bool first)
Function which calculates the source entry.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:612
void getStorage(EntryType &entry, const Element &element, const CellData &cellData, const bool first)
Function which calculates the storage entry.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:656
void addOutputVtkFields(MultiWriter &writer)
Adds pressure output to the output file.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:415
void updateVelocity()
Velocity update.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:307
void update()
Pressure update.
Definition: 2p/sequential/diffusion/cellcentered/pressure.hh:263
The finite volume base class for the solution of a pressure equation.
Definition: sequential/cellcentered/pressure.hh:49
void assemble(bool first)
Function which assembles the system of equations to be solved.
Definition: sequential/cellcentered/pressure.hh:401
void initialize()
Initialize pressure model.
Definition: sequential/cellcentered/pressure.hh:213
PressureSolution & pressure()
Returns the vector containing the pressure solution.
Definition: sequential/cellcentered/pressure.hh:120
@ rhs
index for the right hand side entry
Definition: sequential/cellcentered/pressure.hh:88
@ matrix
index for the global matrix entry
Definition: sequential/cellcentered/pressure.hh:89
void solve()
Solves the global system of equations to get the spatial distribution of the pressure.
Definition: sequential/cellcentered/pressure.hh:527
void update()
Pressure update.
Definition: sequential/cellcentered/pressure.hh:228
Dune::FieldVector< Scalar, 2 > EntryType
Definition: sequential/cellcentered/pressure.hh:78
Specifies the properties for immiscible 2p diffusion/pressure models.
Finite Volume Diffusion Model.