fvbasefdlocallinearizer.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_FD_LOCAL_LINEARIZER_HH
29#define EWOMS_FV_BASE_FD_LOCAL_LINEARIZER_HH
30
31#include <dune/common/fmatrix.hh>
32#include <dune/common/fvector.hh>
33
34#include <dune/istl/bvector.hh>
35#include <dune/istl/matrix.hh>
36
37#include <opm/material/common/MathToolbox.hpp>
38#include <opm/material/common/Valgrind.hpp>
39
43
45
46#include <algorithm>
47#include <cmath>
48#include <cstddef>
49#include <limits>
50#include <memory>
51
52namespace Opm {
53
54// forward declaration
55template<class TypeTag>
56class FvBaseFdLocalLinearizer;
57
58} // namespace Opm
59
60namespace Opm::Properties {
61
62// declare the property tags required for the finite differences local linearizer
63
64namespace TTag {
66} // namespace TTag
67
68template<class TypeTag, class MyTypeTag>
70
71// set the properties to be spliced in
72template<class TypeTag>
73struct LocalLinearizer<TypeTag, TTag::FiniteDifferenceLocalLinearizer>
75
76template<class TypeTag>
77struct Evaluation<TypeTag, TTag::FiniteDifferenceLocalLinearizer>
79
81template<class TypeTag>
82struct BaseEpsilon<TypeTag, TTag::FiniteDifferenceLocalLinearizer>
83{
85 static constexpr type value = std::max<type>(0.9123e-10,
86 std::numeric_limits<type>::epsilon() * 1.23e3);
87};
88
89} // namespace Opm::Properties
90
91namespace Opm::Parameters {
92
100struct NumericDifferenceMethod { static constexpr int value = +1; };
101
102} // namespace Opm::Parameters
103
104namespace Opm {
105
142template<class TypeTag>
144{
145private:
155 using Element = typename GridView::template Codim<0>::Entity;
156
157 enum { numEq = getPropValue<TypeTag, Properties::NumEq>() };
158
159 // extract local matrices from jacobian matrix for consistency
161 using ScalarVectorBlock = Dune::FieldVector<Scalar, numEq>;
162
163 using ScalarLocalBlockVector = Dune::BlockVector<ScalarVectorBlock>;
164 using ScalarLocalBlockMatrix = Dune::Matrix<ScalarMatrixBlock>;
165
166 using LocalEvalBlockVector = typename LocalResidual::LocalEvalBlockVector;
167
168public:
170
171 // Disable copying for efficiency reasons
173
177 static void registerParameters()
178 {
179 Parameters::Register<Parameters::NumericDifferenceMethod>
180 ("The method used for numeric differentiation (-1: backward "
181 "differences, 0: central differences, 1: forward differences)");
182 }
183
192 void init(Simulator& simulator)
193 {
194 simulatorPtr_ = &simulator;
195 internalElemContext_ = std::make_unique<ElementContext>(simulator);
196 }
197
209 void linearize(const Element& element)
210 {
212 }
213
228 void linearize(ElementContext& elemCtx, const Element& elem)
229 {
230 elemCtx.updateAll(elem);
231
232 // update the weights of the primary variables for the context
233 model_().updatePVWeights(elemCtx);
234
235 resize_(elemCtx);
236 reset_(elemCtx);
237
238 // calculate the local residual
239 localResidual_.eval(residual_, elemCtx);
240
241 // calculate the local jacobian matrix
242 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
243 for (auto dofIdx = 0 * numPrimaryDof; dofIdx < numPrimaryDof; ++dofIdx) {
244 for (auto pvIdx = 0 * numEq; pvIdx < numEq; ++pvIdx) {
245 asImp_().evalPartialDerivative_(elemCtx, dofIdx, pvIdx);
246
247 // incorporate the partial derivatives into the local Jacobian matrix
248 updateLocalJacobian_(elemCtx, dofIdx, pvIdx);
249 }
250 }
251 }
252
257 static Scalar baseEpsilon()
258 { return getPropValue<TypeTag, Properties::BaseEpsilon>(); }
259
271 Scalar numericEpsilon(const ElementContext& elemCtx,
272 unsigned dofIdx,
273 unsigned pvIdx) const
274 {
275 const unsigned globalIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0);
276 const Scalar pvWeight = elemCtx.model().primaryVarWeight(globalIdx, pvIdx);
277 assert(pvWeight > 0 && std::isfinite(pvWeight));
278 Valgrind::CheckDefined(pvWeight);
279
280 return baseEpsilon() / pvWeight;
281 }
282
286 LocalResidual& localResidual()
287 { return localResidual_; }
288
292 const LocalResidual& localResidual() const
293 { return localResidual_; }
294
303 const ScalarMatrixBlock& jacobian(unsigned domainScvIdx, unsigned rangeScvIdx) const
304 { return jacobian_[domainScvIdx][rangeScvIdx]; }
305
311 const ScalarVectorBlock& residual(unsigned dofIdx) const
312 { return residual_[dofIdx]; }
313
314protected:
315 Implementation& asImp_()
316 { return *static_cast<Implementation*>(this); }
317
318 const Implementation& asImp_() const
319 { return *static_cast<const Implementation*>(this); }
320
321 const Simulator& simulator_() const
322 { return *simulatorPtr_; }
323
324 const Problem& problem_() const
325 { return simulatorPtr_->problem(); }
326
327 const Model& model_() const
328 { return simulatorPtr_->model(); }
329
334 {
335 static int diff = Parameters::Get<Parameters::NumericDifferenceMethod>();
336 return diff;
337 }
338
343 void resize_(const ElementContext& elemCtx)
344 {
345 const std::size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
346 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
347
348 residual_.resize(numDof);
349 jacobian_.setSize(numDof, numPrimaryDof);
350
351 derivResidual_.resize(numDof);
352 }
353
357 void reset_(const ElementContext& elemCtx)
358 {
359 const std::size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
360 const std::size_t numPrimaryDof = elemCtx.numPrimaryDof(/*timeIdx=*/0);
361 for (unsigned primaryDofIdx = 0; primaryDofIdx < numPrimaryDof; ++primaryDofIdx) {
362 for (unsigned dof2Idx = 0; dof2Idx < numDof; ++dof2Idx) {
363 jacobian_[dof2Idx][primaryDofIdx] = 0.0;
364 }
365 }
366
367 for (unsigned primaryDofIdx = 0; primaryDofIdx < numDof; ++primaryDofIdx) {
368 residual_[primaryDofIdx] = 0.0;
369 }
370 }
371
414 void evalPartialDerivative_(ElementContext& elemCtx,
415 unsigned dofIdx,
416 unsigned pvIdx)
417 {
418 // save all quantities which depend on the specified primary
419 // variable at the given sub control volume
420 elemCtx.stashIntensiveQuantities(dofIdx);
421
422 PrimaryVariables priVars(elemCtx.primaryVars(dofIdx, /*timeIdx=*/0));
423 const Scalar eps = asImp_().numericEpsilon(elemCtx, dofIdx, pvIdx);
424 Scalar delta = 0.0;
425
426 if (numericDifferenceMethod_() >= 0) {
427 // we are not using backward differences, i.e. we need to
428 // calculate f(x + \epsilon)
429
430 // deflect primary variables
431 priVars[pvIdx] += eps;
432 delta += eps;
433
434 // calculate the deflected residual
435 elemCtx.updateIntensiveQuantities(priVars, dofIdx, /*timeIdx=*/0);
436 elemCtx.updateAllExtensiveQuantities();
437 localResidual_.eval(derivResidual_, elemCtx);
438 }
439 else {
440 // we are using backward differences, i.e. we don't need
441 // to calculate f(x + \epsilon) and we can recycle the
442 // (already calculated) residual f(x)
444 }
445
446 if (numericDifferenceMethod_() <= 0) {
447 // we are not using forward differences, i.e. we don't
448 // need to calculate f(x - \epsilon)
449
450 // deflect the primary variables
451 priVars[pvIdx] -= delta + eps;
452 delta += eps;
453
454 // calculate the deflected residual again, this time we use the local
455 // residual's internal storage.
456 elemCtx.updateIntensiveQuantities(priVars, dofIdx, /*timeIdx=*/0);
457 elemCtx.updateAllExtensiveQuantities();
458 localResidual_.eval(elemCtx);
459
460 derivResidual_ -= localResidual_.residual();
461 }
462 else {
463 // we are using forward differences, i.e. we don't need to
464 // calculate f(x - \epsilon) and we can recycle the
465 // (already calculated) residual f(x)
467 }
468
469 assert(delta > 0);
470
471 // divide difference in residuals by the magnitude of the
472 // deflections between the two function evaluation
473 derivResidual_ /= delta;
474
475 // restore the original state of the element's volume
476 // variables
477 elemCtx.restoreIntensiveQuantities(dofIdx);
478
479#ifndef NDEBUG
480 for (unsigned i = 0; i < derivResidual_.size(); ++i) {
481 Valgrind::CheckDefined(derivResidual_[i]);
482 }
483#endif
484 }
485
491 void updateLocalJacobian_(const ElementContext& elemCtx,
492 unsigned focusDofIdx,
493 unsigned pvIdx)
494 {
495 const std::size_t numDof = elemCtx.numDof(/*timeIdx=*/0);
496 for (unsigned dofIdx = 0; dofIdx < numDof; ++dofIdx) {
497 for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) {
498 // A[dofIdx][focusDofIdx][eqIdx][pvIdx] is the partial derivative of the
499 // residual function 'eqIdx' for the degree of freedom 'dofIdx' with
500 // regard to the primary variable 'pvIdx' of the degree of freedom
501 // 'focusDofIdx'
502 jacobian_[dofIdx][focusDofIdx][eqIdx][pvIdx] = derivResidual_[dofIdx][eqIdx];
503 Valgrind::CheckDefined(jacobian_[dofIdx][focusDofIdx][eqIdx][pvIdx]);
504 }
505 }
506 }
507
508 Simulator* simulatorPtr_{};
509
510 std::unique_ptr<ElementContext> internalElemContext_{};
511
512 LocalEvalBlockVector residual_{};
513 LocalEvalBlockVector derivResidual_{};
514 ScalarLocalBlockMatrix jacobian_{};
515
516 LocalResidual localResidual_{};
517};
518
519} // namespace Opm
520
521#endif
Calculates the Jacobian of the local residual for finite volume spatial discretizations using a finit...
Definition: fvbasefdlocallinearizer.hh:144
const Implementation & asImp_() const
Definition: fvbasefdlocallinearizer.hh:318
std::unique_ptr< ElementContext > internalElemContext_
Definition: fvbasefdlocallinearizer.hh:510
LocalEvalBlockVector derivResidual_
Definition: fvbasefdlocallinearizer.hh:513
void evalPartialDerivative_(ElementContext &elemCtx, unsigned dofIdx, unsigned pvIdx)
Compute the partial derivatives of a context's residual functions.
Definition: fvbasefdlocallinearizer.hh:414
void linearize(const Element &element)
Compute an element's local Jacobian matrix and evaluate its residual.
Definition: fvbasefdlocallinearizer.hh:209
Scalar numericEpsilon(const ElementContext &elemCtx, unsigned dofIdx, unsigned pvIdx) const
Returns the epsilon value which is added and removed from the current solution.
Definition: fvbasefdlocallinearizer.hh:271
LocalResidual localResidual_
Definition: fvbasefdlocallinearizer.hh:516
static Scalar baseEpsilon()
Returns the unweighted epsilon value used to calculate the local derivatives.
Definition: fvbasefdlocallinearizer.hh:257
void updateLocalJacobian_(const ElementContext &elemCtx, unsigned focusDofIdx, unsigned pvIdx)
Updates the current local Jacobian matrix with the partial derivatives of all equations for primary v...
Definition: fvbasefdlocallinearizer.hh:491
const Model & model_() const
Definition: fvbasefdlocallinearizer.hh:327
FvBaseFdLocalLinearizer(const FvBaseFdLocalLinearizer &)=delete
ScalarLocalBlockMatrix jacobian_
Definition: fvbasefdlocallinearizer.hh:514
static int numericDifferenceMethod_()
Returns the numeric difference method which is applied.
Definition: fvbasefdlocallinearizer.hh:333
const ScalarMatrixBlock & jacobian(unsigned domainScvIdx, unsigned rangeScvIdx) const
Returns the local Jacobian matrix of the residual of a sub-control volume.
Definition: fvbasefdlocallinearizer.hh:303
static void registerParameters()
Register all run-time parameters for the local jacobian.
Definition: fvbasefdlocallinearizer.hh:177
const Simulator & simulator_() const
Definition: fvbasefdlocallinearizer.hh:321
const LocalResidual & localResidual() const
Return reference to the local residual.
Definition: fvbasefdlocallinearizer.hh:292
Simulator * simulatorPtr_
Definition: fvbasefdlocallinearizer.hh:508
void init(Simulator &simulator)
Initialize the local Jacobian object.
Definition: fvbasefdlocallinearizer.hh:192
const ScalarVectorBlock & residual(unsigned dofIdx) const
Returns the local residual of a sub-control volume.
Definition: fvbasefdlocallinearizer.hh:311
const Problem & problem_() const
Definition: fvbasefdlocallinearizer.hh:324
LocalEvalBlockVector residual_
Definition: fvbasefdlocallinearizer.hh:512
void linearize(ElementContext &elemCtx, const Element &elem)
Compute an element's local Jacobian matrix and evaluate its residual.
Definition: fvbasefdlocallinearizer.hh:228
void reset_(const ElementContext &elemCtx)
Reset the all relevant internal attributes to 0.
Definition: fvbasefdlocallinearizer.hh:357
LocalResidual & localResidual()
Return reference to the local residual.
Definition: fvbasefdlocallinearizer.hh:286
void resize_(const ElementContext &elemCtx)
Resize all internal attributes to the size of the element.
Definition: fvbasefdlocallinearizer.hh:343
Implementation & asImp_()
Definition: fvbasefdlocallinearizer.hh:315
Declare the properties used by the infrastructure code of the finite volume discretizations.
Declares the properties required by the black oil model.
Definition: blackoilnewtonmethodparams.hpp:31
Definition: blackoilmodel.hh:79
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
This file provides the infrastructure to retrieve run-time parameters.
The Opm property system, traits with inheritance.
Specify which kind of method should be used to numerically calculate the partial derivatives of the r...
Definition: fvbasefdlocallinearizer.hh:100
static constexpr int value
Definition: fvbasefdlocallinearizer.hh:100
GetPropType< TypeTag, Properties::Scalar > type
Definition: fvbasefdlocallinearizer.hh:84
Definition: fvbasefdlocallinearizer.hh:69
GetPropType< TypeTag, Properties::Scalar > type
Definition: fvbasefdlocallinearizer.hh:78
Representation of a function evaluation and all necessary derivatives with regard to the intensive qu...
Definition: fvbaseproperties.hh:66
The type of the local linearizer.
Definition: fvbaseproperties.hh:97
Definition: fvbasefdlocallinearizer.hh:65
a tag to mark properties as undefined
Definition: propertysystem.hh:38