fvbaselocalresidual.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 */
26 #ifndef EWOMS_FV_BASE_LOCAL_RESIDUAL_HH
27 #define EWOMS_FV_BASE_LOCAL_RESIDUAL_HH
28 
29 #include <opm/material/common/Valgrind.hpp>
30 
31 #include <dune/istl/bvector.hh>
32 #include <dune/grid/common/geometry.hh>
33 
34 #include <dune/common/fvector.hh>
35 
36 #include <opm/material/common/ClassName.hpp>
37 
38 #include "fvbaseproperties.hh"
39 
40 #include <cmath>
41 
42 namespace Ewoms {
51 template<class TypeTag>
53 {
54 private:
55  typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation;
56 
57  typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
58  typedef typename GridView::template Codim<0>::Entity Element;
59 
60  typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
61  typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
62  typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
63  typedef typename GET_PROP_TYPE(TypeTag, BoundaryRateVector) BoundaryRateVector;
64  typedef typename GET_PROP_TYPE(TypeTag, Constraints) Constraints;
65  typedef typename GET_PROP_TYPE(TypeTag, RateVector) RateVector;
66  typedef typename GET_PROP_TYPE(TypeTag, EqVector) EqVector;
67  typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
68  enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
69 
70  typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
71  typedef typename GET_PROP_TYPE(TypeTag, BoundaryContext) BoundaryContext;
72  typedef typename GET_PROP_TYPE(TypeTag, ConstraintsContext) ConstraintsContext;
73 
74  typedef Opm::MathToolbox<Evaluation> Toolbox;
75  typedef Dune::FieldVector<Evaluation, numEq> EvalEqVector;
76  typedef Dune::FieldVector<Evaluation, numEq> VectorBlock;
77  typedef Dune::BlockVector<VectorBlock> LocalBlockVector;
78 
79  // copying the local residual class is not a good idea
81  {}
82 
83 public:
85  { }
86 
88  { }
89 
93  static void registerParameters()
94  { }
95 
100  const LocalBlockVector &residual() const
101  { return internalResidual_; }
102 
109  const VectorBlock &residual(int dofIdx) const
110  { return internalResidual_[dofIdx]; }
111 
116  const LocalBlockVector &storageTerm() const
117  { return internalStorageTerm_; }
118 
125  const VectorBlock &storageTerm(int dofIdx) const
126  { return internalStorageTerm_[dofIdx]; }
127 
139  void eval(const Problem &problem, const Element &element)
140  {
141  ElementContext elemCtx(problem);
142  elemCtx.updateAll(element);
143  eval(elemCtx);
144  }
145 
156  void eval(const ElementContext &elemCtx)
157  {
158  int numDof = elemCtx.numDof(/*timeIdx=*/0);
159  int numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
160  internalResidual_.resize(numDof);
161  internalStorageTerm_.resize(numPrimaryDof);
162  asImp_().eval(internalResidual_, internalStorageTerm_, elemCtx);
163  }
164 
173  void eval(LocalBlockVector &residual,
174  LocalBlockVector &storage,
175  const ElementContext &elemCtx) const
176  {
177  int numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
178  int numDof = elemCtx.numDof(/*timeIdx=*/0);
179 
180  typedef Opm::MathToolbox<Evaluation> Toolbox;
181 
182  residual = Toolbox::createConstant(0.0);
183  storage = Toolbox::createConstant(0.0);
184 
185  // evaluate the flux terms
186  asImp_().evalFluxes(residual, elemCtx, /*timeIdx=*/0);
187  assert(static_cast<int>(residual.size()) == numDof);
188  assert(static_cast<int>(storage.size()) == numPrimaryDof);
189 
190 #if !defined NDEBUG
191  for (int i=0; i < numDof; i++) {
192  for (int j = 0; j < numEq; ++ j) {
193  assert(std::isfinite(Toolbox::value(residual[i][j])));
194  Valgrind::CheckDefined(residual[i][j]);
195  }
196  }
197 #endif
198 
199  // evaluate the storage and the source terms
200  asImp_().evalVolumeTerms_(residual, storage, elemCtx);
201  for (int dofIdx=0; dofIdx < numPrimaryDof; dofIdx++) {
202  for (int eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
203  storage[dofIdx][eqIdx] /= elemCtx.dofTotalVolume(dofIdx, /*timeIdx=*/0);
204 
205  assert(std::isfinite(Toolbox::value(residual[dofIdx][eqIdx])));
206  Valgrind::CheckDefined(residual[dofIdx][eqIdx]);
207  }
208  }
209 
210  // evaluate the boundary conditions
211  asImp_().evalBoundary_(residual, elemCtx, /*timeIdx=*/0);
212 #if !defined NDEBUG
213  for (int i=0; i < numDof; i++) {
214  for (int j = 0; j < numEq; ++ j) {
215  assert(std::isfinite(Toolbox::value(residual[i][j])));
216  Valgrind::CheckDefined(residual[i][j]);
217  }
218  }
219 #endif
220 
221  // evaluate the constraint DOFs
222  asImp_().evalConstraints_(residual, storage, elemCtx, /*timeIdx=*/0);
223 
224  // make the residual volume specific (i.e., make it incorrect mass per cubic
225  // meter instead of total mass)
226  for (int dofIdx=0; dofIdx < numDof; ++dofIdx) {
227  if (elemCtx.dofTotalVolume(dofIdx, /*timeIdx=*/0) > 0) {
228  // interior DOF
229  Scalar dofVolume = elemCtx.dofTotalVolume(dofIdx, /*timeIdx=*/0);
230 
231  for (int eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
232  residual[dofIdx][eqIdx] /= dofVolume;
233  assert(std::isfinite(Toolbox::value(residual[dofIdx][eqIdx])));
234  Valgrind::CheckDefined(residual[dofIdx][eqIdx]);
235  }
236  }
237  }
238  }
239 
250  void evalStorage(const ElementContext &elemCtx, int timeIdx)
251  {
252  int numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
253  internalStorageTerm_.resize(numPrimaryDof);
254  evalStorage(internalStorageTerm_,
255  elemCtx,
256  timeIdx);
257  }
258 
270  void evalStorage(LocalBlockVector &storage,
271  const ElementContext &elemCtx,
272  int timeIdx) const
273  {
274  if (timeIdx == 0) {
275  // for the most current solution, the storage term depends on the current
276  // primary variables.
277 
278  // calculate the amount of conservation each quantity inside
279  // all primary sub control volumes
280  int numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
281  for (int dofIdx=0; dofIdx < numPrimaryDof; dofIdx++) {
282  storage[dofIdx] = Toolbox::createConstant(0.0);
283  asImp_().computeStorage(storage[dofIdx], elemCtx, dofIdx, timeIdx);
284 
285  for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) {
286  storage[dofIdx][eqIdx] *=
287  elemCtx.stencil(timeIdx).subControlVolume(dofIdx).volume()
288  * elemCtx.intensiveQuantities(dofIdx, timeIdx).extrusionFactor();
289  }
290  }
291  }
292  else {
293  // for all previous solutions, the storage term does _not_ depend on the
294  // current primary variables, so we use scalars to store it.
295 
296  // calculate the amount of conservation each quantity inside
297  // all primary sub control volumes
298  Dune::FieldVector<Scalar, numEq> tmp;
299  int numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
300  for (int dofIdx=0; dofIdx < numPrimaryDof; dofIdx++) {
301  tmp = 0;
302  asImp_().computeStorage(tmp,
303  elemCtx,
304  dofIdx,
305  timeIdx);
306  tmp *=
307  elemCtx.stencil(timeIdx).subControlVolume(dofIdx).volume()
308  * elemCtx.intensiveQuantities(dofIdx, timeIdx).extrusionFactor();
309 
310 
311  for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
312  storage[dofIdx][eqIdx] = Toolbox::createConstant(tmp[eqIdx]);
313  }
314  }
315  }
316 
324  void evalFluxes(LocalBlockVector &residual,
325  const ElementContext &elemCtx,
326  int timeIdx) const
327  {
328  RateVector flux;
329 
330  const auto &stencil = elemCtx.stencil(timeIdx);
331  // calculate the mass flux over the sub-control volume faces
332  int numInteriorFaces = elemCtx.numInteriorFaces(timeIdx);
333  for (int scvfIdx = 0; scvfIdx < numInteriorFaces; scvfIdx++) {
334  const auto &face = stencil.interiorFace(scvfIdx);
335  int i = face.interiorIndex();
336  int j = face.exteriorIndex();
337 
338  Valgrind::SetUndefined(flux);
339  asImp_().computeFlux(flux, /*context=*/elemCtx, scvfIdx, timeIdx);
340 
341  Scalar alpha = elemCtx.extensiveQuantities(scvfIdx, timeIdx).extrusionFactor();
342  alpha *= face.area();
343  for (int eqIdx = 0; eqIdx < numEq; ++ eqIdx)
344  flux[eqIdx] *= alpha;
345  Valgrind::CheckDefined(flux);
346 
347  // The balance equation for a finite volume is given by
348  //
349  // dStorage/dt + Flux = Source
350  //
351  // where the 'Flux' and the 'Source' terms represent the
352  // mass per second which leaves the finite
353  // volume. Re-arranging this, we get
354  //
355  // dStorage/dt + Flux - Source = 0
356  //
357  // Since the mass flux as calculated by computeFlux() goes out of sub-control
358  // volume i and into sub-control volume j, we need to add the flux to finite
359  // volume i and subtract it from finite volume j
360  residual[i] += flux;
361  residual[j] -= flux;
362  }
363  }
364 
366  // The following methods _must_ be overloaded by the actual flow
367  // models!
369 
377  void computeStorage(EqVector &storage,
378  const ElementContext &elemCtx,
379  int dofIdx,
380  int timeIdx) const
381  {
382  OPM_THROW(std::logic_error,
383  "Not implemented: The local residual " << Opm::className<Implementation>()
384  << " does not implement the required method 'computeStorage()'");
385  }
386 
394  void computeFlux(RateVector &flux,
395  const ElementContext &elemCtx,
396  int scvfIdx,
397  int timeIdx) const
398  {
399  OPM_THROW(std::logic_error,
400  "Not implemented: The local residual " << Opm::className<Implementation>()
401  << " does not implement the required method 'computeFlux()'");
402  }
403 
410  void computeSource(RateVector &source,
411  const ElementContext &elemCtx,
412  int dofIdx,
413  int timeIdx) const
414  {
415  OPM_THROW(std::logic_error,
416  "Not implemented: The local residual " << Opm::className<Implementation>()
417  << " does not implement the required method 'computeSource()'");
418  }
419 
420 protected:
424  void evalBoundary_(LocalBlockVector &residual,
425  const ElementContext &elemCtx,
426  int timeIdx) const
427  {
428  if (!elemCtx.onBoundary())
429  return;
430 
431  BoundaryContext boundaryCtx(elemCtx);
432 
433  // evaluate the boundary for all boundary faces of the current context
434  int numBoundaryFaces = boundaryCtx.numBoundaryFaces(/*timeIdx=*/0);
435  for (int faceIdx = 0; faceIdx < numBoundaryFaces; ++faceIdx) {
436  // add the residual of all vertices of the boundary
437  // segment
438  evalBoundarySegment_(residual,
439  boundaryCtx,
440  faceIdx,
441  timeIdx);
442  }
443  }
444 
449  void evalBoundarySegment_(LocalBlockVector &residual,
450  const BoundaryContext &boundaryCtx,
451  int boundaryFaceIdx,
452  int timeIdx) const
453  {
454  BoundaryRateVector values;
455 
456  Valgrind::SetUndefined(values);
457  boundaryCtx.problem().boundary(values,
458  boundaryCtx,
459  boundaryFaceIdx,
460  timeIdx);
461  Valgrind::CheckDefined(values);
462 
463  const auto &stencil = boundaryCtx.stencil(timeIdx);
464  int dofIdx = stencil.boundaryFace(boundaryFaceIdx).interiorIndex();
465  const auto &insideIntQuants = boundaryCtx.elementContext().intensiveQuantities(dofIdx, timeIdx);
466  for (unsigned eqIdx = 0; eqIdx < values.size(); ++eqIdx)
467  values[eqIdx] *=
468  stencil.boundaryFace(boundaryFaceIdx).area()
469  * insideIntQuants.extrusionFactor();
470 
471  for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
472  residual[dofIdx][eqIdx] += values[eqIdx];
473  }
474  }
475 
479  void evalConstraints_(LocalBlockVector &residual,
480  LocalBlockVector &storage,
481  const ElementContext &elemCtx,
482  int timeIdx) const
483  {
484  if (!GET_PROP_VALUE(TypeTag, EnableConstraints))
485  return;
486 
487  const auto &problem = elemCtx.problem();
488  Constraints constraints;
489  ConstraintsContext constraintsCtx(elemCtx);
490  int numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
491  for (int dofIdx = 0; dofIdx < numPrimaryDof; ++dofIdx) {
492  // ask the problem for the constraint values
493  constraints.reset();
494  problem.constraints(constraints, elemCtx, dofIdx, timeIdx);
495 
496  if (!constraints.isConstraint())
497  continue;
498 
499  // enforce the constraints
500  const PrimaryVariables &priVars = elemCtx.primaryVars(dofIdx, timeIdx);
501  for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) {
502  if (!constraints.isConstraint(eqIdx))
503  continue;
504 
505  int pvIdx = constraints.eqToPvIndex(eqIdx);
506 
507  assert(0 <= pvIdx && pvIdx < numEq);
508  Valgrind::CheckDefined(constraints[pvIdx]);
509 
510  residual[dofIdx][eqIdx] = priVars.makeEvaluation(pvIdx, timeIdx) - constraints[pvIdx];
511  storage[dofIdx][eqIdx] = 0.0;
512  }
513  }
514  }
515 
521  void evalVolumeTerms_(LocalBlockVector &residual,
522  LocalBlockVector &storage,
523  const ElementContext &elemCtx) const
524  {
525  EvalEqVector tmp;
526  EqVector tmp2;
527  RateVector sourceRate;
528 
529  tmp = Toolbox::createConstant(0.0);
530  tmp2 = 0.0;
531 
532  // evaluate the volumetric terms (storage + source terms)
533  int numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
534  for (int dofIdx=0; dofIdx < numPrimaryDof; dofIdx++) {
535  Scalar extrusionFactor =
536  elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0).extrusionFactor();
537  Scalar scvVolume =
538  elemCtx.stencil(/*timeIdx=*/0).subControlVolume(dofIdx).volume() * extrusionFactor;
539  Valgrind::CheckDefined(scvVolume);
540 
541  // mass balance within the element. this is the
542  // \f$\frac{m}{\partial t}\f$ term if using implicit
543  // euler as time discretization.
544  //
545  // TODO (?): we might need a more explicit way for
546  // doing the time discretization...
547  asImp_().computeStorage(tmp,
548  elemCtx,
549  dofIdx,
550  /*timeIdx=*/0);
551  Valgrind::CheckDefined(tmp);
552 
553  asImp_().computeStorage(tmp2,
554  elemCtx,
555  dofIdx,
556  /*timeIdx=*/1);
557  Valgrind::CheckDefined(tmp2);
558 
559  tmp -= tmp2;
560  for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
561  tmp[eqIdx] *= scvVolume / elemCtx.simulator().timeStepSize();
562 
563  storage[dofIdx] += tmp;
564  residual[dofIdx] += tmp;
565 
566  Valgrind::CheckDefined(storage[dofIdx]);
567  Valgrind::CheckDefined(residual[dofIdx]);
568 
569  // subtract the source term from the residual
570  asImp_().computeSource(sourceRate, elemCtx, dofIdx, /*timeIdx=*/0);
571  for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
572  sourceRate[eqIdx] *= scvVolume;
573  residual[dofIdx] -= sourceRate;
574 
575  // make sure that only defined quantities were used
576  // to calculate the residual.
577  Valgrind::CheckDefined(storage[dofIdx]);
578  Valgrind::CheckDefined(residual[dofIdx]);
579  }
580  }
581 
582 
583 private:
584  Implementation &asImp_()
585  {
586  assert(static_cast<Implementation*>(this) != 0);
587  return *static_cast<Implementation*>(this);
588  }
589 
590  const Implementation &asImp_() const
591  {
592  assert(static_cast<const Implementation*>(this) != 0);
593  return *static_cast<const Implementation*>(this);
594  }
595 
596  LocalBlockVector internalResidual_;
597  LocalBlockVector internalStorageTerm_;
598 };
599 
600 } // namespace Ewoms
601 
602 #endif
~FvBaseLocalResidual()
Definition: fvbaselocalresidual.hh:87
void eval(LocalBlockVector &residual, LocalBlockVector &storage, const ElementContext &elemCtx) const
Compute the local residual, i.e. the deviation of the conservation equations from zero...
Definition: fvbaselocalresidual.hh:173
void eval(const ElementContext &elemCtx)
Compute the local residual, i.e. the deviation of the conservation equations from zero and store the ...
Definition: fvbaselocalresidual.hh:156
Declare the properties used by the infrastructure code of the finite volume discretizations.
#define GET_PROP_VALUE(TypeTag, PropTagName)
Access the value attribute of a property for a type tag.
Definition: propertysystem.hh:468
const LocalBlockVector & storageTerm() const
Return the storage term calculated using the last call to eval() using internal storage.
Definition: fvbaselocalresidual.hh:116
void evalConstraints_(LocalBlockVector &residual, LocalBlockVector &storage, const ElementContext &elemCtx, int timeIdx) const
Set the values of the constraint volumes of the current element.
Definition: fvbaselocalresidual.hh:479
void evalVolumeTerms_(LocalBlockVector &residual, LocalBlockVector &storage, const ElementContext &elemCtx) const
Add the change in the storage terms and the source term to the local residual of all sub-control volu...
Definition: fvbaselocalresidual.hh:521
void computeSource(RateVector &source, const ElementContext &elemCtx, int dofIdx, int timeIdx) const
Calculate the source term of the equation.
Definition: fvbaselocalresidual.hh:410
void computeFlux(RateVector &flux, const ElementContext &elemCtx, int scvfIdx, int timeIdx) const
Evaluates the total mass flux of all conservation quantities over a face of a sub-control volume...
Definition: fvbaselocalresidual.hh:394
void eval(const Problem &problem, const Element &element)
Compute the local residual, i.e. the deviation of the conservation equations from zero and store the ...
Definition: fvbaselocalresidual.hh:139
void computeStorage(EqVector &storage, const ElementContext &elemCtx, int dofIdx, int timeIdx) const
Evaluate the amount all conservation quantities (e.g. phase mass) within a finite sub-control volume...
Definition: fvbaselocalresidual.hh:377
const VectorBlock & storageTerm(int dofIdx) const
Return the storage term calculated using the last call to eval() using internal storage.
Definition: fvbaselocalresidual.hh:125
Definition: baseauxiliarymodule.hh:35
const LocalBlockVector & residual() const
Return the result of the eval() call using internal storage.
Definition: fvbaselocalresidual.hh:100
void evalFluxes(LocalBlockVector &residual, const ElementContext &elemCtx, int timeIdx) const
Add the flux term to a local residual.
Definition: fvbaselocalresidual.hh:324
const VectorBlock & residual(int dofIdx) const
Return the result of the eval() call using internal storage.
Definition: fvbaselocalresidual.hh:109
void evalStorage(const ElementContext &elemCtx, int timeIdx)
Calculate the amount of all conservation quantities stored in all element's primary sub-control volum...
Definition: fvbaselocalresidual.hh:250
void evalBoundary_(LocalBlockVector &residual, const ElementContext &elemCtx, int timeIdx) const
Evaluate the boundary conditions of an element.
Definition: fvbaselocalresidual.hh:424
FvBaseLocalResidual()
Definition: fvbaselocalresidual.hh:84
void evalBoundarySegment_(LocalBlockVector &residual, const BoundaryContext &boundaryCtx, int boundaryFaceIdx, int timeIdx) const
Evaluate all boundary conditions for a single sub-control volume face to the local residual...
Definition: fvbaselocalresidual.hh:449
Element-wise caculation of the residual matrix for models based on a finite volume spatial discretiza...
Definition: fvbaselocalresidual.hh:52
static void registerParameters()
Register all run-time parameters for the local residual.
Definition: fvbaselocalresidual.hh:93
void evalStorage(LocalBlockVector &storage, const ElementContext &elemCtx, int timeIdx) const
Calculate the amount of all conservation quantities stored in all element's sub-control volumes for a...
Definition: fvbaselocalresidual.hh:270