forchheimerfluxmodule.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  Copyright (C) 2008-2013 by Andreas Lauser
5 
6  This file is part of the Open Porous Media project (OPM).
7 
8  OPM is free software: you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation, either version 2 of the License, or
11  (at your option) any later version.
12 
13  OPM is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with OPM. If not, see <http://www.gnu.org/licenses/>.
20 */
28 #ifndef EWOMS_FORCHHEIMER_FLUX_MODULE_HH
29 #define EWOMS_FORCHHEIMER_FLUX_MODULE_HH
30 
32 #include "darcyfluxmodule.hh"
33 
34 
35 #include <dune/common/fvector.hh>
36 #include <dune/common/fmatrix.hh>
37 
38 #include <cmath>
39 
40 namespace Ewoms {
41 namespace Properties {
42 NEW_PROP_TAG(MaterialLaw);
43 }
44 }
45 
46 namespace Ewoms {
47 template <class TypeTag>
49 
50 template <class TypeTag>
52 
53 template <class TypeTag>
55 
60 template <class TypeTag>
62 {
66 
70  static void registerParameters()
71  {}
72 };
73 
79 template <class TypeTag>
80 class ForchheimerBaseProblem
81 {
82  typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
83 
84 public:
94  template <class Context>
95  Scalar ergunCoefficient(Context &context, int spaceIdx, int timeIdx) const
96  {
97  OPM_THROW(std::logic_error,
98  "Not implemented: Problem::ergunCoefficient()");
99  }
100 
112  template <class Context>
113  Scalar mobilityPassabilityRatio(Context &context, int spaceIdx, int timeIdx,
114  int phaseIdx) const
115  {
116  return 1.0 / context.intensiveQuantities(spaceIdx, timeIdx).fluidState().viscosity(
117  phaseIdx);
118  }
119 };
120 
125 template <class TypeTag>
126 class ForchheimerIntensiveQuantities
127 {
128  typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
129  typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
130 
131  enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) };
132 
133 public:
141  Scalar ergunCoefficient() const
142  {
143  return ergunCoefficient_;
144  }
145 
149  Scalar mobilityPassabilityRatio(int phaseIdx) const
150  {
151  return mobilityPassabilityRatio_[phaseIdx];
152  }
153 
154 protected:
155  void update_(const ElementContext &elemCtx, int dofIdx, int timeIdx)
156  {
157  const auto &problem = elemCtx.problem();
158  ergunCoefficient_ = problem.ergunCoefficient(elemCtx, dofIdx, timeIdx);
159 
160  for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
161  mobilityPassabilityRatio_[phaseIdx] =
162  problem.mobilityPassabilityRatio(elemCtx,
163  dofIdx,
164  timeIdx,
165  phaseIdx);
166  }
167 
168 private:
169  Scalar ergunCoefficient_;
170  Scalar mobilityPassabilityRatio_[numPhases];
171 };
172 
215 template <class TypeTag>
216 class ForchheimerExtensiveQuantities
217  : public DarcyExtensiveQuantities<TypeTag>
218 {
219  typedef DarcyExtensiveQuantities<TypeTag> DarcyExtQuants;
220  typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
221  typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw;
222  typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
223  typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
224  typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
225  typedef typename GET_PROP_TYPE(TypeTag, ExtensiveQuantities) Implementation;
226 
227 
228  enum { dimWorld = GridView::dimensionworld };
229  enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) };
230 
231  typedef Dune::FieldVector<Scalar, dimWorld> DimVector;
232  typedef Dune::FieldMatrix<Scalar, dimWorld, dimWorld> DimMatrix;
233 
234 public:
238  Scalar ergunCoefficient() const
239  { return ergunCoefficient_; }
240 
247  Scalar mobilityPassabilityRatio(int phaseIdx) const
248  { return mobilityPassabilityRatio_[phaseIdx]; }
249 
250 protected:
251  void calculateGradients_(const ElementContext &elemCtx,
252  int faceIdx,
253  int timeIdx)
254  {
255  DarcyExtQuants::calculateGradients_(elemCtx, faceIdx, timeIdx);
256 
257  const auto &intQuantsIn = elemCtx.intensiveQuantities(this->interiorDofIdx_, timeIdx);
258  const auto &intQuantsEx = elemCtx.intensiveQuantities(this->exteriorDofIdx_, timeIdx);
259 
260  // calculate the square root of the intrinsic permeability
261  assert(isDiagonal_(this->K_));
262  sqrtK_ = 0.0;
263  for (int i = 0; i < dimWorld; ++i)
264  sqrtK_[i][i] = std::sqrt(this->K_[i][i]);
265 
266  // obtain the Ergun coefficient. Lacking better ideas, we use its the arithmetic mean.
267  ergunCoefficient_ = (intQuantsIn.ergunCoefficient() + intQuantsEx.ergunCoefficient())/2;
268 
269  // obtain the mobility to passability ratio for each phase.
270  for (int phaseIdx=0; phaseIdx < numPhases; phaseIdx++) {
271  if (!elemCtx.model().phaseIsConsidered(phaseIdx))
272  continue;
273 
274  const auto &up = elemCtx.intensiveQuantities(this->upstreamIndex_(phaseIdx), timeIdx);
275 
276  density_[phaseIdx] = up.fluidState().density(phaseIdx);
277  mobilityPassabilityRatio_[phaseIdx] = up.mobilityPassabilityRatio(phaseIdx);
278  }
279  }
280 
281  template <class FluidState>
282  void calculateBoundaryGradients_(const ElementContext &elemCtx,
283  int boundaryFaceIdx,
284  int timeIdx,
285  const FluidState& fluidState,
286  const typename FluidSystem::ParameterCache& paramCache)
287  {
289  boundaryFaceIdx,
290  timeIdx,
291  fluidState,
292  paramCache);
293 
294  const auto &intQuantsIn = elemCtx.intensiveQuantities(this->interiorDofIdx_, timeIdx);
295 
296  // obtain the Ergun coefficient. Because we are on the boundary here, we will
297  // take the Ergun coefficient of the interior
298  ergunCoefficient_ = intQuantsIn.ergunCoefficient();
299 
300  // calculate the square root of the intrinsic permeability
301  assert(isDiagonal_(this->K_));
302  sqrtK_ = 0.0;
303  for (int i = 0; i < dimWorld; ++i)
304  sqrtK_[i][i] = std::sqrt(this->K_[i][i]);
305 
306  for (int phaseIdx=0; phaseIdx < numPhases; phaseIdx++) {
307  if (!elemCtx.model().phaseIsConsidered(phaseIdx))
308  continue;
309 
310  density_[phaseIdx] = intQuantsIn.fluidState().density(phaseIdx);
311  mobilityPassabilityRatio_[phaseIdx] = intQuantsIn.mobilityPassabilityRatio(phaseIdx);
312  }
313  }
314 
321  void calculateFluxes_(const ElementContext &elemCtx, int scvfIdx, int timeIdx)
322  {
323  const auto &intQuantsI = elemCtx.intensiveQuantities(asImp_().interiorIndex(), timeIdx);
324  const auto &intQuantsJ = elemCtx.intensiveQuantities(asImp_().exteriorIndex(), timeIdx);
325 
326  const auto &scvf = elemCtx.stencil(timeIdx).interiorFace(scvfIdx);
327  const auto &normal = scvf.normal();
328  Valgrind::CheckDefined(normal);
329 
330  // obtain the Ergun coefficient from the intensive quantity object. Until a
331  // better method comes along, we use arithmetic averaging.
332  ergunCoefficient_ = (intQuantsI.ergunCoefficient() + intQuantsJ.ergunCoefficient()) / 2;
333 
335  // calculate the weights of the upstream and the downstream control volumes
337  for (int phaseIdx = 0; phaseIdx < numPhases; phaseIdx++) {
338  if (!elemCtx.model().phaseIsConsidered(phaseIdx)) {
339  this->filterVelocity_[phaseIdx] = 0;
340  this->volumeFlux_[phaseIdx] = 0;
341  continue;
342  }
343 
344  calculateForchheimerFlux_(phaseIdx);
345  this->volumeFlux_[phaseIdx] = (this->filterVelocity_[phaseIdx] * normal);
346  }
347  }
348 
352  void calculateBoundaryFluxes_(const ElementContext& elemCtx,
353  int bfIdx,
354  int timeIdx)
355  {
356  const auto &boundaryFace = elemCtx.stencil(timeIdx).boundaryFace(bfIdx);
357  const auto &normal = boundaryFace.normal();
358 
360  // calculate the weights of the upstream and the downstream degrees of freedom
362  for (int phaseIdx = 0; phaseIdx < numPhases; phaseIdx++) {
363  if (!elemCtx.model().phaseIsConsidered(phaseIdx)) {
364  this->filterVelocity_[phaseIdx] = 0;
365  this->volumeFlux_[phaseIdx] = 0;
366  continue;
367  }
368 
369  calculateForchheimerFlux_(phaseIdx);
370  this->volumeFlux_[phaseIdx] = (this->filterVelocity_[phaseIdx] * normal);
371  }
372  }
373 
374  void calculateForchheimerFlux_(int phaseIdx)
375  {
376  // initial guess: filter velocity is zero
377  DimVector &velocity = this->filterVelocity_[phaseIdx];
378  velocity = 0;
379 
380  // the change of velocity between two consecutive Newton iterations
381  DimVector deltaV(1e5);
382  // the function value that is to be minimized of the equation that is to be
383  // fulfilled
384  DimVector residual;
385  // derivative of equation that is to be solved
386  DimMatrix gradResid;
387 
388  // search by means of the Newton method for a root of Forchheimer equation
389  int newtonIter = 0;
390  while (deltaV.two_norm() > 1e-11) {
391  if (newtonIter >= 50)
392  OPM_THROW(Opm::NumericalProblem,
393  "Could not determine Forchheimer velocity within "
394  << newtonIter << " iterations");
395  ++newtonIter;
396 
397  // calculate the residual and its Jacobian matrix
398  gradForchheimerResid_(residual, gradResid, phaseIdx);
399 
400  // newton method
401  gradResid.solve(deltaV, residual);
402  velocity -= deltaV;
403  }
404  }
405 
406  void forchheimerResid_(DimVector &residual, int phaseIdx) const
407  {
408  const DimVector &velocity = this->filterVelocity_[phaseIdx];
409 
410  // Obtaining the upstreamed quantities
411  Scalar mobility = this->mobility_[phaseIdx];
412  Scalar density = density_[phaseIdx];
414 
415  // optain the quantites for the integration point
416  const auto &pGrad = this->potentialGrad_[phaseIdx];
417 
418  // residual = v_\alpha
419  residual = velocity;
420 
421  // residual += mobility_\alpha K(\grad p_\alpha - \rho_\alpha g)
422  this->K_.usmv(mobility, pGrad, residual);
423 
424  // Forchheimer turbulence correction:
425  //
426  // residual +=
427  // \rho_\alpha
428  // * mobility_\alpha
429  // * C_E / \eta_{r,\alpha}
430  // * abs(v_\alpha) * sqrt(K)*v_\alpha
431  sqrtK_.usmv(density*mobilityPassabilityRatio*ergunCoefficient_*velocity.two_norm(),
432  velocity,
433  residual);
434 
435  Valgrind::CheckDefined(residual);
436  }
437 
438  void gradForchheimerResid_(DimVector &residual, DimMatrix &gradResid,
439  int phaseIdx)
440  {
441  DimVector &velocity = this->filterVelocity_[phaseIdx];
442  forchheimerResid_(residual, phaseIdx);
443 
444  Scalar eps = 1e-11;
445  DimVector tmp;
446  for (int i = 0; i < dimWorld; ++i) {
447  Scalar coordEps = std::max(eps, velocity[i] * (1 + eps));
448  velocity[i] += coordEps;
449  forchheimerResid_(tmp, phaseIdx);
450  tmp -= residual;
451  tmp /= coordEps;
452  gradResid[i] = tmp;
453  velocity[i] -= coordEps;
454  }
455  }
456 
464  bool isDiagonal_(const DimMatrix &K) const
465  {
466  for (int i = 0; i < dimWorld; i++) {
467  for (int j = 0; j < dimWorld; j++) {
468  if (i == j)
469  continue;
470 
471  if (std::abs(K[i][j]) > 1e-25)
472  return false;
473  }
474  }
475  return true;
476  }
477 
478 private:
479  Implementation &asImp_()
480  { return *static_cast<Implementation *>(this); }
481 
482  const Implementation &asImp_() const
483  { return *static_cast<const Implementation *>(this); }
484 
485 protected:
486  // intrinsic permeability tensor and its square root
487  DimMatrix sqrtK_;
488 
489  // Ergun coefficient of all phases at the integration point
491 
492  // Passability of all phases at the integration point
493  Scalar mobilityPassabilityRatio_[numPhases];
494 
495  // Density of all phases at the integration point
496  Scalar density_[numPhases];
497 };
498 
499 } // namespace Ewoms
500 
501 #endif
Specifies a flux module which uses the Forchheimer relation.
Definition: forchheimerfluxmodule.hh:61
Scalar ergunCoefficient(Context &context, int spaceIdx, int timeIdx) const
Returns the Ergun coefficient.
Definition: forchheimerfluxmodule.hh:95
void calculateForchheimerFlux_(int phaseIdx)
Definition: forchheimerfluxmodule.hh:374
short interiorDofIdx_
Definition: darcyfluxmodule.hh:521
Scalar mobilityPassabilityRatio(int phaseIdx) const
Returns the passability of a phase.
Definition: forchheimerfluxmodule.hh:149
void forchheimerResid_(DimVector &residual, int phaseIdx) const
Definition: forchheimerfluxmodule.hh:406
Declare the properties used by the infrastructure code of the finite volume discretizations.
DimMatrix sqrtK_
Definition: forchheimerfluxmodule.hh:487
Scalar ergunCoefficient() const
Returns the Ergun coefficient.
Definition: forchheimerfluxmodule.hh:141
static void registerParameters()
Register all run-time parameters for the flux module.
Definition: forchheimerfluxmodule.hh:70
#define GET_PROP_VALUE(TypeTag, PropTagName)
Access the value attribute of a property for a type tag.
Definition: propertysystem.hh:468
ForchheimerBaseProblem< TypeTag > FluxBaseProblem
Definition: forchheimerfluxmodule.hh:65
ForchheimerIntensiveQuantities< TypeTag > FluxIntensiveQuantities
Definition: forchheimerfluxmodule.hh:63
Scalar density_[numPhases]
Definition: forchheimerfluxmodule.hh:496
Provides the intensive quantities for the Forchheimer module.
Definition: forchheimerfluxmodule.hh:48
void calculateBoundaryGradients_(const ElementContext &elemCtx, int boundaryFaceIdx, int timeIdx, const FluidState &fluidState, const typename FluidSystem::ParameterCache &paramCache)
Definition: forchheimerfluxmodule.hh:282
void calculateFluxes_(const ElementContext &elemCtx, int scvfIdx, int timeIdx)
Calculate the volumetric fluxes of all phases.
Definition: forchheimerfluxmodule.hh:321
NEW_PROP_TAG(Grid)
The type of the DUNE grid.
short upstreamIndex_(int phaseIdx) const
Definition: darcyfluxmodule.hh:182
Provides the Forchheimer flux module.
Definition: forchheimerfluxmodule.hh:51
Scalar ergunCoefficient_
Definition: forchheimerfluxmodule.hh:490
void gradForchheimerResid_(DimVector &residual, DimMatrix &gradResid, int phaseIdx)
Definition: forchheimerfluxmodule.hh:438
Evaluation mobility_[numPhases]
Definition: darcyfluxmodule.hh:527
void calculateBoundaryGradients_(const ElementContext &elemCtx, int boundaryFaceIdx, int timeIdx, const FluidState &fluidState, const typename FluidSystem::ParameterCache &paramCache)
Calculate the gradients at the grid boundary which are required to determine the volumetric fluxes...
Definition: darcyfluxmodule.hh:320
Definition: baseauxiliarymodule.hh:35
Scalar mobilityPassabilityRatio(int phaseIdx) const
Return the ratio of the mobility divided by the passability at the face's integration point for a giv...
Definition: forchheimerfluxmodule.hh:247
Scalar mobilityPassabilityRatio(Context &context, int spaceIdx, int timeIdx, int phaseIdx) const
Returns the ratio between the phase mobility and its passability for a given fluid phase ...
Definition: forchheimerfluxmodule.hh:113
Evaluation volumeFlux_[numPhases]
Definition: darcyfluxmodule.hh:534
This file contains the necessary classes to calculate the volumetric fluxes out of a pressure potenti...
DimMatrix K_
Definition: darcyfluxmodule.hh:518
Scalar ergunCoefficient() const
Return the Ergun coefficent at the face's integration point.
Definition: forchheimerfluxmodule.hh:238
bool isDiagonal_(const DimMatrix &K) const
Check whether all off-diagonal entries of a tensor are zero.
Definition: forchheimerfluxmodule.hh:464
void calculateBoundaryFluxes_(const ElementContext &elemCtx, int bfIdx, int timeIdx)
Calculate the volumetric flux rates of all phases at the domain boundary.
Definition: forchheimerfluxmodule.hh:352
EvalDimVector filterVelocity_[numPhases]
Definition: darcyfluxmodule.hh:530
Provides the defaults for the parameters required by the Forchheimer velocity approach.
Definition: forchheimerfluxmodule.hh:54
void calculateGradients_(const ElementContext &elemCtx, int faceIdx, int timeIdx)
Definition: forchheimerfluxmodule.hh:251
void calculateGradients_(const ElementContext &elemCtx, int faceIdx, int timeIdx)
Calculate the gradients which are required to determine the volumetric fluxes.
Definition: darcyfluxmodule.hh:193
EvalDimVector potentialGrad_[numPhases]
Definition: darcyfluxmodule.hh:537
Scalar mobilityPassabilityRatio_[numPhases]
Definition: forchheimerfluxmodule.hh:493
void update_(const ElementContext &elemCtx, int dofIdx, int timeIdx)
Definition: forchheimerfluxmodule.hh:155
ForchheimerExtensiveQuantities< TypeTag > FluxExtensiveQuantities
Definition: forchheimerfluxmodule.hh:64
short exteriorDofIdx_
Definition: darcyfluxmodule.hh:522