3.5-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
assembly/fvassembler.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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program 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 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
24#ifndef DUMUX_FV_ASSEMBLER_HH
25#define DUMUX_FV_ASSEMBLER_HH
26
27#include <vector>
28#include <deque>
29#include <type_traits>
30#include <memory>
31
32#include <dune/istl/matrixindexset.hh>
33
38
42
45
46#include "boxlocalassembler.hh"
47#include "cclocalassembler.hh"
48#include "fclocalassembler.hh"
49
50namespace Dumux::Detail {
51
52template<class DiscretizationMethod>
54
55template<>
56struct LocalAssemblerChooser<DiscretizationMethods::Box>
57{
58 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
60};
61
62template<>
63struct LocalAssemblerChooser<DiscretizationMethods::CCMpfa>
64{
65 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
67};
68
69template<>
70struct LocalAssemblerChooser<DiscretizationMethods::CCTpfa>
71{
72 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
74};
75
76template<>
77struct LocalAssemblerChooser<DiscretizationMethods::FCStaggered>
78{
79 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
81};
82
83template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
86>::template type<TypeTag, Impl, diffMethod, isImplicit>;
87
88} // end namespace Dumux::Detail
89
90namespace Dumux {
91
99template<class TypeTag, DiffMethod diffMethod, bool isImplicit = true>
101{
103 using GridView = typename GridGeo::GridView;
105 using Element = typename GridView::template Codim<0>::Entity;
106 using ElementSeed = typename GridView::Grid::template Codim<0>::EntitySeed;
109
110 static constexpr bool isBox = GridGeo::discMethod == DiscretizationMethods::box;
111
114
115public:
118 using GridGeometry = GridGeo;
121
122 using ResidualType = SolutionVector;
123
129 FVAssembler(std::shared_ptr<const Problem> problem,
130 std::shared_ptr<const GridGeometry> gridGeometry,
131 std::shared_ptr<GridVariables> gridVariables)
132 : problem_(problem)
133 , gridGeometry_(gridGeometry)
134 , gridVariables_(gridVariables)
135 , timeLoop_()
136 , isStationaryProblem_(true)
137 {
138 static_assert(isImplicit, "Explicit assembler for stationary problem doesn't make sense!");
141 && getParam<bool>("Assembly.Multithreading", true);
142
143 maybeComputeColors_();
144 }
145
151 FVAssembler(std::shared_ptr<const Problem> problem,
152 std::shared_ptr<const GridGeometry> gridGeometry,
153 std::shared_ptr<GridVariables> gridVariables,
154 std::shared_ptr<const TimeLoop> timeLoop,
155 const SolutionVector& prevSol)
156 : problem_(problem)
157 , gridGeometry_(gridGeometry)
158 , gridVariables_(gridVariables)
159 , timeLoop_(timeLoop)
160 , prevSol_(&prevSol)
161 , isStationaryProblem_(!timeLoop)
162 {
165 && getParam<bool>("Assembly.Multithreading", true);
166
167 maybeComputeColors_();
168 }
169
174 template<class PartialReassembler = DefaultPartialReassembler>
175 void assembleJacobianAndResidual(const SolutionVector& curSol, const PartialReassembler* partialReassembler = nullptr)
176 {
177 checkAssemblerState_();
178 resetJacobian_(partialReassembler);
179 resetResidual_();
180
181 assemble_([&](const Element& element)
182 {
183 LocalAssembler localAssembler(*this, element, curSol);
184 localAssembler.assembleJacobianAndResidual(*jacobian_, *residual_, *gridVariables_, partialReassembler);
185 });
186
187 enforcePeriodicConstraints_(*jacobian_, *residual_, curSol, *gridGeometry_);
188 }
189
193 void assembleJacobian(const SolutionVector& curSol)
194 {
195 checkAssemblerState_();
196 resetJacobian_();
197
198 assemble_([&](const Element& element)
199 {
200 LocalAssembler localAssembler(*this, element, curSol);
201 localAssembler.assembleJacobianAndResidual(*jacobian_, *gridVariables_);
202 });
203 }
204
206 void assembleResidual(const SolutionVector& curSol)
207 {
208 resetResidual_();
209 assembleResidual(*residual_, curSol);
210 }
211
213 void assembleResidual(ResidualType& r, const SolutionVector& curSol) const
214 {
215 checkAssemblerState_();
216
217 assemble_([&](const Element& element)
218 {
219 LocalAssembler localAssembler(*this, element, curSol);
220 localAssembler.assembleResidual(r);
221 });
222 }
223
225 Scalar residualNorm(const SolutionVector& curSol) const
226 {
228 assembleResidual(residual, curSol);
229
230 // issue a warning if the caluclation is used in parallel with overlap
231 static bool warningIssued = false;
232
233 if (gridView().comm().size() > 1 && gridView().overlapSize(0) == 0)
234 {
235 if constexpr (isBox)
236 {
237 using DM = typename GridGeometry::VertexMapper;
239
240 PVHelper vectorHelper(gridView(), gridGeometry_->vertexMapper());
241
242 vectorHelper.makeNonOverlappingConsistent(residual);
243 }
244 }
245 else if (!warningIssued)
246 {
247 if (gridView().comm().size() > 1 && gridView().comm().rank() == 0)
248 std::cout << "\nWarning: norm calculation adds entries corresponding to\n"
249 << "overlapping entities multiple times. Please use the norm\n"
250 << "function provided by a linear solver instead." << std::endl;
251
252 warningIssued = true;
253 }
254
255 // calculate the square norm of the residual
256 Scalar result2 = residual.two_norm2();
257 if (gridView().comm().size() > 1)
258 result2 = gridView().comm().sum(result2);
259
260 using std::sqrt;
261 return sqrt(result2);
262 }
263
269 void setLinearSystem(std::shared_ptr<JacobianMatrix> A,
270 std::shared_ptr<SolutionVector> r)
271 {
272 jacobian_ = A;
273 residual_ = r;
274
275 // check and/or set the BCRS matrix's build mode
276 if (jacobian_->buildMode() == JacobianMatrix::BuildMode::unknown)
277 jacobian_->setBuildMode(JacobianMatrix::random);
278 else if (jacobian_->buildMode() != JacobianMatrix::BuildMode::random)
279 DUNE_THROW(Dune::NotImplemented, "Only BCRS matrices with random build mode are supported at the moment");
280
281 setResidualSize_();
282 setJacobianPattern_();
283 }
284
290 {
291 jacobian_ = std::make_shared<JacobianMatrix>();
292 jacobian_->setBuildMode(JacobianMatrix::random);
293 residual_ = std::make_shared<SolutionVector>();
294
295 setResidualSize_();
296 setJacobianPattern_();
297 }
298
303 {
304 setResidualSize_();
305 setJacobianPattern_();
306 maybeComputeColors_();
307 }
308
312 [[deprecated("Use updateAfterGridAdaption. Will be removed after release 3.5.")]]
314 {
315 // resize the jacobian and the residual
316 const auto numDofs = this->numDofs();
317 jacobian_->setSize(numDofs, numDofs);
318
319 // create occupation pattern of the jacobian
320 const auto occupationPattern = getJacobianPattern<isImplicit>(gridGeometry());
321
322 // export pattern to jacobian
323 occupationPattern.exportIdx(*jacobian_);
324
325 // maybe recompute colors
326 maybeComputeColors_();
327 }
328
330 [[deprecated("Use updateAfterGridAdaption. Will be removed after release 3.5.")]]
332 { residual_->resize(numDofs()); }
333
335 std::size_t numDofs() const
336 { return gridGeometry_->numDofs(); }
337
339 const Problem& problem() const
340 { return *problem_; }
341
344 { return *gridGeometry_; }
345
347 const GridView& gridView() const
348 { return gridGeometry().gridView(); }
349
352 { return *gridVariables_; }
353
356 { return *gridVariables_; }
357
360 { return *jacobian_; }
361
363 SolutionVector& residual()
364 { return *residual_; }
365
367 const SolutionVector& prevSol() const
368 { return *prevSol_; }
369
374 void setTimeLoop(std::shared_ptr<const TimeLoop> timeLoop)
375 { timeLoop_ = timeLoop; isStationaryProblem_ = !static_cast<bool>(timeLoop); }
376
381 void setPreviousSolution(const SolutionVector& u)
382 { prevSol_ = &u; }
383
388 { return isStationaryProblem_; }
389
393 LocalResidual localResidual() const
394 { return LocalResidual(problem_.get(), timeLoop_.get()); }
395
399 void updateGridVariables(const SolutionVector &cursol)
400 {
401 gridVariables().update(cursol);
402 }
403
407 void resetTimeStep(const SolutionVector &cursol)
408 {
409 gridVariables().resetTimeStep(cursol);
410 }
411
412private:
416 void setJacobianPattern_()
417 {
418 // resize the jacobian and the residual
419 const auto numDofs = this->numDofs();
420 jacobian_->setSize(numDofs, numDofs);
421
422 // create occupation pattern of the jacobian
423 const auto occupationPattern = getJacobianPattern<isImplicit>(gridGeometry());
424
425 // export pattern to jacobian
426 occupationPattern.exportIdx(*jacobian_);
427 }
428
430 void setResidualSize_()
431 { residual_->resize(numDofs()); }
432
434 void maybeComputeColors_()
435 {
436 if (enableMultithreading_)
437 elementSets_ = computeColoring(gridGeometry()).sets;
438 }
439
440 // reset the residual vector to 0.0
441 void resetResidual_()
442 {
443 if(!residual_)
444 {
445 residual_ = std::make_shared<SolutionVector>();
446 setResidualSize_();
447 }
448
449 (*residual_) = 0.0;
450 }
451
452 // reset the Jacobian matrix to 0.0
453 template <class PartialReassembler = DefaultPartialReassembler>
454 void resetJacobian_(const PartialReassembler *partialReassembler = nullptr)
455 {
456 if(!jacobian_)
457 {
458 jacobian_ = std::make_shared<JacobianMatrix>();
459 jacobian_->setBuildMode(JacobianMatrix::random);
460 setJacobianPattern_();
461 }
462
463 if (partialReassembler)
464 partialReassembler->resetJacobian(*this);
465 else
466 *jacobian_ = 0.0;
467 }
468
469 // check if the assembler is in a correct state for assembly
470 void checkAssemblerState_() const
471 {
472 if (!isStationaryProblem_ && !prevSol_)
473 DUNE_THROW(Dune::InvalidStateException, "Assembling instationary problem but previous solution was not set!");
474 }
475
481 template<typename AssembleElementFunc>
482 void assemble_(AssembleElementFunc&& assembleElement) const
483 {
484 // a state that will be checked on all processes
485 bool succeeded = false;
486
487 // try assembling using the local assembly function
488 try
489 {
490 if (enableMultithreading_)
491 {
492 assert(elementSets_.size() > 0);
493
494 // make this element loop run in parallel
495 // for this we have to color the elements so that we don't get
496 // race conditions when writing into the global matrix
497 // each color can be assembled using multiple threads
498 for (const auto& elements : elementSets_)
499 {
500 Dumux::parallelFor(elements.size(), [&](const std::size_t i)
501 {
502 const auto element = gridView().grid().entity(elements[i]);
503 assembleElement(element);
504 });
505 }
506 }
507 else
508 for (const auto& element : elements(gridView()))
509 assembleElement(element);
510
511 // if we get here, everything worked well on this process
512 succeeded = true;
513 }
514 // throw exception if a problem ocurred
515 catch (NumericalProblem &e)
516 {
517 std::cout << "rank " << gridView().comm().rank()
518 << " caught an exception while assembling:" << e.what()
519 << "\n";
520 succeeded = false;
521 }
522
523 // make sure everything worked well on all processes
524 if (gridView().comm().size() > 1)
525 succeeded = gridView().comm().min(succeeded);
526
527 // if not succeeded rethrow the error on all processes
528 if (!succeeded)
529 DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system");
530 }
531
532 template<class GG> std::enable_if_t<GG::discMethod == DiscretizationMethods::box, void>
533 enforcePeriodicConstraints_(JacobianMatrix& jac, SolutionVector& res, const SolutionVector& curSol, const GG& gridGeometry)
534 {
535 for (const auto& m : gridGeometry.periodicVertexMap())
536 {
537 if (m.first < m.second)
538 {
539 // add the second row to the first
540 res[m.first] += res[m.second];
541 const auto end = jac[m.second].end();
542 for (auto it = jac[m.second].begin(); it != end; ++it)
543 jac[m.first][it.index()] += (*it);
544
545 // enforce constraint in second row
546 res[m.second] = curSol[m.second] - curSol[m.first];
547 for (auto it = jac[m.second].begin(); it != end; ++it)
548 (*it) = it.index() == m.second ? 1.0 : it.index() == m.first ? -1.0 : 0.0;
549 }
550 }
551 }
552
553 template<class GG> std::enable_if_t<GG::discMethod != DiscretizationMethods::box, void>
554 enforcePeriodicConstraints_(JacobianMatrix& jac, SolutionVector& res, const SolutionVector& curSol, const GG& gridGeometry) {}
555
557 std::shared_ptr<const Problem> problem_;
558
560 std::shared_ptr<const GridGeometry> gridGeometry_;
561
563 std::shared_ptr<GridVariables> gridVariables_;
564
566 std::shared_ptr<const TimeLoop> timeLoop_;
567
569 const SolutionVector* prevSol_ = nullptr;
570
572 bool isStationaryProblem_;
573
575 std::shared_ptr<JacobianMatrix> jacobian_;
576 std::shared_ptr<SolutionVector> residual_;
577
579 bool enableMultithreading_ = false;
580 std::deque<std::vector<ElementSeed>> elementSets_;
581};
582
583} // namespace Dumux
584
585#endif
An enum class to define various differentiation methods available in order to compute the derivatives...
An assembler for Jacobian and residual contribution per element (cell-centered methods)
An assembler for Jacobian and residual contribution per element (box method)
Coloring schemes for shared-memory-parallel assembly.
An assembler for Jacobian and residual contribution per element (face-centered staggered methods)
Helper function to generate Jacobian pattern for different discretization methods.
The available discretization methods in Dumux.
Provides a helper class for nonoverlapping decomposition.
Multithreading in Dumux.
Parallel for loop (multithreading)
constexpr bool isSerial()
Checking whether the backend is serial.
Definition: multithreading.hh:57
Definition: adapt.hh:29
auto computeColoring(const GridGeometry &gg, int verbosity=1)
Compute iterable lists of element seeds partitioned by color.
Definition: coloring.hh:192
void parallelFor(const std::size_t count, const FunctorType &functor)
Definition: parallel_for.hh:173
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
Distance implementation details.
Definition: fclocalassembler.hh:42
typename LocalAssemblerChooser< typename GetPropType< TypeTag, Properties::GridGeometry >::DiscretizationMethod >::template type< TypeTag, Impl, diffMethod, isImplicit > LocalAssemblerChooser_t
Definition: assembly/fvassembler.hh:86
constexpr Box box
Definition: method.hh:139
An assembler for Jacobian and residual contribution per element (box methods)
Definition: boxlocalassembler.hh:326
An assembler for Jacobian and residual contribution per element (cell-centered methods)
Definition: cclocalassembler.hh:136
Traits specifying if a given discretization tag supports coloring.
Definition: coloring.hh:245
An assembler for Jacobian and residual contribution per element (Face-centered methods)
Definition: fclocalassembler.hh:295
Definition: assembly/fvassembler.hh:53
A linear system assembler (residual and Jacobian) for finite volume schemes (box, tpfa,...
Definition: assembly/fvassembler.hh:101
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: assembly/fvassembler.hh:116
void assembleJacobian(const SolutionVector &curSol)
Assembles only the global Jacobian of the residual.
Definition: assembly/fvassembler.hh:193
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition: assembly/fvassembler.hh:302
const GridView & gridView() const
The gridview.
Definition: assembly/fvassembler.hh:347
const Problem & problem() const
The problem.
Definition: assembly/fvassembler.hh:339
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition: assembly/fvassembler.hh:289
SolutionVector ResidualType
Definition: assembly/fvassembler.hh:122
bool isStationaryProblem() const
Whether we are assembling a stationary or instationary problem.
Definition: assembly/fvassembler.hh:387
GetPropType< TypeTag, Properties::JacobianMatrix > JacobianMatrix
Definition: assembly/fvassembler.hh:117
LocalResidual localResidual() const
Create a local residual object (used by the local assembler)
Definition: assembly/fvassembler.hh:393
FVAssembler(std::shared_ptr< const Problem > problem, std::shared_ptr< const GridGeometry > gridGeometry, std::shared_ptr< GridVariables > gridVariables, std::shared_ptr< const TimeLoop > timeLoop, const SolutionVector &prevSol)
The constructor for instationary problems.
Definition: assembly/fvassembler.hh:151
Scalar residualNorm(const SolutionVector &curSol) const
compute the residual and return it's vector norm
Definition: assembly/fvassembler.hh:225
std::size_t numDofs() const
Returns the number of degrees of freedom.
Definition: assembly/fvassembler.hh:335
GridVariables & gridVariables()
The global grid variables.
Definition: assembly/fvassembler.hh:351
JacobianMatrix & jacobian()
The jacobian matrix.
Definition: assembly/fvassembler.hh:359
void assembleResidual(ResidualType &r, const SolutionVector &curSol) const
assemble a residual r
Definition: assembly/fvassembler.hh:213
GetPropType< TypeTag, Properties::Problem > Problem
Definition: assembly/fvassembler.hh:119
void setTimeLoop(std::shared_ptr< const TimeLoop > timeLoop)
Set time loop for instationary problems.
Definition: assembly/fvassembler.hh:374
void setResidualSize()
Resizes the residual.
Definition: assembly/fvassembler.hh:331
void assembleResidual(const SolutionVector &curSol)
compute the residuals using the internal residual
Definition: assembly/fvassembler.hh:206
GetPropType< TypeTag, Properties::GridVariables > GridVariables
Definition: assembly/fvassembler.hh:120
void setJacobianPattern()
Resizes the jacobian and sets the jacobian' sparsity pattern.
Definition: assembly/fvassembler.hh:313
void setPreviousSolution(const SolutionVector &u)
Sets the solution from which to start the time integration. Has to be called prior to assembly for ti...
Definition: assembly/fvassembler.hh:381
const GridGeometry & gridGeometry() const
The global finite volume geometry.
Definition: assembly/fvassembler.hh:343
void resetTimeStep(const SolutionVector &cursol)
Reset the gridVariables.
Definition: assembly/fvassembler.hh:407
const GridVariables & gridVariables() const
The global grid variables.
Definition: assembly/fvassembler.hh:355
void setLinearSystem(std::shared_ptr< JacobianMatrix > A, std::shared_ptr< SolutionVector > r)
Tells the assembler which jacobian and residual to use. This also resizes the containers to the requi...
Definition: assembly/fvassembler.hh:269
void assembleJacobianAndResidual(const SolutionVector &curSol, const PartialReassembler *partialReassembler=nullptr)
Assembles the global Jacobian of the residual and the residual for the current solution.
Definition: assembly/fvassembler.hh:175
GridGeo GridGeometry
Definition: assembly/fvassembler.hh:118
FVAssembler(std::shared_ptr< const Problem > problem, std::shared_ptr< const GridGeometry > gridGeometry, std::shared_ptr< GridVariables > gridVariables)
The constructor for stationary problems.
Definition: assembly/fvassembler.hh:129
SolutionVector & residual()
The residual vector (rhs)
Definition: assembly/fvassembler.hh:363
const SolutionVector & prevSol() const
The solution of the previous time step.
Definition: assembly/fvassembler.hh:367
void updateGridVariables(const SolutionVector &cursol)
Update the grid variables.
Definition: assembly/fvassembler.hh:399
detects which entries in the Jacobian have to be recomputed
Definition: partialreassembler.hh:432
Manages the handling of time dependent problems.
Definition: common/timeloop.hh:69
Definition: parallelhelpers.hh:430
Declares all properties used in Dumux.
Manages the handling of time dependent problems.