Loading [MathJax]/extensions/tex2jax.js
3.4
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
2p/sequential/diffusion/cellcentered/velocity.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_FVVELOCITY2P_HH
25#define DUMUX_FVVELOCITY2P_HH
26
27#include <dune/common/float_cmp.hh>
28#include <dune/grid/common/gridenums.hh>
30
31namespace Dumux {
32
59template<class TypeTag>
61{
65
67
69
72
75 using PrimaryVariables = typename SolutionTypes::PrimaryVariables;
77
78 using Element = typename GridView::Traits::template Codim<0>::Entity;
79 using Intersection = typename GridView::Intersection;
80
81 using Geometry = typename Element::Geometry;
82 using JacobianTransposed = typename Geometry::JacobianTransposed;
83
84 enum
85 {
86 dim = GridView::dimension, dimWorld = GridView::dimensionworld
87 };
88
89 enum
90 {
91 pw = Indices::pressureW,
92 pn = Indices::pressureNw,
93 pGlobal = Indices::pressureGlobal,
94 vw = Indices::velocityW,
95 vn = Indices::velocityNw,
96 vt = Indices::velocityTotal,
97 sw = Indices::saturationW,
98 sn = Indices::saturationNw,
99 pressureIdx = Indices::pressureIdx,
100 saturationIdx = Indices::saturationIdx,
101 eqIdxPress = Indices::pressureEqIdx,
102 eqIdxSat = Indices::satEqIdx
103 };
104 enum
105 {
106 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx, numPhases = getPropValue<TypeTag, Properties::NumPhases>()
107 };
108
109 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
110 using GravityVector = Dune::FieldVector<Scalar, dimWorld>;
111 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
112
113public:
118 FVVelocity2P(Problem& problem) :
119 problem_(problem), gravity_(problem.gravity())
120 {
121 if (getPropValue<TypeTag, Properties::EnableCompressibility>() && velocityType_ == vt)
122 {
123 DUNE_THROW(Dune::NotImplemented,
124 "Total velocity - global pressure - model cannot be used with compressible fluids!");
125 }
126 if (velocityType_ != vw && velocityType_ != vn && velocityType_ != vt)
127 {
128 DUNE_THROW(Dune::NotImplemented, "Velocity type not supported!");
129 }
130
131 density_[wPhaseIdx] = 0.;
132 density_[nPhaseIdx] = 0.;
133 viscosity_[wPhaseIdx] = 0.;
134 viscosity_[nPhaseIdx] = 0.;
135
136 vtkOutputLevel_ = getParam<int>("Vtk.OutputLevel");
137 }
138
141 {
142 if (!compressibility_)
143 {
144 const auto element = *problem_.gridView().template begin<0> ();
145 FluidState fluidState;
146 fluidState.setPressure(wPhaseIdx, problem_.referencePressure(element));
147 fluidState.setPressure(nPhaseIdx, problem_.referencePressure(element));
148 fluidState.setTemperature(problem_.temperature(element));
149 fluidState.setSaturation(wPhaseIdx, 1.);
150 fluidState.setSaturation(nPhaseIdx, 0.);
151 density_[wPhaseIdx] = FluidSystem::density(fluidState, wPhaseIdx);
152 density_[nPhaseIdx] = FluidSystem::density(fluidState, nPhaseIdx);
153 viscosity_[wPhaseIdx] = FluidSystem::viscosity(fluidState, wPhaseIdx);
154 viscosity_[nPhaseIdx] = FluidSystem::viscosity(fluidState, nPhaseIdx);
155 }
156 }
157
159 void calculateVelocity(const Intersection&, CellData&);
160
162 void calculateVelocityOnBoundary(const Intersection&, CellData&);
163
170 {
171 return true;
172 }
173
182 template<class MultiWriter>
183 void addOutputVtkFields(MultiWriter &writer)
184 {
185 if (vtkOutputLevel_ > 0)
186 {
187 Dune::BlockVector < Dune::FieldVector<Scalar, dim> > &velocity = *(writer.template allocateManagedBuffer<Scalar,
188 dim>(problem_.gridView().size(0)));
189 Dune::BlockVector < Dune::FieldVector<Scalar, dim> > &velocitySecondPhase =
190 *(writer.template allocateManagedBuffer<Scalar, dim>(problem_.gridView().size(0)));
191
192 // compute update vector
193 for (const auto& element : elements(problem_.gridView()))
194 {
195 // cell index
196 int eIdxGlobal = problem_.variables().index(element);
197
198 CellData& cellData = problem_.variables().cellData(eIdxGlobal);
199
200 const typename Element::Geometry& geometry = element.geometry();
201
202 // get corresponding reference element
203 const auto refElement = referenceElement(geometry);
204
205 const int numberOfFaces=refElement.size(1);
206 std::vector<Scalar> fluxW(numberOfFaces,0);
207 std::vector<Scalar> fluxNw(numberOfFaces,0);
208
209 // run through all intersections with neighbors and boundary
210 for (const auto& intersection : intersections(problem_.gridView(), element))
211 {
212 int isIndex = intersection.indexInInside();
213
214 fluxW[isIndex] += intersection.geometry().volume()
215 * (intersection.centerUnitOuterNormal() * cellData.fluxData().velocity(wPhaseIdx, isIndex));
216 fluxNw[isIndex] += intersection.geometry().volume()
217 * (intersection.centerUnitOuterNormal() * cellData.fluxData().velocity(nPhaseIdx, isIndex));
218 }
219
220 // calculate velocity on reference element as the Raviart-Thomas-0
221 // interpolant of the fluxes
222 Dune::FieldVector<Scalar, dim> refVelocity;
223 // simplices
224 if (refElement.type().isSimplex()) {
225 for (int dimIdx = 0; dimIdx < dim; dimIdx++)
226 {
227 refVelocity[dimIdx] = -fluxW[dim - 1 - dimIdx];
228 for (int fIdx = 0; fIdx < dim + 1; fIdx++)
229 {
230 refVelocity[dimIdx] += fluxW[fIdx]/(dim + 1);
231 }
232 }
233 }
234 // cubes
235 else if (refElement.type().isCube()){
236 for (int i = 0; i < dim; i++)
237 refVelocity[i] = 0.5 * (fluxW[2*i + 1] - fluxW[2*i]);
238 }
239 // 3D prism and pyramids
240 else {
241 DUNE_THROW(Dune::NotImplemented, "velocity output for prism/pyramid not implemented");
242 }
243
244 const Dune::FieldVector<Scalar, dim> localPos =
245 refElement.position(0, 0);
246
247 // get the transposed Jacobian of the element mapping
248 const JacobianTransposed jacobianT =
249 geometry.jacobianTransposed(localPos);
250
251 // calculate the element velocity by the Piola transformation
252 Dune::FieldVector < Scalar, dim > elementVelocity(0);
253 jacobianT.umtv(refVelocity, elementVelocity);
254 elementVelocity /= geometry.integrationElement(localPos);
255
256 velocity[eIdxGlobal] = elementVelocity;
257
258 // calculate velocity on reference element as the Raviart-Thomas-0
259 // interpolant of the fluxes
260 // simplices
261 if (refElement.type().isSimplex()) {
262 for (int dimIdx = 0; dimIdx < dim; dimIdx++)
263 {
264 refVelocity[dimIdx] = -fluxNw[dim - 1 - dimIdx];
265 for (int fIdx = 0; fIdx < dim + 1; fIdx++)
266 {
267 refVelocity[dimIdx] += fluxNw[fIdx]/(dim + 1);
268 }
269 }
270 }
271 // cubes
272 else if (refElement.type().isCube()){
273 for (int i = 0; i < dim; i++)
274 refVelocity[i] = 0.5 * (fluxNw[2*i + 1] - fluxNw[2*i]);
275 }
276 // 3D prism and pyramids
277 else {
278 DUNE_THROW(Dune::NotImplemented, "velocity output for prism/pyramid not implemented");
279 }
280
281 // calculate the element velocity by the Piola transformation
282 elementVelocity = 0;
283 jacobianT.umtv(refVelocity, elementVelocity);
284 elementVelocity /= geometry.integrationElement(localPos);
285
286 velocitySecondPhase[eIdxGlobal] = elementVelocity;
287 }
288
289 // switch velocities
290 if (velocityType_ == vt)
291 {
292 writer.attachCellData(velocity, "total velocity", dim);
293 }
294 else
295 {
296 writer.attachCellData(velocity, "wetting-velocity", dim);
297 writer.attachCellData(velocitySecondPhase, "nonwetting-velocity", dim);
298 }
299 }
300
301 return;
302 }
303
304private:
305 Problem& problem_;
306 const GravityVector& gravity_;
307 Scalar density_[numPhases];
308 Scalar viscosity_[numPhases];
309
310 int vtkOutputLevel_;
311
313 static const int velocityType_ = getPropValue<TypeTag, Properties::VelocityFormulation>();
314 static const bool compressibility_ = getPropValue<TypeTag, Properties::EnableCompressibility>();
316 static const int pressureType_ = getPropValue<TypeTag, Properties::PressureFormulation>();
318 static const int saturationType_ = getPropValue<TypeTag, Properties::SaturationFormulation>();
319};
320
329template<class TypeTag>
330void FVVelocity2P<TypeTag>::calculateVelocity(const Intersection& intersection, CellData& cellData)
331{
332 auto elementI = intersection.inside();
333 auto elementJ = intersection.outside();
334
335 int eIdxGlobalJ = problem_.variables().index(elementJ);
336
337 CellData& cellDataJ = problem_.variables().cellData(eIdxGlobalJ);
338
339 // get global coordinates of cell centers
340 const GlobalPosition& globalPosI = (elementI).geometry().center();
341 const GlobalPosition& globalPosJ = (elementJ).geometry().center();
342
343 // get mobilities and fractional flow factors
344 Scalar lambdaWI = cellData.mobility(wPhaseIdx);
345 Scalar lambdaNwI = cellData.mobility(nPhaseIdx);
346 Scalar lambdaWJ = cellDataJ.mobility(wPhaseIdx);
347 Scalar lambdaNwJ = cellDataJ.mobility(nPhaseIdx);
348
349 // get capillary pressure
350 Scalar pcI = cellData.capillaryPressure();
351 Scalar pcJ = cellDataJ.capillaryPressure();
352
353 // get face index
354 int isIndexI = intersection.indexInInside();
355 int isIndexJ = intersection.indexInOutside();
356
357 // get face normal
358 const Dune::FieldVector<Scalar, dim>& unitOuterNormal = intersection.centerUnitOuterNormal();
359
360 // distance vector between barycenters
361 GlobalPosition distVec = globalPosJ - globalPosI;
362
363 // compute distance between cell centers
364 Scalar dist = distVec.two_norm();
365
366 // compute vectorized permeabilities
367 DimMatrix meanPermeability(0);
368
369 problem_.spatialParams().meanK(meanPermeability, problem_.spatialParams().intrinsicPermeability(elementI),
370 problem_.spatialParams().intrinsicPermeability(elementJ));
371
372 Dune::FieldVector<Scalar, dim> permeability(0);
373 meanPermeability.mv(unitOuterNormal, permeability);
374
375 // calculate potential gradients
376 Scalar potentialDiffW = cellData.potential(wPhaseIdx) - cellDataJ.potential(wPhaseIdx);
377 Scalar potentialDiffNw = cellData.potential(nPhaseIdx) - cellDataJ.potential(nPhaseIdx);
378
379 if (compressibility_)
380 {
381 density_[wPhaseIdx] = (potentialDiffW > 0.) ? cellData.density(wPhaseIdx) : cellDataJ.density(wPhaseIdx);
382 density_[nPhaseIdx] = (potentialDiffNw > 0.) ? cellData.density(nPhaseIdx) : cellDataJ.density(nPhaseIdx);
383
384 density_[wPhaseIdx] =
385 (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? 0.5 * (cellData.density(wPhaseIdx) + cellDataJ.density(wPhaseIdx)) :
386 density_[wPhaseIdx];
387 density_[nPhaseIdx] =
388 (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? 0.5 * (cellData.density(nPhaseIdx) + cellDataJ.density(nPhaseIdx)) :
389 density_[nPhaseIdx];
390
391 potentialDiffW = (cellData.pressure(wPhaseIdx) - cellDataJ.pressure(wPhaseIdx));
392 potentialDiffNw = (cellData.pressure(nPhaseIdx) - cellDataJ.pressure(nPhaseIdx));
393
394 potentialDiffW += density_[wPhaseIdx] * (distVec * gravity_); //delta z/delta x in unitOuterNormal[z]
395 potentialDiffNw += density_[nPhaseIdx] * (distVec * gravity_);
396 }
397
398 // store potentials for further calculations (velocity, saturation, ...)
399 cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndexI, potentialDiffW);
400 cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndexI, potentialDiffNw);
401
402 cellDataJ.fluxData().setUpwindPotential(wPhaseIdx, isIndexJ, -potentialDiffW);
403 cellDataJ.fluxData().setUpwindPotential(nPhaseIdx, isIndexJ, -potentialDiffNw);
404
405 // do the upwinding of the mobility depending on the phase potentials
406 Scalar lambdaW = (potentialDiffW > 0.) ? lambdaWI : lambdaWJ;
407 lambdaW = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? 0.5 * (lambdaWI + lambdaWJ) : lambdaW;
408 Scalar lambdaNw = (potentialDiffNw > 0.) ? lambdaNwI : lambdaNwJ;
409 lambdaNw = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? 0.5 * (lambdaNwI + lambdaNwJ) : lambdaNw;
410
411 if (compressibility_)
412 {
413 density_[wPhaseIdx] = (potentialDiffW > 0.) ? cellData.density(wPhaseIdx) : cellDataJ.density(wPhaseIdx);
414 density_[nPhaseIdx] = (potentialDiffNw > 0.) ? cellData.density(nPhaseIdx) : cellDataJ.density(nPhaseIdx);
415
416 density_[wPhaseIdx] =
417 (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? 0.5 * (cellData.density(wPhaseIdx) + cellDataJ.density(wPhaseIdx)) :
418 density_[wPhaseIdx];
419 density_[nPhaseIdx] =
420 (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? 0.5 * (cellData.density(nPhaseIdx) + cellDataJ.density(nPhaseIdx)) :
421 density_[nPhaseIdx];
422 }
423
424 Scalar scalarPerm = permeability.two_norm();
425
426 // calculate the gravity term
427 Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal);
428 Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal);
429
430 // calculate unit distVec
431 distVec /= dist;
432 Scalar areaScaling = (unitOuterNormal * distVec);
433 // this treatment of g allows to account for gravity flux through faces where the face normal
434 // has no z component (e.g. parallelepiped grids)
435 Scalar gravityTermW = (gravity_ * distVec) * density_[wPhaseIdx] * areaScaling;
436 Scalar gravityTermNw = (gravity_ * distVec) * density_[nPhaseIdx] * areaScaling;
437
438 // calculate velocity depending on the pressure used -> use pc = pn - pw
439 switch (pressureType_)
440 {
441 case pw:
442 {
443 velocityW *= lambdaW * scalarPerm
444 * ((cellData.pressure(wPhaseIdx) - cellDataJ.pressure(wPhaseIdx)) / dist + gravityTermW);
445 velocityNw *= lambdaNw * scalarPerm
446 * ((cellData.pressure(wPhaseIdx) - cellDataJ.pressure(wPhaseIdx)) / dist + gravityTermNw)
447 + 0.5 * (lambdaNwI + lambdaNwJ) * scalarPerm * (pcI - pcJ) / dist;
448 break;
449 }
450 case pn:
451 {
452 velocityW *= lambdaW * scalarPerm
453 * ((cellData.pressure(nPhaseIdx) - cellDataJ.pressure(nPhaseIdx)) / dist + gravityTermW)
454 - 0.5 * (lambdaWI + lambdaWJ) * scalarPerm * (pcI - pcJ) / dist;
455 velocityNw *= lambdaNw * scalarPerm
456 * ((cellData.pressure(nPhaseIdx) - cellDataJ.pressure(nPhaseIdx)) / dist + gravityTermNw);
457 break;
458 }
459 case pGlobal:
460 {
461 velocityW *= (lambdaW + lambdaNw) * scalarPerm * (cellData.globalPressure() - cellDataJ.globalPressure()) / dist
462 + scalarPerm * (lambdaW * gravityTermW + lambdaNw * gravityTermNw);
463 velocityNw = 0;
464 break;
465 }
466 }
467
468 // store velocities
469 cellData.fluxData().setVelocity(wPhaseIdx, isIndexI, velocityW);
470 cellData.fluxData().setVelocity(nPhaseIdx, isIndexI, velocityNw);
471 cellData.fluxData().setVelocityMarker(isIndexI);
472
473 cellDataJ.fluxData().setVelocity(wPhaseIdx, isIndexJ, velocityW);
474 cellDataJ.fluxData().setVelocity(nPhaseIdx, isIndexJ, velocityNw);
475 cellDataJ.fluxData().setVelocityMarker(isIndexJ);
476
477// printvector(std::cout, cellData.fluxData().velocity(), "velocity", "row", 4, 1, 3);
478 return;
479}
480
489template<class TypeTag>
490void FVVelocity2P<TypeTag>::calculateVelocityOnBoundary(const Intersection& intersection, CellData& cellData)
491{
492 auto element = intersection.inside();
493
494 // get face index
495 int isIndex = intersection.indexInInside();
496
497 // get face normal
498 const Dune::FieldVector<Scalar, dim>& unitOuterNormal = intersection.centerUnitOuterNormal();
499
500 BoundaryTypes bcType;
501 //get boundary type
502 problem_.boundaryTypes(bcType, intersection);
503 PrimaryVariables boundValues(0.0);
504
505 if (bcType.isDirichlet(eqIdxPress))
506 {
507 problem_.dirichlet(boundValues, intersection);
508
509 // get global coordinates of cell centers
510 const GlobalPosition& globalPosI = element.geometry().center();
511
512 // center of face in global coordinates
513 const GlobalPosition& globalPosJ = intersection.geometry().center();
514
515 // get mobilities and fractional flow factors
516 Scalar lambdaWI = cellData.mobility(wPhaseIdx);
517 Scalar lambdaNwI = cellData.mobility(nPhaseIdx);
518 Scalar fractionalWI = cellData.fracFlowFunc(wPhaseIdx);
519 Scalar fractionalNwI = cellData.fracFlowFunc(nPhaseIdx);
520
521 // get capillary pressure
522 Scalar pcI = cellData.capillaryPressure();
523
524 // distance vector between barycenters
525 GlobalPosition distVec = globalPosJ - globalPosI;
526
527 // compute distance between cell centers
528 Scalar dist = distVec.two_norm();
529
530 // permeability vector at boundary
531 // compute vectorized permeabilities
532 DimMatrix meanPermeability(0);
533
534 problem_.spatialParams().meanK(meanPermeability, problem_.spatialParams().intrinsicPermeability(element));
535
536 Dune::FieldVector<Scalar, dim> permeability(0);
537 meanPermeability.mv(unitOuterNormal, permeability);
538
539 // determine saturation at the boundary -> if no saturation is known directly at the boundary use the cell saturation
540 Scalar satW = 0;
541 Scalar satNw = 0;
542 if (bcType.isDirichlet(eqIdxSat))
543 {
544 switch (saturationType_)
545 {
546 case sw:
547 {
548 satW = boundValues[saturationIdx];
549 satNw = 1 - boundValues[saturationIdx];
550 break;
551 }
552 case sn:
553 {
554 satW = 1 - boundValues[saturationIdx];
555 satNw = boundValues[saturationIdx];
556 break;
557 }
558 }
559 }
560 else
561 {
562 satW = cellData.saturation(wPhaseIdx);
563 satNw = cellData.saturation(nPhaseIdx);
564 }
565
566 const Scalar pressBound = boundValues[pressureIdx];
567
568 const auto fluidMatrixInteraction = problem_.spatialParams().fluidMatrixInteractionAtPos(element.geometry().center());
569 const Scalar pcBound = fluidMatrixInteraction.pc(satW);
570
571 // determine phase pressures from primary pressure variable
572 Scalar pressWBound = 0;
573 Scalar pressNwBound = 0;
574 if (pressureType_ == pw)
575 {
576 pressWBound = pressBound;
577 pressNwBound = pressBound + pcBound;
578 }
579 else if (pressureType_ == pn)
580 {
581 pressWBound = pressBound - pcBound;
582 pressNwBound = pressBound;
583 }
584
585 // get temperature at current position
586 const Scalar temperature = problem_.temperature(element);
587
588 Scalar densityWBound = density_[wPhaseIdx];
589 Scalar densityNwBound = density_[nPhaseIdx];
590 Scalar viscosityWBound = viscosity_[wPhaseIdx];
591 Scalar viscosityNwBound = viscosity_[nPhaseIdx];
592
593 if (compressibility_)
594 {
595 FluidState fluidState;
596 fluidState.setSaturation(wPhaseIdx, satW);
597 fluidState.setSaturation(nPhaseIdx, satNw);
598 fluidState.setTemperature(temperature);
599 fluidState.setPressure(wPhaseIdx, pressWBound);
600 fluidState.setPressure(nPhaseIdx, pressNwBound);
601
602 densityWBound = FluidSystem::density(fluidState, wPhaseIdx);
603 densityNwBound = FluidSystem::density(fluidState, nPhaseIdx);
604 viscosityWBound = FluidSystem::viscosity(fluidState, wPhaseIdx) / densityWBound;
605 viscosityNwBound = FluidSystem::viscosity(fluidState, nPhaseIdx) / densityNwBound;
606 }
607
608 Scalar lambdaWBound = fluidMatrixInteraction.krw(satW)
609 / viscosityWBound;
610 Scalar lambdaNwBound = fluidMatrixInteraction.krn(satW)
611 / viscosityNwBound;
612
613 Scalar potentialDiffW = cellData.fluxData().upwindPotential(wPhaseIdx, isIndex);
614 Scalar potentialDiffNw = cellData.fluxData().upwindPotential(nPhaseIdx, isIndex);
615
616 if (compressibility_)
617 {
618 density_[wPhaseIdx] = (potentialDiffW > 0.) ? cellData.density(wPhaseIdx) : densityWBound;
619 density_[wPhaseIdx] =
620 (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? 0.5 * (cellData.density(wPhaseIdx) + densityWBound) : density_[wPhaseIdx];
621 density_[nPhaseIdx] = (potentialDiffNw > 0.) ? cellData.density(nPhaseIdx) : densityNwBound;
622 density_[nPhaseIdx] =
623 (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? 0.5 * (cellData.density(nPhaseIdx) + densityNwBound) : density_[nPhaseIdx];
624 }
625
626 // calculate potential gradient
627 if (pressureType_ == pGlobal)
628 {
629 potentialDiffW = (cellData.globalPressure() - pressBound - fractionalNwI * (pcI - pcBound));
630 potentialDiffNw = (cellData.globalPressure() - pressBound + fractionalWI * (pcI - pcBound));
631 }
632 else
633 {
634 potentialDiffW = (cellData.pressure(wPhaseIdx) - pressWBound);
635 potentialDiffNw = (cellData.pressure(nPhaseIdx) - pressNwBound);
636 }
637
638 potentialDiffW += density_[wPhaseIdx] * (distVec * gravity_);
639 potentialDiffNw += density_[nPhaseIdx] * (distVec * gravity_);
640
641 // store potential gradients for further calculations
642 cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, potentialDiffW);
643 cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, potentialDiffNw);
644
645 // do the upwinding of the mobility depending on the phase potentials
646 Scalar lambdaW = (potentialDiffW > 0.) ? lambdaWI : lambdaWBound;
647 lambdaW = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? 0.5 * (lambdaWI + lambdaWBound) : lambdaW;
648 Scalar lambdaNw = (potentialDiffNw > 0.) ? lambdaNwI : lambdaNwBound;
649 lambdaNw = (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? 0.5 * (lambdaNwI + lambdaNwBound) : lambdaNw;
650
651 if (compressibility_)
652 {
653 density_[wPhaseIdx] = (potentialDiffW > 0.) ? cellData.density(wPhaseIdx) : densityWBound;
654 density_[wPhaseIdx] =
655 (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffW, 0.0, 1.0e-30)) ? 0.5 * (cellData.density(wPhaseIdx) + densityWBound) : density_[wPhaseIdx];
656 density_[nPhaseIdx] = (potentialDiffNw > 0.) ? cellData.density(nPhaseIdx) : densityNwBound;
657 density_[nPhaseIdx] =
658 (Dune::FloatCmp::eq<Scalar, Dune::FloatCmp::absolute>(potentialDiffNw, 0.0, 1.0e-30)) ? 0.5 * (cellData.density(nPhaseIdx) + densityNwBound) : density_[nPhaseIdx];
659 }
660
661 const Scalar scalarPerm = permeability.two_norm();
662
663 // calculate the gravity term
664 Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal);
665 Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal);
666
667 // calculate unit distVec
668 distVec /= dist;
669 Scalar areaScaling = (unitOuterNormal * distVec);
670 // this treatment of g allows to account for gravity flux through faces where the face normal
671 // has no z component (e.g. parallelepiped grids)
672 Scalar gravityTermW = (gravity_ * distVec) * density_[wPhaseIdx] * areaScaling;
673 Scalar gravityTermNw = (gravity_ * distVec) * density_[nPhaseIdx] * areaScaling;
674
675 // calculate velocity depending on the pressure used -> use pc = pn - pw
676 switch (pressureType_)
677 {
678 case pw:
679 {
680 velocityW *= lambdaW * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermW);
681 velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(wPhaseIdx) - pressBound) / dist + gravityTermNw)
682 + 0.5 * (lambdaNwI + lambdaNwBound) * scalarPerm * (pcI - pcBound) / dist;
683 break;
684 }
685 case pn:
686 {
687 velocityW *= lambdaW * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermW)
688 - 0.5 * (lambdaWI + lambdaWBound) * scalarPerm * (pcI - pcBound) / dist;
689 velocityNw *= lambdaNw * scalarPerm * ((cellData.pressure(nPhaseIdx) - pressBound) / dist + gravityTermNw);
690 break;
691 }
692 case pGlobal:
693 {
694 velocityW *= (lambdaW + lambdaNw) * scalarPerm * (cellData.globalPressure() - pressBound) / dist
695 + scalarPerm * (lambdaW * gravityTermW + lambdaNw * gravityTermNw);
696 velocityNw = 0;
697 break;
698 }
699 }
700
701 // store velocities
702 cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW);
703 cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw);
704 cellData.fluxData().setVelocityMarker(isIndex);
705
706 } // end Dirichlet boundary
707
708 else if (bcType.isNeumann(eqIdxPress))
709 {
710 problem_.neumann(boundValues, intersection);
711
712 Dune::FieldVector<Scalar, dimWorld> velocityW(unitOuterNormal);
713 Dune::FieldVector<Scalar, dimWorld> velocityNw(unitOuterNormal);
714
715 velocityW *= boundValues[wPhaseIdx];
716 velocityNw *= boundValues[nPhaseIdx];
717
718 if (!compressibility_)
719 {
720 velocityW /= density_[wPhaseIdx];
721 velocityNw /= density_[nPhaseIdx];
722 }
723
724 // store potential gradients for further calculations
725 cellData.fluxData().setUpwindPotential(wPhaseIdx, isIndex, boundValues[wPhaseIdx]);
726 cellData.fluxData().setUpwindPotential(nPhaseIdx, isIndex, boundValues[nPhaseIdx]);
727
728 cellData.fluxData().setVelocity(wPhaseIdx, isIndex, velocityW);
729 cellData.fluxData().setVelocity(nPhaseIdx, isIndex, velocityNw);
730 cellData.fluxData().setVelocityMarker(isIndex);
731 } // end Neumann boundary
732 else
733 {
734 DUNE_THROW(Dune::NotImplemented, "No valid boundary condition type defined for pressure equation!");
735 }
736
737// printvector(std::cout, cellData.fluxData().velocity(), "velocity", "row", 4, 1, 3);
738 return;
739}
740} // end namespace Dumux
741#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 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
Determines the velocity from a finite volume solution of the pressure equation of a sequential model ...
Definition: 2p/sequential/diffusion/cellcentered/velocity.hh:61
void addOutputVtkFields(MultiWriter &writer)
Adds velocity output to the output file.
Definition: 2p/sequential/diffusion/cellcentered/velocity.hh:183
void calculateVelocity(const Intersection &, CellData &)
Calculates the velocity at a cell-cell interface.
Definition: 2p/sequential/diffusion/cellcentered/velocity.hh:330
bool calculateVelocityInTransport()
Indicates if velocity is reconstructed in the pressure step or in the transport step.
Definition: 2p/sequential/diffusion/cellcentered/velocity.hh:169
FVVelocity2P(Problem &problem)
Constructs a FVVelocity2P object.
Definition: 2p/sequential/diffusion/cellcentered/velocity.hh:118
void initialize()
For initialization.
Definition: 2p/sequential/diffusion/cellcentered/velocity.hh:140
void calculateVelocityOnBoundary(const Intersection &, CellData &)
Calculates the velocity at a boundary.
Definition: 2p/sequential/diffusion/cellcentered/velocity.hh:490
Specifies the properties for immiscible 2p diffusion/pressure models.