fvbasegradientcalculator.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) 2011-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_GRADIENT_CALCULATOR_HH
27 #define EWOMS_FV_BASE_GRADIENT_CALCULATOR_HH
28 
29 #include "fvbaseproperties.hh"
30 
31 #include <dune/common/fvector.hh>
32 
33 namespace Ewoms {
34 template<class TypeTag>
36 
43 template<class TypeTag>
45 {
46 
47  typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
48  typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
49  typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
50  typedef typename GET_PROP_TYPE(TypeTag, Discretization) Discretization;
51  typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
52 
53  enum { dim = GridView::dimension };
54  enum { dimWorld = GridView::dimensionworld };
55 
56  // maximum number of flux approximation points. to calculate this,
57  // we assume that the geometry with the most pointsq is a cube.
58  enum { maxFap = 2 << dim };
59 
60  typedef Opm::MathToolbox<Evaluation> Toolbox;
61  typedef Dune::FieldVector<Scalar, dim> DimVector;
62  typedef Dune::FieldVector<Evaluation, dim> EvalDimVector;
63 
64  static_assert(std::is_same<Evaluation, Scalar>::value ||
65  std::is_same<Discretization, EcfvDiscretization<TypeTag> >::value,
66  "So far, automatic differentiation is only available for the "
67  "element-centered finite volume discretization!");
68 
69 public:
74  static void registerParameters()
75  { }
76 
84  template <bool prepareValues = true, bool prepareGradients = true>
85  void prepare(const ElementContext &elemCtx, int timeIdx)
86  {
87  const auto &stencil = elemCtx.stencil(timeIdx);
88  for (int fapIdx = 0; fapIdx < stencil.numInteriorFaces(); ++ fapIdx) {
89  const auto &scvf = stencil.interiorFace(fapIdx);
90  const auto &normal = scvf.normal();
91  const auto &interiorPos = stencil.subControlVolume(scvf.interiorIndex()).globalPos();
92  const auto &exteriorPos = stencil.subControlVolume(scvf.exteriorIndex()).globalPos();
93 
94  interiorDistance_[fapIdx] = 0;
95  exteriorDistance_[fapIdx] = 0;
96  for (int dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
97  interiorDistance_[fapIdx] +=
98  (interiorPos[dimIdx] - scvf.integrationPos()[dimIdx])
99  * normal[dimIdx];
100 
101  exteriorDistance_[fapIdx] +=
102  (exteriorPos[dimIdx] - scvf.integrationPos()[dimIdx])
103  * normal[dimIdx];
104  }
105 
106  interiorDistance_[fapIdx] = std::abs(interiorDistance_[fapIdx]);
107  exteriorDistance_[fapIdx] = std::abs(exteriorDistance_[fapIdx]);
108  }
109  }
110 
111 
123  template <class QuantityCallback>
124  auto calculateValue(const ElementContext &elemCtx,
125  int fapIdx,
126  const QuantityCallback &quantityCallback) const
127  -> typename std::remove_reference<decltype(quantityCallback.operator()(0))>::type
128  {
129  const auto &face = elemCtx.stencil(/*timeIdx=*/0).interiorFace(fapIdx);
130 
131  // average weighted by distance to DOF coordinate...
132  auto value(quantityCallback(face.interiorIndex()));
133  value *= interiorDistance_[fapIdx];
134  auto tmp(quantityCallback(face.exteriorIndex()));
135  tmp *= exteriorDistance_[fapIdx];
136  value += tmp;
137  value /= interiorDistance_[fapIdx] + exteriorDistance_[fapIdx];
138 
139  return value;
140  }
141 
153  template <class QuantityCallback>
154  void calculateGradient(EvalDimVector &quantityGrad,
155  const ElementContext &elemCtx,
156  int fapIdx,
157  const QuantityCallback &quantityCallback) const
158  {
159  const auto &stencil = elemCtx.stencil(/*timeIdx=*/0);
160  const auto &face = stencil.interiorFace(fapIdx);
161 
162  const auto& exteriorPos = stencil.subControlVolume(face.exteriorIndex()).center();
163  const auto& interiorPos = stencil.subControlVolume(face.interiorIndex()).center();
164 
165  // this is slightly hacky because the derivatives of the quantity for the
166  // exterior DOF are thrown away and this code thus assumes that the exterior DOF
167  // is not a primary degree of freedom. Basically this means that two-point flux
168  // approximation scheme is used. A way to fix this in a conceptionally elegant
169  // way would be to introduce the concept of extensive evaluations, but
170  // unfortunately this makes things quite a bit slower. (and also quite a bit
171  // harder to comprehend :/ )
172  Evaluation deltay =
173  Toolbox::value(quantityCallback(face.exteriorIndex()))
174  - quantityCallback(face.interiorIndex());
175 
176  Scalar distSquared = 0;
177  for (int dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
178  quantityGrad[dimIdx] = deltay;
179 
180  Scalar tmp = exteriorPos[dimIdx] - interiorPos[dimIdx];
181  distSquared += tmp*tmp;
182  }
183 
184  // divide the gradient by the squared distance between the centers of the
185  // sub-control volumes: the gradient is the normalized directional vector between
186  // the two centers times the ratio of the difference of the values and their
187  // distance, i.e., d/abs(d) * delta y / abs(d) = d*delta y / abs(d)^2.
188  for (int dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
189  Scalar tmp = exteriorPos[dimIdx] - interiorPos[dimIdx];
190  quantityGrad[dimIdx] *= tmp/distSquared;
191  }
192  }
193 
208  template <class QuantityCallback>
209  auto calculateBoundaryValue(const ElementContext &elemCtx,
210  int fapIdx,
211  const QuantityCallback &quantityCallback)
212  -> decltype(quantityCallback.boundaryValue())
213  { return quantityCallback.boundaryValue(); }
214 
229  template <class QuantityCallback>
230  void calculateBoundaryGradient(EvalDimVector &quantityGrad,
231  const ElementContext &elemCtx,
232  int faceIdx,
233  const QuantityCallback &quantityCallback) const
234  {
235  const auto &stencil = elemCtx.stencil(/*timeIdx=*/0);
236  const auto &face = stencil.boundaryFace(faceIdx);
237 
238  auto deltay = quantityCallback.boundaryValue() - quantityCallback(face.interiorIndex());
239 
240  const auto& boundaryFacePos = face.integrationPos();
241  const auto& interiorPos = stencil.subControlVolume(face.interiorIndex()).center();
242 
243  Scalar distSquared = 0;
244  for (int dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
245  Scalar tmp = boundaryFacePos[dimIdx] - interiorPos[dimIdx];
246  distSquared += tmp*tmp;
247 
248  quantityGrad[dimIdx] = deltay;
249  }
250 
251  // divide the gradient by the squared distance between the center of the
252  // sub-control and the center of the boundary face: the gradient is the
253  // normalized directional vector between the two centers times the ratio of the
254  // difference of the values and their distance, i.e., d/abs(d) * deltay / abs(d)
255  // = d*deltay / abs(d)^2.
256  for (int dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
257  Scalar tmp = boundaryFacePos[dimIdx] - interiorPos[dimIdx];
258  quantityGrad[dimIdx] *= tmp/distSquared;
259  }
260  }
261 
262 private:
263  // distance [m] of the the flux approximation point to the center
264  // of the control volume to the inside of the face
265  Scalar interiorDistance_[maxFap];
266 
267  // distance [m] of the the flux approximation point to the center
268  // of the control volume to the outside of the face
269  Scalar exteriorDistance_[maxFap];
270 };
271 } // namespace Ewoms
272 
273 #endif
Declare the properties used by the infrastructure code of the finite volume discretizations.
The base class for the element-centered finite-volume discretization scheme.
Definition: fvbasegradientcalculator.hh:35
Definition: baseauxiliarymodule.hh:35
This class calculates gradients of arbitrary quantities at flux integration points using the two-poin...
Definition: fvbasegradientcalculator.hh:44