fvbaselinearizer.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) 2010-2015 by Andreas Lauser
5  Copyright (C) 2009-2011 by Bernd Flemisch
6 
7  This file is part of the Open Porous Media project (OPM).
8 
9  OPM is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 2 of the License, or
12  (at your option) any later version.
13 
14  OPM is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with OPM. If not, see <http://www.gnu.org/licenses/>.
21 */
27 #ifndef EWOMS_FV_BASE_LINEARIZER_HH
28 #define EWOMS_FV_BASE_LINEARIZER_HH
29 
30 #include "fvbaseproperties.hh"
31 
36 
37 #include <dune/common/fvector.hh>
38 #include <dune/common/fmatrix.hh>
39 
40 #include <type_traits>
41 #include <iostream>
42 #include <vector>
43 #include <set>
44 
45 namespace Ewoms {
46 // forward declarations
47 template<class TypeTag>
48 class EcfvDiscretization;
49 
59 template<class TypeTag>
61 {
63  typedef typename GET_PROP_TYPE(TypeTag, Model) Model;
64  typedef typename GET_PROP_TYPE(TypeTag, Discretization) Discretization;
65  typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
66  typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator;
67  typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
68  typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
69  typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation;
70  typedef typename GET_PROP_TYPE(TypeTag, DofMapper) DofMapper;
71  typedef typename GET_PROP_TYPE(TypeTag, ElementMapper) ElementMapper;
72  typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext;
73 
74  typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector;
75  typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) GlobalEqVector;
76  typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix;
77  typedef typename GET_PROP_TYPE(TypeTag, EqVector) EqVector;
78  typedef typename GET_PROP_TYPE(TypeTag, Stencil) Stencil;
79  typedef typename GET_PROP_TYPE(TypeTag, ThreadManager) ThreadManager;
80 
81  typedef typename GET_PROP_TYPE(TypeTag, GridCommHandleFactory) GridCommHandleFactory;
82 
83  typedef Opm::MathToolbox<Evaluation> Toolbox;
84 
85  typedef typename GridView::template Codim<0>::Entity Element;
86  typedef typename GridView::template Codim<0>::Iterator ElementIterator;
87 
88  typedef GlobalEqVector Vector;
89  typedef JacobianMatrix Matrix;
90 
91  enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
92  enum { historySize = GET_PROP_VALUE(TypeTag, TimeDiscHistorySize) };
93 
94  typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock;
95  typedef Dune::FieldVector<Scalar, numEq> VectorBlock;
96 
97  static const bool linearizeNonLocalElements = GET_PROP_VALUE(TypeTag, LinearizeNonLocalElements);
98 
99  // copying the linearizer is not a good idea
102 
103 public:
108  enum EntityColor {
113  Red = 2,
114 
119  Yellow = 1,
120 
124  Green = 0
125  };
126 
128  {
129  simulatorPtr_ = 0;
130 
131  matrix_ = 0;
132 
133  // set relinearization accuracies to 0, so that if partial relinearization of the
134  // system of equations is disabled, the relinearization accuracy is always
135  // smaller than the current tolerance
136  relinearizationAccuracy_ = 0.0;
137  }
138 
140  {
141  delete matrix_;
142  auto it = elementCtx_.begin();
143  const auto &endIt = elementCtx_.end();
144  for (; it != endIt; ++it)
145  delete *it;
146  }
147 
151  static void registerParameters()
152  {
153  EWOMS_REGISTER_PARAM(TypeTag, bool, EnableLinearizationRecycling,
154  "Re-use of the linearized system of equations at the first "
155  "iteration of the next time step");
156  EWOMS_REGISTER_PARAM(TypeTag, bool, EnablePartialRelinearization,
157  "relinearize only those degrees of freedom that have changed "
158  "'sufficiently' between two Newton iterations");
159  }
160 
170  void init(Simulator& simulator)
171  {
172  simulatorPtr_ = &simulator;
173  delete matrix_; // <- note that this even works for nullpointers!
174  matrix_ = 0;
175  }
176 
181  {
182  delete matrix_; // <- note that this even works for nullpointers!
183  matrix_ = 0;
184  }
185 
195  void linearize()
196  {
197  // we defer the initialization of the Jacobian matrix until here because the
198  // auxiliary modules usually assume the problem, model and grid to be fully
199  // initialized...
200  if (!matrix_)
201  initFirstIteration_();
202 
203  // we need to store whether the linearization was recycled
204  // here because the linearize_ method modifies the
205  // reuseLinearization_ attribute!
206  bool linearizationReused = reuseLinearization_;
207 
208  // store the data required for the end-of-iteration message here because the
209  // linearize_() method modifies them for the next iteration...
210  int curNumRelin = numTotalElems_ - numGreenElems_;
211  Scalar curRelAcc = relinearizationAccuracy_;
212 
213  int succeeded;
214  try {
215  linearize_();
216  succeeded = 1;
217  succeeded = gridView_().comm().min(succeeded);
218  }
219  catch (Opm::NumericalProblem &e)
220  {
221  std::cout << "rank " << simulator_().gridView().comm().rank()
222  << " caught an exception while linearizing:" << e.what()
223  << "\n" << std::flush;
224  succeeded = 0;
225  succeeded = gridView_().comm().min(succeeded);
226  }
227 
228  if (!succeeded) {
229  OPM_THROW(Opm::NumericalProblem,
230  "A process did not succeed in linearizing the system");
231  }
232 
233  if (!linearizationReused && enablePartialRelinearization_()) {
234  model_().newtonMethod().endIterMsg()
235  << ", relinearized " << curNumRelin << " of " << numTotalElems_
236  << " elements (" << 100*Scalar(curNumRelin)/numTotalElems_ << "%)"
237  << " and achieved a accuracy of " << curRelAcc;
238  }
239  }
240 
248  void setLinearizationReusable(bool yesno = true)
249  {
250  if (enableLinearizationRecycling_())
251  reuseLinearization_ = yesno;
252  }
253 
259  {
260  // do not reuse the current linearization
261  reuseLinearization_ = false;
262 
263  // do not use partial relinearization for the next iteration
264  relinearizationAccuracy_ = 0.0;
265  relinearizationTolerance_ = 0.0;
266  numGreenElems_ = 0;
267  if (enablePartialRelinearization_()) {
268  std::fill(dofError_.begin(), dofError_.end(), 1e100);
269  std::fill(dofColor_.begin(), dofColor_.end(), Red);
270  std::fill(elementColor_.begin(), elementColor_.end(), Red);
271  }
272 
273  // set the intensive quantities cache
274  auto &model = model_();
275  int numGridDof = model.numGridDof();
276  for (int timeIdx = 0; timeIdx < historySize; ++timeIdx) {
277  for (int dofIdx = 0; dofIdx < numGridDof; ++dofIdx) {
278  model.setIntensiveQuantitiesCacheEntryValidity(dofIdx, timeIdx, false);
279  }
280  }
281  }
282 
293  Scalar relinearizationAccuracy() const
294  { return relinearizationAccuracy_; }
295 
299  Scalar maxDofError() const
300  { return maxDofError_; }
301 
312  void updateRelinearizationErrors(const GlobalEqVector &uDelta, const GlobalEqVector &resid)
313  {
314  if (!enablePartialRelinearization_())
315  return;
316 
317  unsigned numGridDof = model_().numGridDof();
318 
319  // update the vector which stores the error for partial
320  // relinearization for each degree of freedom
321  maxDofError_ = 0;
322  for (unsigned globalDofIdx = 0; globalDofIdx < numGridDof; ++globalDofIdx) {
323  if (!model_().isLocalDof(globalDofIdx)) {
324  // ignore degrees of freedom of overlap and ghost degrees of freedom
325  dofError_[globalDofIdx] = 0;
326  continue;
327  }
328 
329  // compute the error of the solution at a given DOF. we use the weighted
330  // magnitude of the deviation between the solution for two consecutive
331  // iterations.
332  const auto &d = uDelta[globalDofIdx];
333  Scalar distRel = 0;
334  for (unsigned pvIdx = 0; pvIdx < d.size(); ++pvIdx) {
335  Scalar tmp = std::abs(d[pvIdx]*model_().primaryVarWeight(globalDofIdx, pvIdx));
336  distRel = std::max(distRel, tmp);
337  }
338  Valgrind::CheckDefined(distRel);
339  dofError_[globalDofIdx] += distRel;
340  maxDofError_ = std::max(maxDofError_, dofError_[globalDofIdx]);
341  }
342  }
343 
350  void markDofRed(int dofIdx)
351  {
352  if (enablePartialRelinearization_())
353  dofError_[dofIdx] = 1e100;
354  this->model_().setIntensiveQuantitiesCacheEntryValidity(dofIdx, /*timeIdx=*/0, false);
355  }
356 
360  EntityColor dofColor(int dofIdx) const
361  {
362  if (!enablePartialRelinearization_())
363  return Red;
364  return dofColor_[dofIdx];
365  }
366 
370  EntityColor elementColor(int elemIdx) const
371  {
372  if (!enablePartialRelinearization_())
373  return Red;
374  return elementColor_[elemIdx];
375  }
376 
381  { return relinearizationTolerance_; }
382 
386  void setRelinearizationTolerance(Scalar tolerance)
387  { relinearizationTolerance_ = tolerance; }
388 
392  Scalar dofError(int dofIdx) const
393  { return dofError_[dofIdx]; }
394 
398  const Matrix &matrix() const
399  { return *matrix_; }
400 
404  const GlobalEqVector &residual() const
405  { return residual_; }
406 
407 private:
413  void computeColors_()
414  {
415  if (!enablePartialRelinearization_())
416  return;
417 
418  // mark the red degrees of freedom and update the tolerance of
419  // the linearization which actually will get achieved
420  for (unsigned dofIdx = 0; dofIdx < dofColor_.size(); ++dofIdx) {
421  if (dofError_[dofIdx] > relinearizationTolerance_) {
422  // mark the degree of freedom 'red' if discrepancy is
423  // larger than the given tolerance
424  dofColor_[dofIdx] = Red;
425  dofError_[dofIdx] = 0.0;
426  }
427  else if (!model_().isLocalDof(dofIdx)) {
428  // always mark non-local degrees of freedom as red
429  dofColor_[dofIdx] = Red;
430  dofError_[dofIdx] = 0.0;
431  }
432  else
433  dofColor_[dofIdx] = Green;
434  }
435 
436  // mark all elements that connect to red ones as yellow
437  int numGridDof = this->model_().numGridDof();
438  for (int dofIdx = 0; dofIdx < numGridDof; ++dofIdx) {
439  if (dofColor_[dofIdx] != Red)
440  continue;
441 
442  typedef typename JacobianMatrix::ColIterator ColIterator;
443  ColIterator colIt = (*matrix_)[dofIdx].begin();
444  const ColIterator &colEndIt = (*matrix_)[dofIdx].end();
445  for (; colIt != colEndIt; ++colIt) {
446  int dof2Idx = colIt.index();
447  if (dof2Idx >= numGridDof)
448  break; // auxiliary equation
449 
450  if (dofColor_[dof2Idx] != Red)
451  dofColor_[dof2Idx] = Yellow;
452  }
453  }
454 
455  // calculate the element colors from the DOF colors. for the element centered
456  // finite volume discretization, we can just copy the values. For other
457  // discretizations, we need to loop over the grid and check if an element's
458  // stencil contains a non-green DOFs.
459  if (std::is_same<Discretization, EcfvDiscretization<TypeTag> >::value)
460  elementColor_ = dofColor_;
461  else {
462  const auto& gridView = this->model_().gridView();
463  const auto& elemMapper = this->model_().elementMapper();
464  Stencil stencil(gridView);
465  ElementIterator elemIt = gridView.template begin</*codim=*/0>();
466  const ElementIterator& elemEndIt = gridView.template end</*codim=*/0>();
467  for (; elemIt != elemEndIt; ++elemIt) {
468  const Element& elem = *elemIt;
469  stencil.updateTopology(elem);
470 
471 #if DUNE_VERSION_NEWER(DUNE_COMMON, 2,4)
472  int elemIdx = elemMapper.index(elem);
473 #else
474  int elemIdx = elemMapper.map(elem);
475 #endif
476  int numElemDof = stencil.numDof();
477 
478  // determine the element color: it is red if any of the DOFs in its
479  // stencil are non-green, else it is green.
480  elementColor_[elemIdx] = Green;
481  for (int elemDofIdx = 0; elemDofIdx < numElemDof; ++elemDofIdx) {
482  int dofIdx = stencil.globalSpaceIndex(elemDofIdx);
483  if (dofColor_[dofIdx] != Green) {
484  elementColor_[elemIdx] = Red;
485  break;
486  }
487  }
488  }
489  }
490 
491  // gather statistics
492  relinearizationAccuracy_ = 0;
493  numGreenElems_ = 0;
494  for (unsigned dofIdx = 0; dofIdx < dofColor_.size(); ++dofIdx) {
495  if (dofColor_[dofIdx] != Red) {
496  relinearizationAccuracy_ =
497  std::max(relinearizationAccuracy_, dofError_[dofIdx]);
498 
499  if (dofColor_[dofIdx] == Green)
500  ++numGreenElems_;
501  continue;
502  }
503  }
504 
505  relinearizationAccuracy_ = gridView_().comm().max(relinearizationAccuracy_);
506  numGreenElems_ = gridView_().comm().sum(numGreenElems_);
507  }
508 
509  static bool enableLinearizationRecycling_()
510  { return EWOMS_GET_PARAM(TypeTag, bool, EnableLinearizationRecycling); }
511  static bool enablePartialRelinearization_()
512  { return EWOMS_GET_PARAM(TypeTag, bool, EnablePartialRelinearization); }
513 
514  Simulator &simulator_()
515  { return *simulatorPtr_; }
516  const Simulator &simulator_() const
517  { return *simulatorPtr_; }
518 
519  Problem &problem_()
520  { return simulator_().problem(); }
521  const Problem &problem_() const
522  { return simulator_().problem(); }
523 
524  Model &model_()
525  { return simulator_().model(); }
526  const Model &model_() const
527  { return simulator_().model(); }
528 
529  const GridView &gridView_() const
530  { return problem_().gridView(); }
531 
532  const ElementMapper &elementMapper_() const
533  { return model_().elementMapper(); }
534 
535  const DofMapper &dofMapper_() const
536  { return model_().dofMapper(); }
537 
538  void initFirstIteration_()
539  {
540  // calculate the number of DOFs and elements for the local process and for the
541  // whole simulation
542  int numGridDof = model_().numGridDof();
543  int numAllDof = model_().numTotalDof();
544  int numElems = gridView_().size(/*codim=*/0);
545  numTotalElems_ = gridView_().comm().sum(numElems);
546 
547  // initialize the BCRS matrix for the Jacobian
548  createMatrix_();
549 
550  // initialize the jacobian matrix and the right hand side
551  // vector
552  *matrix_ = 0;
553  residual_.resize(numAllDof);
554  residual_ = 0;
555 
556  // create the per-thread context objects
557  elementCtx_.resize(ThreadManager::maxThreads());
558  for (int threadId = 0; threadId != ThreadManager::maxThreads(); ++ threadId)
559  elementCtx_[threadId] = new ElementContext(simulator_());
560 
561  // initialize the storage part of the Jacobian matrix. Since we only need this if
562  // linearization recycling is enabled, we do not waste space if it is disabled
563  if (enableLinearizationRecycling_()) {
564  storageJacobian_.resize(numGridDof);
565  storageTerm_.resize(numGridDof);
566  }
567 
568  // initialize data needed for partial relinearization
569  reuseLinearization_ = false;
570  if (enablePartialRelinearization_()) {
571  dofColor_.resize(numGridDof);
572  dofError_.resize(numGridDof);
573  elementColor_.resize(numElems);
574  relinearizeAll();
575  }
576  }
577 
578  // Construct the BCRS matrix for the global jacobian
579  void createMatrix_()
580  {
581  int numAllDof = model_().numTotalDof();
582 
583  // allocate raw matrix
584  matrix_ = new Matrix(numAllDof, numAllDof, Matrix::random);
585 
586  Stencil stencil(gridView_());
587 
588  // for the main model, find out the global indices of the neighboring degrees of
589  // freedom of each primary degree of freedom
590  typedef std::set<int> NeighborSet;
591  std::vector<NeighborSet> neighbors(numAllDof);
592  ElementIterator elemIt = gridView_().template begin<0>();
593  const ElementIterator elemEndIt = gridView_().template end<0>();
594  for (; elemIt != elemEndIt; ++elemIt) {
595  const Element &elem = *elemIt;
596  stencil.update(elem);
597 
598  for (int primaryDofIdx = 0; primaryDofIdx < stencil.numPrimaryDof(); ++primaryDofIdx) {
599  int myIdx = stencil.globalSpaceIndex(primaryDofIdx);
600 
601  for (int dofIdx = 0; dofIdx < stencil.numDof(); ++dofIdx) {
602  int neighborIdx = stencil.globalSpaceIndex(dofIdx);
603  neighbors[myIdx].insert(neighborIdx);
604  }
605  }
606  }
607 
608  // add the additional neighbors and degrees of freedom caused by the auxiliary
609  // equations
610  const auto& model = model_();
611  int numAuxMod = model.numAuxiliaryModules();
612  for (int auxModIdx = 0; auxModIdx < numAuxMod; ++auxModIdx)
613  model.auxiliaryModule(auxModIdx)->addNeighbors(neighbors);
614 
615  // allocate space for the rows of the matrix
616  for (int dofIdx = 0; dofIdx < numAllDof; ++ dofIdx)
617  matrix_->setrowsize(dofIdx, neighbors[dofIdx].size());
618  matrix_->endrowsizes();
619 
620  // fill the rows with indices. each degree of freedom talks to
621  // all of its neighbors. (it also talks to itself since
622  // degrees of freedom are sometimes quite egocentric.)
623  for (int dofIdx = 0; dofIdx < numAllDof; ++ dofIdx) {
624  typename NeighborSet::iterator nIt = neighbors[dofIdx].begin();
625  typename NeighborSet::iterator nEndIt = neighbors[dofIdx].end();
626  for (; nIt != nEndIt; ++nIt)
627  matrix_->addindex(dofIdx, *nIt);
628  }
629  matrix_->endindices();
630  }
631 
632  // reset the global linear system of equations. if partial
633  // relinearization is enabled, this means that the Jacobian matrix
634  // must only be erased partially!
635  void resetSystem_()
636  {
637  size_t numGridDof = model_().numGridDof();
638  size_t numTotalDof = model_().numTotalDof();
639 
640  if (!enablePartialRelinearization_()) {
641  // if partial re-linearization is not enabled, we can just reset everything!
642  residual_ = 0.0;
643  (*matrix_) = 0;
644 
645  // reset the parts needed for linearization recycling
646  if (enableLinearizationRecycling_()) {
647  for (unsigned dofIdx=0; dofIdx < numGridDof; ++ dofIdx) {
648  storageTerm_[dofIdx] = 0.0;
649  storageJacobian_[dofIdx] = 0.0;
650  }
651  }
652 
653  return;
654  }
655 
656  // always reset the right hand side completely
657  residual_ = 0.0;
658  if (enableLinearizationRecycling_())
659  for (unsigned dofIdx = 0; dofIdx < numGridDof; ++dofIdx)
660  storageTerm_[dofIdx] = 0.0;
661 
662  // reset the rows in the Jacobian which correspond to DOFs of auxiliary equations
663  for (unsigned dofIdx = numGridDof; dofIdx < numTotalDof; ++dofIdx) {
664  // reset the row of the Jacobian matrix
665  typedef typename JacobianMatrix::ColIterator ColIterator;
666  ColIterator colIt = (*matrix_)[dofIdx].begin();
667  const ColIterator &colEndIt = (*matrix_)[dofIdx].end();
668  for (; colIt != colEndIt; ++colIt) {
669  (*colIt) = 0.0;
670  }
671  }
672 
673  // partially reset the current linearization for rows corresponding to grid DOFs
674  for (unsigned dofIdx = 0; dofIdx < numGridDof; ++dofIdx) {
675  if (dofColor(dofIdx) == Green) {
676  // for green DOFs we keep the left hand side of the current linearization
677  // except for the entries of the Jacobian matrix which connect the green
678  // DOF with auxiliary equations. the implementation of this this is
679  // slightly hacky because it implicitly assumes that all auxiliary DOFs
680  // are placed after the grid DOFs and that auxiliary DOFs don't change
681  // any entries of grid DOFs. For auxiliary equations where this is not
682  // the case, we would need to mark all grid DOFs which have a connection
683  // to an auxiliary DOF as red...
684  typedef typename JacobianMatrix::ColIterator ColIterator;
685  ColIterator colIt = (*matrix_)[dofIdx].beforeEnd();
686  const ColIterator colBeginIt = (*matrix_)[dofIdx].beforeBegin();
687  for (; colIt != colBeginIt; -- colIt) {
688  if (colIt.index() < numGridDof)
689  // the column corresponds to a grid DOF. we have reset
690  // everything.
691  break;
692 
693  // the column corresponds to an auxiliary DOF
694  (*colIt) = 0.0;
695  }
696  }
697  else {
698  // red or yellow DOF
699  if (enableLinearizationRecycling_())
700  storageJacobian_[dofIdx] = 0.0;
701 
702  // reset all entries in the row of the Jacobian which connect two non-green
703  // degrees of freedom
704  typedef typename JacobianMatrix::ColIterator ColIterator;
705  ColIterator colIt = (*matrix_)[dofIdx].begin();
706  const ColIterator &colEndIt = (*matrix_)[dofIdx].end();
707  for (; colIt != colEndIt; ++colIt) {
708  if (colIt.index() >= numGridDof || dofColor_[colIt.index()] != Green)
709  // the entry either corresponds to an auxiliary DOF or to a non-green
710  // grid DOF.
711  (*colIt) = 0.0;
712  }
713  }
714  }
715  }
716 
717  // linearize the whole system
718  void linearize_()
719  {
720  // if we can "recycle" the current linearization, we do it
721  // here and be done with it...
722  Scalar curDt = problem_().simulator().timeStepSize();
723  if (reuseLinearization_) {
724  int numGridDof = model_().numGridDof();
725  for (int dofIdx = 0; dofIdx < numGridDof; ++dofIdx) {
726  // use the flux term plus the source term as the residual: the numerator
727  // in the d(storage)/dt term is 0 for the first iteration of a time step
728  // because the initial guess for the next solution is the value of the
729  // last time step.
730  residual_[dofIdx] -= storageTerm_[dofIdx];
731 
732  // rescale the contributions of the storage term to the Jacobian matrix
733  MatrixBlock &J_ii = (*matrix_)[dofIdx][dofIdx];
734 
735  J_ii -= storageJacobian_[dofIdx];
736  storageJacobian_[dofIdx] *= oldDt_/curDt;
737  J_ii += storageJacobian_[dofIdx];
738  }
739 
740  reuseLinearization_ = false;
741  oldDt_ = curDt;
742 
743  linearizeAuxiliaryEquations_();
744 
745  problem_().newtonMethod().endIterMsg()
746  << ", linear system of equations rescaled using previous time step";
747  return;
748  }
749 
750  oldDt_ = curDt;
751  computeColors_();
752  resetSystem_();
753 
754  // relinearize the elements...
755  ThreadedEntityIterator<GridView, /*codim=*/0> threadedElemIt(gridView_());
756 #ifdef _OPENMP
757 #pragma omp parallel
758 #endif
759  {
760  ElementIterator elemIt = gridView_().template begin</*codim=*/0>();
761  for (threadedElemIt.beginParallel(elemIt);
762  !threadedElemIt.isFinished(elemIt);
763  threadedElemIt.increment(elemIt))
764  {
765  const Element &elem = *elemIt;
766 
767  if (!linearizeNonLocalElements && elem.partitionType() != Dune::InteriorEntity)
768  continue;
769 
770  linearizeElement_(elem);
771  }
772  }
773 
774  linearizeAuxiliaryEquations_();
775  }
776 
777  // linearize an element in the interior of the process' grid partition
778  void linearizeElement_(const Element &elem)
779  {
780  if (enablePartialRelinearization_()) {
781 #if DUNE_VERSION_NEWER(DUNE_COMMON, 2, 4)
782  int globalElemIdx = model_().elementMapper().index(elem);
783 #else
784  int globalElemIdx = model_().elementMapper().map(elem);
785 #endif
786  if (elementColor(globalElemIdx) == Green) {
787  linearizeGreenElement_(elem);
788  return;
789  }
790  }
791 
792  int threadId = ThreadManager::threadId();
793 
794  ElementContext *elementCtx = elementCtx_[threadId];
795  auto &localLinearizer = model_().localLinearizer(threadId);
796 
797  // the actual work of linearization is done by the local linearizer class
798  elementCtx->updateAll(elem);
799  localLinearizer.linearize(*elementCtx);
800 
801  // update the right hand side and the Jacobian matrix
802  ScopedLock addLock(globalMatrixMutex_);
803  int numPrimaryDof = elementCtx->numPrimaryDof(/*timeIdx=*/0);
804  for (int primaryDofIdx = 0; primaryDofIdx < numPrimaryDof; ++ primaryDofIdx) {
805  int globI = elementCtx->globalSpaceIndex(/*spaceIdx=*/primaryDofIdx, /*timeIdx=*/0);
806 
807  // we only need to update the Jacobian matrix for entries which connect two
808  // non-green DOFs. if the row DOF corresponds to a green one, we can skip the
809  // whole row...
810  if (dofColor(globI) == Green)
811  continue;
812 
813  // update the right hand side
814  residual_[globI] += localLinearizer.residual(primaryDofIdx);
815 
816  if (enableLinearizationRecycling_()) {
817  storageTerm_[globI] += localLinearizer.residualStorage(primaryDofIdx);
818  storageJacobian_[globI] += localLinearizer.jacobianStorage(primaryDofIdx);
819  }
820 
821  // update the global Jacobian matrix
822  for (int dofIdx = 0; dofIdx < elementCtx->numDof(/*timeIdx=*/0); ++ dofIdx) {
823  int globJ = elementCtx->globalSpaceIndex(/*spaceIdx=*/dofIdx, /*timeIdx=*/0);
824 
825 
826  // only update the jacobian matrix for non-green degrees of freedom
827  if (dofColor(globJ) == Green)
828  continue;
829 
830  (*matrix_)[globJ][globI] += localLinearizer.jacobian(dofIdx, primaryDofIdx);
831  }
832  }
833  addLock.unlock();
834  }
835 
836  // "linearize" a green element. green elements only get the
837  // residual updated, but the Jacobian is left alone...
838  void linearizeGreenElement_(const Element &elem)
839  {
840  int threadId = ThreadManager::threadId();
841  ElementContext *elementCtx = elementCtx_[threadId];
842 
843  elementCtx->updateAll(elem);
844  auto& localResidual = model_().localResidual(threadId);
845  localResidual.eval(*elementCtx);
846 
847  ScopedLock addLock(globalMatrixMutex_);
848  for (int dofIdx=0; dofIdx < elementCtx->numPrimaryDof(/*timeIdx=*/0); ++ dofIdx) {
849  int globI = elementCtx->globalSpaceIndex(dofIdx, /*timeIdx=*/0);
850 
851  // update the right hand side
852  for (int eqIdx = 0; eqIdx < numEq; ++ eqIdx)
853  residual_[globI][eqIdx] += Toolbox::value(localResidual.residual(dofIdx)[eqIdx]);
854  if (enableLinearizationRecycling_())
855  for (int eqIdx = 0; eqIdx < numEq; ++ eqIdx)
856  storageTerm_[globI][eqIdx] += Toolbox::value(localResidual.storageTerm(dofIdx)[eqIdx]);
857  }
858  addLock.unlock();
859  }
860 
861  void linearizeAuxiliaryEquations_()
862  {
863  auto& model = model_();
864  for (unsigned auxModIdx = 0; auxModIdx < model.numAuxiliaryModules(); ++auxModIdx)
865  model.auxiliaryModule(auxModIdx)->linearize(*matrix_, residual_);
866  }
867 
868  Simulator *simulatorPtr_;
869  std::vector<ElementContext*> elementCtx_;
870 
871  // the jacobian matrix
872  Matrix *matrix_;
873  // the right-hand side
874  GlobalEqVector residual_;
875 
876  // attributes required for jacobian matrix recycling
877  bool reuseLinearization_;
878  // The storage part of the local Jacobian
879  std::vector<MatrixBlock> storageJacobian_;
880  std::vector<VectorBlock> storageTerm_;
881  // time step size used for the last linearization
882  Scalar oldDt_;
883 
884  // data required for partial relinearization
885  std::vector<EntityColor> dofColor_;
886  std::vector<Scalar> dofError_;
887  std::vector<EntityColor> elementColor_;
888 
889  int numTotalElems_;
890  int numGreenElems_;
891 
892  Scalar relinearizationTolerance_;
893  Scalar relinearizationAccuracy_;
894  Scalar maxDofError_;
895 
896  OmpMutex globalMatrixMutex_;
897 };
898 
899 } // namespace Ewoms
900 
901 #endif
FvBaseLinearizer()
Definition: fvbaselinearizer.hh:127
void relinearizeAll()
If partial relinearization is enabled, this method causes all elements to be relinearized in the next...
Definition: fvbaselinearizer.hh:258
Scalar relinearizationTolerance() const
Returns the maximum error for which a degree of freedom is not relinearized.
Definition: fvbaselinearizer.hh:380
Problem & problem()
Return the object which specifies the pysical setup of the simulation.
Definition: simulator.hh:189
EntityColor dofColor(int dofIdx) const
Returns the "relinearization color" of a degree of freedom.
Definition: fvbaselinearizer.hh:360
Declare the properties used by the infrastructure code of the finite volume discretizations.
void linearize()
Linearize the global non-linear system of equations.
Definition: fvbaselinearizer.hh:195
#define GET_PROP_VALUE(TypeTag, PropTagName)
Access the value attribute of a property for a type tag.
Definition: propertysystem.hh:468
The common code for the linearizers of non-linear systems of equations.
Definition: fvbaselinearizer.hh:60
void init(Simulator &simulator)
Initialize the linearizer.
Definition: fvbaselinearizer.hh:170
const GlobalEqVector & residual() const
Return constant reference to global residual vector.
Definition: fvbaselinearizer.hh:404
void setLinearizationReusable(bool yesno=true)
If linearization recycling is enabled, this method specifies whether the next call to linearize() jus...
Definition: fvbaselinearizer.hh:248
Definition: fvbaselinearizer.hh:124
#define GET_PROP_TYPE(TypeTag, PropTagName)
Access the type attribute of a property for a type tag.
Definition: propertysystem.hh:485
This class implements an exception-safe scoped lock-keeper.
Definition: locks.hh:63
const Matrix & matrix() const
Return constant reference to global Jacobian matrix.
Definition: fvbaselinearizer.hh:398
Simplifies multi-threaded capabilities.
Definition: threadmanager.hh:48
void updateRelinearizationErrors(const GlobalEqVector &uDelta, const GlobalEqVector &resid)
Update the distance where the non-linear system was originally insistently linearized and the point w...
Definition: fvbaselinearizer.hh:312
void recreateMatrix()
Causes the Jacobian matrix to be recreated in the next iteration.
Definition: fvbaselinearizer.hh:180
Definition: fvbaselinearizer.hh:119
void setRelinearizationTolerance(Scalar tolerance)
Sets the maximum error for which a degree of freedom is not relinearized.
Definition: fvbaselinearizer.hh:386
void markDofRed(int dofIdx)
Ensure that a given degree of freedom is relinarized in the next iteration.
Definition: fvbaselinearizer.hh:350
Manages the initializing and running of time dependent problems.
Definition: simulator.hh:73
Scalar dofError(int dofIdx) const
Returns the error for a given degree of freedom after the last iteration.
Definition: fvbaselinearizer.hh:392
Definition: baseauxiliarymodule.hh:35
Scalar relinearizationAccuracy() const
Returns the largest error of a "green" degree of freedom for the most recent call of the linearize() ...
Definition: fvbaselinearizer.hh:293
EntityColor elementColor(int elemIdx) const
Returns the "relinearization color" of an element.
Definition: fvbaselinearizer.hh:370
Scalar maxDofError() const
The maximum deflection seen for any DOF after an Newton update.
Definition: fvbaselinearizer.hh:299
Provides data handles for parallel communication which operate on DOFs.
static int maxThreads()
Return the maximum number of threads of the current process.
Definition: threadmanager.hh:117
#define EWOMS_REGISTER_PARAM(TypeTag, ParamType, ParamName, Description)
Register a run-time parameter.
Definition: parametersystem.hh:64
static int threadId()
Return the index of the current OpenMP thread.
Definition: threadmanager.hh:123
EntityColor
The colors of elements and degrees of freedom required for partial relinearization.
Definition: fvbaselinearizer.hh:108
static void registerParameters()
Register all run-time parameters for the Jacobian linearizer.
Definition: fvbaselinearizer.hh:151
Model & model()
Return the physical model used in the simulation.
Definition: simulator.hh:176
~FvBaseLinearizer()
Definition: fvbaselinearizer.hh:139
Implements a shallow wrapper around the "raw" locks provided by OpenMP.
Definition: locks.hh:35
GridView & gridView()
Return the grid view for which the simulation is done.
Definition: simulator.hh:164
Definition: fvbaselinearizer.hh:113
Base class for specifying auxiliary equations.
Simplifies multi-threaded capabilities.
Provides an STL-iterator like interface to iterate over the enties of a GridView in OpenMP threaded a...
#define EWOMS_GET_PARAM(TypeTag, ParamType, ParamName)
Retrieve a runtime parameter.
Definition: parametersystem.hh:95