3.4
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
lmethod/2dpressurevelocity.hh
Go to the documentation of this file.
1/*****************************************************************************
2 * See the file COPYING for full copying permissions. *
3 * *
4 * This program is free software: you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation, either version 3 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
16 *****************************************************************************/
22#ifndef DUMUX_MPFAL2DPRESSUREVELOCITY2P_HH
23#define DUMUX_MPFAL2DPRESSUREVELOCITY2P_HH
24
25#include <dune/common/float_cmp.hh>
26
27#include "2dpressure.hh"
28#include "2dvelocity.hh"
29
30namespace Dumux {
31
45template<class TypeTag> class FvMpfaL2dPressureVelocity2p: public FvMpfaL2dPressure2p<TypeTag>
46{
48
50
51 enum
52 {
53 dim = GridView::dimension, dimWorld = GridView::dimensionworld
54 };
55
61 using PrimaryVariables = typename SolutionTypes::PrimaryVariables;
62
64
66
69
70 using IndexSet = typename GridView::IndexSet;
71 using Intersection = typename GridView::Intersection;
72
74
75 enum
76 {
77 pw = Indices::pressureW,
78 pn = Indices::pressureNw,
79 sw = Indices::saturationW,
80 sn = Indices::saturationNw,
81 wPhaseIdx = Indices::wPhaseIdx,
82 nPhaseIdx = Indices::nPhaseIdx,
83 pressureIdx = Indices::pressureIdx,
84 saturationIdx = Indices::saturationIdx,
85 pressEqIdx = Indices::pressureEqIdx,
86 satEqIdx = Indices::satEqIdx,
87 numPhases = getPropValue<TypeTag, Properties::NumPhases>()
88 };
89
90 using Element = typename GridView::template Codim<0>::Entity;
91
92 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
93 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
94
95public:
101 FvMpfaL2dPressureVelocity2p(Problem& problem) :
102 ParentType(problem), problem_(problem), velocity_(problem)
103 {
104 density_[wPhaseIdx] = 0.;
105 density_[nPhaseIdx] = 0.;
106 viscosity_[wPhaseIdx] = 0.;
107 viscosity_[nPhaseIdx] = 0.;
108
109 calcVelocityInTransport_ = getParam<bool>("MPFA.CalcVelocityInTransport");
110 }
111
113 void calculateVelocity();
114
116 void calculateVelocity(const Intersection&, CellData&);
117 void calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData);
118
121 {
122 this->updateMaterialLaws();
123
124 this->storePressureSolution();
125
128 }
129
136 {
137 const auto element = *problem_.gridView().template begin<0>();
138 FluidState fluidState;
139 fluidState.setPressure(wPhaseIdx, problem_.referencePressure(element));
140 fluidState.setPressure(nPhaseIdx, problem_.referencePressure(element));
141 fluidState.setTemperature(problem_.temperature(element));
142 fluidState.setSaturation(wPhaseIdx, 1.);
143 fluidState.setSaturation(nPhaseIdx, 0.);
144 density_[wPhaseIdx] = FluidSystem::density(fluidState, wPhaseIdx);
145 density_[nPhaseIdx] = FluidSystem::density(fluidState, nPhaseIdx);
146 viscosity_[wPhaseIdx] = FluidSystem::viscosity(fluidState, wPhaseIdx);
147 viscosity_[nPhaseIdx] = FluidSystem::viscosity(fluidState, nPhaseIdx);
148
150 velocity_.initialize();
153
154 return;
155 }
156
162 void update()
163 {
167 }
168
175 {
176 return calcVelocityInTransport_;
177 }
178
189 template<class MultiWriter>
190 void addOutputVtkFields(MultiWriter &writer)
191 {
193 velocity_.addOutputVtkFields(writer);
194 }
195
196private:
197 Problem& problem_;
199
200 Scalar density_[numPhases];
201 Scalar viscosity_[numPhases];
202 bool calcVelocityInTransport_;
203
205 static const int pressureType_ = getPropValue<TypeTag, Properties::PressureFormulation>();
207 static const int saturationType_ = getPropValue<TypeTag, Properties::SaturationFormulation>();
208};
209// end of template
210
211
217template<class TypeTag>
219{
220 // run through all elements
221 for (const auto& vertex : vertices(problem_.gridView()))
222 {
223 int vIdxGlobal = problem_.variables().index(vertex);
224
225 InteractionVolume& interactionVolume = this->interactionVolumes_[vIdxGlobal];
226
227 if (interactionVolume.isInnerVolume())
228 {
229 auto element1 = interactionVolume.getSubVolumeElement(0);
230 auto element2 = interactionVolume.getSubVolumeElement(1);
231 auto element3 = interactionVolume.getSubVolumeElement(2);
232 auto element4 = interactionVolume.getSubVolumeElement(3);
233
234 // cell index
235 int eIdxGlobal1 = problem_.variables().index(element1);
236 int eIdxGlobal2 = problem_.variables().index(element2);
237 int eIdxGlobal3 = problem_.variables().index(element3);
238 int eIdxGlobal4 = problem_.variables().index(element4);
239
240 //get the cell Data
241 CellData& cellData1 = problem_.variables().cellData(eIdxGlobal1);
242 CellData& cellData2 = problem_.variables().cellData(eIdxGlobal2);
243 CellData& cellData3 = problem_.variables().cellData(eIdxGlobal3);
244 CellData& cellData4 = problem_.variables().cellData(eIdxGlobal4);
245
246 velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, cellData1, cellData2,
247 cellData3, cellData4, this->innerBoundaryVolumeFaces_);
248
249 }
250 // at least one face on boundary!
251 else
252 {
253 for (int elemIdx = 0; elemIdx < 2 * dim; elemIdx++)
254 {
255 bool isOutside = false;
256 for (int fIdx = 0; fIdx < dim; fIdx++)
257 {
258 int intVolFaceIdx = interactionVolume.getFaceIndexFromSubVolume(elemIdx, fIdx);
259 if (interactionVolume.isOutsideFace(intVolFaceIdx))
260 {
261 isOutside = true;
262 break;
263 }
264 }
265 if (isOutside)
266 {
267 continue;
268 }
269 // cell index
270 int eIdxGlobal = problem_.variables().index(interactionVolume.getSubVolumeElement(elemIdx));
271 //get the cell Data
272 CellData& cellData = problem_.variables().cellData(eIdxGlobal);
273
274 velocity_.calculateBoundaryInteractionVolumeVelocity(interactionVolume, cellData, elemIdx);
275 }
276
277 } // end boundaries
278
279 } // end vertex iterator
280
281// }
282 return;
283} // end method calcTotalVelocity
284
293template<class TypeTag>
294void FvMpfaL2dPressureVelocity2p<TypeTag>::calculateVelocity(const Intersection& intersection, CellData& cellData)
295{
296 int numVertices = intersection.geometry().corners();
297
298 auto elementI = intersection.inside();
299 auto elementJ = intersection.outside();
300
301 int eIdxGlobalI = problem_.variables().index(elementI);
302 int eIdxGlobalJ = problem_.variables().index(elementJ);
303
304 CellData& cellDataJ = problem_.variables().cellData(eIdxGlobalJ);
305
306 const auto refElement = referenceElement(elementI);
307
308 int indexInInside = intersection.indexInInside();
309 int indexInOutside = intersection.indexInOutside();
310
311 Dune::FieldVector<CellData, 4> cellDataTemp;
312
313 for (int vIdx = 0; vIdx < numVertices; vIdx++)
314 {
315 int localVertIdx = refElement.subEntity(indexInInside, dim - 1, vIdx, dim);
316
317 int vIdxGlobal = problem_.variables().index(elementI.template subEntity<dim>(localVertIdx));
318
319 InteractionVolume& interactionVolume = this->interactionVolumes_[vIdxGlobal];
320
321 if (interactionVolume.isInnerVolume())
322 {
323
324 auto element1 = interactionVolume.getSubVolumeElement(0);
325 auto element2 = interactionVolume.getSubVolumeElement(1);
326 auto element3 = interactionVolume.getSubVolumeElement(2);
327 auto element4 = interactionVolume.getSubVolumeElement(3);
328
329 // cell index
330 int eIdxGlobal[4];
331 eIdxGlobal[0] = problem_.variables().index(element1);
332 eIdxGlobal[1] = problem_.variables().index(element2);
333 eIdxGlobal[2] = problem_.variables().index(element3);
334 eIdxGlobal[3] = problem_.variables().index(element4);
335
336 //get the cell Data
337 cellDataTemp[0] = problem_.variables().cellData(eIdxGlobal[0]);
338 cellDataTemp[1] = problem_.variables().cellData(eIdxGlobal[1]);
339 cellDataTemp[2] = problem_.variables().cellData(eIdxGlobal[2]);
340 cellDataTemp[3] = problem_.variables().cellData(eIdxGlobal[3]);
341
342 velocity_.calculateInnerInteractionVolumeVelocity(interactionVolume, cellDataTemp[0], cellDataTemp[1],
343 cellDataTemp[2], cellDataTemp[3], this->innerBoundaryVolumeFaces_);
344
345 for (int i = 0; i < 4; i++)
346 {
347 if (eIdxGlobal[i] == eIdxGlobalI)
348 {
349 cellData.fluxData().setVelocity(wPhaseIdx, indexInInside,
350 cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInInside));
351 cellData.fluxData().setVelocity(nPhaseIdx, indexInInside,
352 cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInInside));
353 cellData.fluxData().setUpwindPotential(wPhaseIdx, indexInInside,
354 cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInInside));
355 cellData.fluxData().setUpwindPotential(nPhaseIdx, indexInInside,
356 cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInInside));
357 }
358 else if (eIdxGlobal[i] == eIdxGlobalJ)
359 {
360 cellDataJ.fluxData().setVelocity(wPhaseIdx, indexInOutside,
361 cellDataTemp[i].fluxData().velocity(wPhaseIdx, indexInOutside));
362 cellDataJ.fluxData().setVelocity(nPhaseIdx, indexInOutside,
363 cellDataTemp[i].fluxData().velocity(nPhaseIdx, indexInOutside));
364 cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, indexInOutside,
365 cellDataTemp[i].fluxData().upwindPotential(wPhaseIdx, indexInOutside));
366 cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, indexInOutside,
367 cellDataTemp[i].fluxData().upwindPotential(nPhaseIdx, indexInOutside));
368 }
369 }
370 }
371 }
372 cellData.fluxData().setVelocityMarker(indexInInside);
373 cellDataJ.fluxData().setVelocityMarker(indexInOutside);
374}
375
384template<class TypeTag>
385void FvMpfaL2dPressureVelocity2p<TypeTag>::calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData)
386{
387 auto element = intersection.inside();
388
389 //get face index
390 int isIndex = intersection.indexInInside();
391
392 //get face normal
393 const Dune::FieldVector<Scalar, dim>& unitOuterNormal = intersection.centerUnitOuterNormal();
394
395 BoundaryTypes bcType;
396 //get boundary type
397 problem_.boundaryTypes(bcType, intersection);
398 PrimaryVariables boundValues(0.0);
399
400 if (bcType.isDirichlet(pressEqIdx))
401 {
402 problem_.dirichlet(boundValues, intersection);
403
404 // get global coordinates of cell centers
405 const GlobalPosition& globalPosI = element.geometry().center();
406
407 // center of face in global coordinates
408 const GlobalPosition& globalPosJ = intersection.geometry().center();
409
410 // get mobilities and fractional flow factors
411 Scalar lambdaWI = cellData.mobility(wPhaseIdx);
412 Scalar lambdaNwI = cellData.mobility(nPhaseIdx);
413
414 // get capillary pressure
415 Scalar pcI = cellData.capillaryPressure();
416
417 // distance vector between barycenters
418 GlobalPosition distVec = globalPosJ - globalPosI;
419
420 // compute distance between cell centers
421 Scalar dist = distVec.two_norm();
422
423 //permeability vector at boundary
424 // compute vectorized permeabilities
425 DimMatrix meanPermeability(0);
426
427 problem_.spatialParams().meanK(meanPermeability, problem_.spatialParams().intrinsicPermeability(element));
428
429 Dune::FieldVector<Scalar, dim> permeability(0);
430 meanPermeability.mv(unitOuterNormal, permeability);
431
432 //determine saturation at the boundary -> if no saturation is known directly at the boundary use the cell saturation
433 Scalar satW = 0;
434 if (bcType.isDirichlet(satEqIdx))
435 {
436 switch (saturationType_)
437 {
438 case sw:
439 {
440 satW = boundValues[saturationIdx];
441 break;
442 }
443 case sn:
444 {
445 satW = 1 - boundValues[saturationIdx];
446 break;
447 }
448 }
449 }
450 else
451 {
452 satW = cellData.saturation(wPhaseIdx);
453 }
454
455 const Scalar pressBound = boundValues[pressureIdx];
456
457 const auto fluidMatrixInteraction = problem_.spatialParams().fluidMatrixInteractionAtPos(element.geometry().center());
458 const Scalar pcBound = fluidMatrixInteraction.pc(satW);
459
460 //determine phase pressures from primary pressure variable
461 Scalar pressWBound = 0;
462 Scalar pressNwBound = 0;
463 if (pressureType_ == pw)
464 {
465 pressWBound = pressBound;
466 pressNwBound = pressBound + pcBound;
467 }
468 else if (pressureType_ == pn)
469 {
470 pressWBound = pressBound - pcBound;
471 pressNwBound = pressBound;
472 }
473
474 const Scalar lambdaWBound = fluidMatrixInteraction.krw(satW) / viscosity_[wPhaseIdx];
475 const Scalar lambdaNwBound = fluidMatrixInteraction.krn(satW) / viscosity_[nPhaseIdx];
476
477 Scalar potentialDiffW = cellData.fluxData().upwindPotential(wPhaseIdx, isIndex);
478 Scalar potentialDiffNw = cellData.fluxData().upwindPotential(nPhaseIdx, isIndex);
479
480 //calculate potential gradient
481 potentialDiffW = (cellData.pressure(wPhaseIdx) - pressWBound);
482 potentialDiffNw = (cellData.pressure(nPhaseIdx) - pressNwBound);
483
484 potentialDiffW += density_[wPhaseIdx] * (distVec * problem_.gravity());
485 potentialDiffNw += density_[nPhaseIdx] * (distVec * problem_.gravity());
486
487 //store potential gradients for further calculations
488 cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, potentialDiffW);
489 cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, potentialDiffNw);
490
491 //do the upwinding of the mobility depending on the phase potentials
492 Scalar lambdaW = (potentialDiffW > 0.) ? lambdaWI : lambdaWBound;
493 lambdaW = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? 0.5 * (lambdaWI + lambdaWBound) : lambdaW;
494 Scalar lambdaNw = (potentialDiffNw > 0.) ? lambdaNwI : lambdaNwBound;
495 lambdaNw = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? 0.5 * (lambdaNwI + lambdaNwBound) : lambdaNw;
496
497
498 Scalar scalarPerm = permeability.two_norm();
499
500 //calculate the gravity term
501 Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal);
502 Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal);
503
504 //calculate unit distVec
505 distVec /= dist;
506 Scalar areaScaling = (unitOuterNormal * distVec);
507 //this treatment of g allows to account for gravity flux through faces where the face normal has no z component (e.g. parallelepiped grids)
508 Scalar gravityTermW = (problem_.gravity() * distVec) * density_[wPhaseIdx] * areaScaling;
509 Scalar gravityTermNw = (problem_.gravity() * distVec) * density_[nPhaseIdx] * areaScaling;
510
511 //calculate velocity depending on the pressure used -> use pc = pn - pw
512 switch (pressureType_)
513 {
514 case pw:
515 {
516 velocityW *= lambdaW * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermW);
517 velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermNw)
518 + 0.5 * (lambdaNwI + lambdaNwBound) * scalarPerm * (pcI - pcBound) / dist;
519 break;
520 }
521 case pn:
522 {
523 velocityW *= lambdaW * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermW)
524 - 0.5 * (lambdaWI + lambdaWBound) * scalarPerm * (pcI - pcBound) / dist;
525 velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermNw);
526 break;
527 }
528 }
529
530 //store velocities
531 cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW);
532 cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw);
533 cellData.fluxData().setVelocityMarker(isIndex);
534
535 } //end dirichlet boundary
536
537 else if (bcType.isNeumann(pressEqIdx))
538 {
539 problem_.neumann(boundValues, intersection);
540
541 Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal);
542 Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal);
543
544 velocityW *= boundValues[wPhaseIdx];
545 velocityNw *= boundValues[nPhaseIdx];
546
547 velocityW /= density_[wPhaseIdx];
548 velocityNw /= density_[nPhaseIdx];
549
550 //store potential gradients for further calculations
551 cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, boundValues[wPhaseIdx]);
552 cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, boundValues[nPhaseIdx]);
553
554 cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW);
555 cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw);
556 cellData.fluxData().setVelocityMarker(isIndex);
557 } //end neumann boundary
558 else
559 {
560 DUNE_THROW(Dune::NotImplemented, "No valid boundary condition type defined for pressure equation!");
561 }
562}
563
564} // end namespace Dumux
565#endif
Definition: adapt.hh:29
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type GetProp
get the type of a property
Definition: propertysystem.hh:141
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
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
Finite volume MPFA L-method discretization of a two-phase flow pressure equation of the sequential IM...
Definition: lmethod/2dpressure.hh:72
void update()
Pressure update.
Definition: lmethod/2dpressure.hh:288
void initialize()
Initializes the pressure model.
Definition: lmethod/2dpressure.hh:191
FVMPFALInteractionVolume< TypeTag > InteractionVolume
Type of the interaction volume objects.
Definition: lmethod/2dpressure.hh:148
void storePressureSolution()
Globally stores the pressure solution.
Definition: lmethod/2dpressure.hh:225
void addOutputVtkFields(MultiWriter &writer)
Adds pressure output to the output file.
Definition: lmethod/2dpressure.hh:337
void updateMaterialLaws()
constitutive functions are initialized and stored in the variables object
Definition: lmethod/2dpressure.hh:1828
Class for the calculation of velocities from the pressure solution of an IMPES scheme using a MPFA L-...
Definition: lmethod/2dpressurevelocity.hh:46
void updateVelocity()
Function for updating the velocity field if iterations are necessary in the transport solution.
Definition: lmethod/2dpressurevelocity.hh:120
void calculateVelocityOnBoundary(const Intersection &intersection, CellData &cellData)
Calculates the velocity at a boundary.
Definition: lmethod/2dpressurevelocity.hh:385
FvMpfaL2dPressureVelocity2p(Problem &problem)
Constructs a FvMpfaL2dPressureVelocity2p object.
Definition: lmethod/2dpressurevelocity.hh:101
void initialize()
Initializes pressure and velocity.
Definition: lmethod/2dpressurevelocity.hh:135
void addOutputVtkFields(MultiWriter &writer)
Adds velocity output to the output file.
Definition: lmethod/2dpressurevelocity.hh:190
bool calculateVelocityInTransport()
Indicates if velocity is reconstructed in the pressure step or in the transport step.
Definition: lmethod/2dpressurevelocity.hh:174
void calculateVelocity()
Calculates the velocities at all cell-cell interfaces.
Definition: lmethod/2dpressurevelocity.hh:218
void update()
Pressure and velocity update.
Definition: lmethod/2dpressurevelocity.hh:162
Class for calculating 2-d velocities from cell-wise constant pressure values.
Definition: lmethod/2dvelocity.hh:58
Class including the information of an interaction volume of a MPFA L-method that does not change with...
Definition: linteractionvolume.hh:41
bool isInnerVolume()
Returns true if the interaction volume is completely inside the model domain.
Definition: linteractionvolume.hh:316
Element getSubVolumeElement(int subVolumeIdx)
Get an element of the interaction volume.
Definition: linteractionvolume.hh:281
int getFaceIndexFromSubVolume(int subVolumeIdx, int subVolumeFaceIdx)
Map from local interaction volume numbering on element to numbering on interaction volume.
Definition: linteractionvolume.hh:270
bool isOutsideFace(int subVolumeFaceIdx)
Returns true if an interaction volume flux face is outside the model domain.
Definition: linteractionvolume.hh:301
The finite volume base class for the solution of a pressure equation.
Definition: sequential/cellcentered/pressure.hh:49
Finite volume MPFA O-method discretization of a two-phase pressure equation of the sequential IMPES m...
Velocity calculation using a 2-d MPFA O-method.