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 This file is part of the Open Porous Media project (OPM).
5
6 OPM 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 2 of the License, or
9 (at your option) any later version.
10
11 OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
18
19 Consult the COPYING file in the top-level source directory of this
20 module for the precise wording of the license and the list of
21 copyright holders.
22*/
28#ifndef EWOMS_FV_BASE_GRADIENT_CALCULATOR_HH
29#define EWOMS_FV_BASE_GRADIENT_CALCULATOR_HH
30
31#include <dune/common/fvector.hh>
32
35
36#include <cmath>
37#include <type_traits>
38
39namespace Opm {
40
41template<class TypeTag>
42class EcfvDiscretization;
43
50template<class TypeTag>
52{
58
59 enum { dim = GridView::dimension };
60 enum { dimWorld = GridView::dimensionworld };
61
62 // maximum number of flux approximation points. to calculate this,
63 // we assume that the geometry with the most points is a cube.
64 enum { maxFap = 2 << dim };
65
66 using DimVector = Dune::FieldVector<Scalar, dimWorld>;
67 using EvalDimVector = Dune::FieldVector<Evaluation, dimWorld>;
68
69public:
74 static void registerParameters()
75 {}
76
84 template <bool prepareValues = true, bool prepareGradients = true>
85 void prepare(const ElementContext&, unsigned)
86 { /* nothing to do */ }
87
99 template <class QuantityCallback>
100 auto calculateScalarValue(const ElementContext& elemCtx,
101 unsigned fapIdx,
102 const QuantityCallback& quantityCallback) const
103 -> std::remove_reference_t<decltype(quantityCallback.operator()(0))>
104 {
105 using RawReturnType = decltype(quantityCallback.operator()(0));
106 using ReturnType = std::remove_const_t<std::remove_reference_t<RawReturnType>>;
107
108 Scalar interiorDistance;
109 Scalar exteriorDistance;
110 computeDistances_(interiorDistance, exteriorDistance, elemCtx, fapIdx);
111
112 const auto& face = elemCtx.stencil(/*timeIdx=*/0).interiorFace(fapIdx);
113 const auto i = face.interiorIndex();
114 const auto j = face.exteriorIndex();
115 const auto focusDofIdx = elemCtx.focusDofIndex();
116
117 // use the average weighted by distance...
118 ReturnType value;
119 if (i == focusDofIdx) {
120 value = quantityCallback(i) * interiorDistance;
121 } else {
122 value = getValue(quantityCallback(i)) * interiorDistance;
123 }
124
125 if (j == focusDofIdx) {
126 value += quantityCallback(j) * exteriorDistance;
127 }
128 else {
129 value += getValue(quantityCallback(j)) * exteriorDistance;
130 }
131
132 value /= interiorDistance + exteriorDistance;
133
134 return value;
135 }
136
148 template <class QuantityCallback>
149 auto calculateVectorValue(const ElementContext& elemCtx,
150 unsigned fapIdx,
151 const QuantityCallback& quantityCallback) const
152 -> std::remove_reference_t<decltype(quantityCallback.operator()(0))>
153 {
154 using RawReturnType = decltype(quantityCallback.operator()(0));
155 using ReturnType = std::remove_const_t<std::remove_reference_t<RawReturnType>>;
156
157 Scalar interiorDistance;
158 Scalar exteriorDistance;
159 computeDistances_(interiorDistance, exteriorDistance, elemCtx, fapIdx);
160
161 const auto& face = elemCtx.stencil(/*timeIdx=*/0).interiorFace(fapIdx);
162 const auto i = face.interiorIndex();
163 const auto j = face.exteriorIndex();
164 const auto focusDofIdx = elemCtx.focusDofIndex();
165
166 // use the average weighted by distance...
167 ReturnType value;
168 if (i == focusDofIdx) {
169 value = quantityCallback(i);
170 for (int k = 0; k < value.size(); ++k) {
171 value[k] *= interiorDistance;
172 }
173 }
174 else {
175 const auto& dofVal = getValue(quantityCallback(i));
176 for (int k = 0; k < dofVal.size(); ++k) {
177 value[k] = getValue(dofVal[k]) * interiorDistance;
178 }
179 }
180
181 if (j == focusDofIdx) {
182 const auto& dofVal = quantityCallback(j);
183 for (int k = 0; k < dofVal.size(); ++k) {
184 value[k] += dofVal[k] * exteriorDistance;
185 }
186 }
187 else {
188 const auto& dofVal = quantityCallback(j);
189 for (int k = 0; k < dofVal.size(); ++k) {
190 value[k] += getValue(dofVal[k]) * exteriorDistance;
191 }
192 }
193
194 const Scalar totDistance = interiorDistance + exteriorDistance;
195 for (int k = 0; k < value.size(); ++k) {
196 value[k] /= totDistance;
197 }
198
199 return value;
200 }
201
214 template <class QuantityCallback>
215 void calculateGradient(EvalDimVector& quantityGrad,
216 const ElementContext& elemCtx,
217 unsigned fapIdx,
218 const QuantityCallback& quantityCallback) const
219 {
220 const auto& stencil = elemCtx.stencil(/*timeIdx=*/0);
221 const auto& face = stencil.interiorFace(fapIdx);
222
223 const auto i = face.interiorIndex();
224 const auto j = face.exteriorIndex();
225 const auto focusIdx = elemCtx.focusDofIndex();
226
227 const auto& interiorPos = stencil.subControlVolume(i).globalPos();
228 const auto& exteriorPos = stencil.subControlVolume(j).globalPos();
229
230 Evaluation deltay;
231 if (i == focusIdx) {
232 deltay = getValue(quantityCallback(j)) - quantityCallback(i);
233 }
234 else if (j == focusIdx) {
235 deltay = quantityCallback(j) - getValue(quantityCallback(i));
236 }
237 else {
238 deltay = getValue(quantityCallback(j)) - getValue(quantityCallback(i));
239 }
240
241 Scalar distSquared = 0.0;
242 for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
243 const Scalar tmp = exteriorPos[dimIdx] - interiorPos[dimIdx];
244 distSquared += tmp * tmp;
245 }
246
247 // divide the gradient by the squared distance between the centers of the
248 // sub-control volumes: the gradient is the normalized directional vector between
249 // the two centers times the ratio of the difference of the values and their
250 // distance, i.e., d/abs(d) * delta y / abs(d) = d*delta y / abs(d)^2.
251 for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
252 const Scalar tmp = exteriorPos[dimIdx] - interiorPos[dimIdx];
253 quantityGrad[dimIdx] = deltay *( tmp / distSquared);
254 }
255 }
256
271 template <class QuantityCallback>
272 auto calculateBoundaryValue(const ElementContext&,
273 unsigned,
274 const QuantityCallback& quantityCallback)
275 -> decltype(quantityCallback.boundaryValue())
276 { return quantityCallback.boundaryValue(); }
277
293 template <class QuantityCallback>
294 void calculateBoundaryGradient(EvalDimVector& quantityGrad,
295 const ElementContext& elemCtx,
296 unsigned faceIdx,
297 const QuantityCallback& quantityCallback) const
298 {
299 const auto& stencil = elemCtx.stencil(/*timeIdx=*/0);
300 const auto& face = stencil.boundaryFace(faceIdx);
301
302 Evaluation deltay;
303 if (face.interiorIndex() == elemCtx.focusDofIndex()) {
304 deltay = quantityCallback.boundaryValue() - quantityCallback(face.interiorIndex());
305 }
306 else {
307 deltay = getValue(quantityCallback.boundaryValue()) -
308 getValue(quantityCallback(face.interiorIndex()));
309 }
310
311 const auto& boundaryFacePos = face.integrationPos();
312 const auto& interiorPos = stencil.subControlVolume(face.interiorIndex()).center();
313
314 Scalar distSquared = 0;
315 for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
316 const Scalar tmp = boundaryFacePos[dimIdx] - interiorPos[dimIdx];
317 distSquared += tmp * tmp;
318 }
319
320 // divide the gradient by the squared distance between the center of the
321 // sub-control and the center of the boundary face: the gradient is the
322 // normalized directional vector between the two centers times the ratio of the
323 // difference of the values and their distance, i.e., d/abs(d) * deltay / abs(d)
324 // = d*deltay / abs(d)^2.
325 for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
326 const Scalar tmp = boundaryFacePos[dimIdx] - interiorPos[dimIdx];
327 quantityGrad[dimIdx] = deltay * (tmp / distSquared);
328 }
329 }
330
331private:
332 void computeDistances_(Scalar& interiorDistance,
333 Scalar& exteriorDistance,
334 const ElementContext& elemCtx,
335 unsigned fapIdx) const
336 {
337 const auto& stencil = elemCtx.stencil(/*timeIdx=*/0);
338 const auto& face = stencil.interiorFace(fapIdx);
339
340 // calculate the distances of the position of the interior and of the exterior
341 // finite volume to the position of the integration point.
342 const auto& normal = face.normal();
343 const auto i = face.interiorIndex();
344 const auto j = face.exteriorIndex();
345 const auto& interiorPos = stencil.subControlVolume(i).globalPos();
346 const auto& exteriorPos = stencil.subControlVolume(j).globalPos();
347 const auto& integrationPos = face.integrationPos();
348
349 interiorDistance = 0.0;
350 exteriorDistance = 0.0;
351 for (unsigned dimIdx = 0; dimIdx < dimWorld; ++dimIdx) {
352 interiorDistance += (interiorPos[dimIdx] - integrationPos[dimIdx]) * normal[dimIdx];
353 exteriorDistance += (exteriorPos[dimIdx] - integrationPos[dimIdx]) * normal[dimIdx];
354 }
355
356 interiorDistance = std::sqrt(std::abs(interiorDistance));
357 exteriorDistance = std::sqrt(std::abs(exteriorDistance));
358 }
359};
360
361} // namespace Opm
362
363#endif
Defines a type tags and some fundamental properties all models.
This class calculates gradients of arbitrary quantities at flux integration points using the two-poin...
Definition: fvbasegradientcalculator.hh:52
auto calculateScalarValue(const ElementContext &elemCtx, unsigned fapIdx, const QuantityCallback &quantityCallback) const -> std::remove_reference_t< decltype(quantityCallback.operator()(0))>
Calculates the value of an arbitrary scalar quantity at any interior flux approximation point.
Definition: fvbasegradientcalculator.hh:100
void calculateBoundaryGradient(EvalDimVector &quantityGrad, const ElementContext &elemCtx, unsigned faceIdx, const QuantityCallback &quantityCallback) const
Calculates the gradient of an arbitrary quantity at any flux approximation point on the boundary.
Definition: fvbasegradientcalculator.hh:294
auto calculateVectorValue(const ElementContext &elemCtx, unsigned fapIdx, const QuantityCallback &quantityCallback) const -> std::remove_reference_t< decltype(quantityCallback.operator()(0))>
Calculates the value of an arbitrary vectorial quantity at any interior flux approximation point.
Definition: fvbasegradientcalculator.hh:149
void calculateGradient(EvalDimVector &quantityGrad, const ElementContext &elemCtx, unsigned fapIdx, const QuantityCallback &quantityCallback) const
Calculates the gradient of an arbitrary quantity at any flux approximation point.
Definition: fvbasegradientcalculator.hh:215
void prepare(const ElementContext &, unsigned)
Precomputes the common values to calculate gradients and values of quantities at every interior flux ...
Definition: fvbasegradientcalculator.hh:85
static void registerParameters()
Register all run-time parameters for the gradient calculator of the base class of the discretization.
Definition: fvbasegradientcalculator.hh:74
auto calculateBoundaryValue(const ElementContext &, unsigned, const QuantityCallback &quantityCallback) -> decltype(quantityCallback.boundaryValue())
Calculates the value of an arbitrary quantity at any flux approximation point on the grid boundary.
Definition: fvbasegradientcalculator.hh:272
Declare the properties used by the infrastructure code of the finite volume discretizations.
Definition: blackoilboundaryratevector.hh:39
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:233