version 3.11-dev
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// SPDX-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12#ifndef DUMUX_FV_ASSEMBLER_HH
13#define DUMUX_FV_ASSEMBLER_HH
14
15#include <vector>
16#include <deque>
17#include <type_traits>
18#include <memory>
19
20#include <dune/istl/matrixindexset.hh>
21
27
31
35
38
39#include "cvfelocalassembler.hh"
40#include "cclocalassembler.hh"
41#include "fclocalassembler.hh"
42
43namespace Dumux::Detail {
44
45template<class DiscretizationMethod>
47
48template<class DM>
49struct LocalAssemblerChooser<DiscretizationMethods::CVFE<DM>>
50{
51 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
53};
54
55template<>
56struct LocalAssemblerChooser<DiscretizationMethods::CCMpfa>
57{
58 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
60};
61
62template<>
63struct LocalAssemblerChooser<DiscretizationMethods::CCTpfa>
64{
65 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
67};
68
69template<>
70struct LocalAssemblerChooser<DiscretizationMethods::FCStaggered>
71{
72 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
74};
75
76template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
79>::template type<TypeTag, Impl, diffMethod, isImplicit>;
80
82template<class P>
83using ProblemConstraintsDetector = decltype(std::declval<P>().constraints());
84
85template<class P>
86constexpr inline bool hasGlobalConstraints()
87{ return Dune::Std::is_detected<ProblemConstraintsDetector, P>::value; }
88
89} // end namespace Dumux::Detail
90
91namespace Dumux {
92
101template<class TypeTag, DiffMethod diffMethod, bool isImplicit = true, class LocalResidual = GetPropType<TypeTag, Properties::LocalResidual>>
103{
105 using GridView = typename GridGeo::GridView;
106 using Element = typename GridView::template Codim<0>::Entity;
107 using ElementSeed = typename GridView::Grid::template Codim<0>::EntitySeed;
109
110 static constexpr bool isBox = GridGeo::discMethod == DiscretizationMethods::box;
111
114
115public:
120
122
123 using GridGeometry = GridGeo;
125
131 FVAssembler(std::shared_ptr<const Problem> problem,
132 std::shared_ptr<const GridGeometry> gridGeometry,
133 std::shared_ptr<GridVariables> gridVariables)
134 : problem_(problem)
135 , gridGeometry_(gridGeometry)
136 , gridVariables_(gridVariables)
137 , timeLoop_()
138 , isStationaryProblem_(true)
139 {
140 static_assert(isImplicit, "Explicit assembler for stationary problem doesn't make sense!");
142 && Grid::Capabilities::supportsMultithreading(gridGeometry_->gridView())
144 && getParam<bool>("Assembly.Multithreading", true);
145
146 maybeComputeColors_();
147 }
148
154 FVAssembler(std::shared_ptr<const Problem> problem,
155 std::shared_ptr<const GridGeometry> gridGeometry,
156 std::shared_ptr<GridVariables> gridVariables,
157 std::shared_ptr<const TimeLoop> timeLoop,
158 const SolutionVector& prevSol)
159 : problem_(problem)
160 , gridGeometry_(gridGeometry)
161 , gridVariables_(gridVariables)
162 , timeLoop_(timeLoop)
163 , prevSol_(&prevSol)
164 , isStationaryProblem_(!timeLoop)
165 {
167 && Grid::Capabilities::supportsMultithreading(gridGeometry_->gridView())
169 && getParam<bool>("Assembly.Multithreading", true);
170
171 maybeComputeColors_();
172 }
173
178 template<class PartialReassembler = DefaultPartialReassembler>
179 void assembleJacobianAndResidual(const SolutionVector& curSol, const PartialReassembler* partialReassembler = nullptr)
180 {
181 checkAssemblerState_();
182 resetJacobian_(partialReassembler);
183 resetResidual_();
184
185 assemble_([&](const Element& element)
186 {
187 LocalAssembler localAssembler(*this, element, curSol);
188 localAssembler.assembleJacobianAndResidual(*jacobian_, *residual_, *gridVariables_, partialReassembler);
189 });
190
191 enforcePeriodicConstraints_(*jacobian_, *residual_, curSol, *gridGeometry_);
192
193 auto applyDirichletConstraint = [&] (const auto& dofIdx,
194 const auto& values,
195 const auto eqIdx,
196 const auto pvIdx)
197 {
198 (*residual_)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
199
200 auto& row = (*jacobian_)[dofIdx];
201 for (auto col = row.begin(); col != row.end(); ++col)
202 row[col.index()][eqIdx] = 0.0;
203
204 (*jacobian_)[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
205 };
206 enforceGlobalDirichletConstraints_(*problem_, *gridGeometry_, applyDirichletConstraint);
207 }
208
213 {
214 checkAssemblerState_();
215 resetJacobian_();
216
217 assemble_([&](const Element& element)
218 {
219 LocalAssembler localAssembler(*this, element, curSol);
220 localAssembler.assembleJacobian(*jacobian_, *gridVariables_);
221 });
222
223 auto applyDirichletConstraint = [&] (const auto& dofIdx,
224 const auto& values,
225 const auto eqIdx,
226 const auto pvIdx)
227 {
228 auto& row = (*jacobian_)[dofIdx];
229 for (auto col = row.begin(); col != row.end(); ++col)
230 row[col.index()][eqIdx] = 0.0;
231
232 (*jacobian_)[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
233 };
234 enforceGlobalDirichletConstraints_(*problem_, *gridGeometry_, applyDirichletConstraint);
235 }
236
239 {
240 resetResidual_();
241 assembleResidual(*residual_, curSol);
242
243 auto applyDirichletConstraint = [&] (const auto& dofIdx,
244 const auto& values,
245 const auto eqIdx,
246 const auto pvIdx)
247 {
248 (*residual_)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
249 };
250 enforceGlobalDirichletConstraints_(*problem_, *gridGeometry_, applyDirichletConstraint);
251 }
252
254 void assembleResidual(ResidualType& r, const SolutionVector& curSol) const
255 {
256 checkAssemblerState_();
257
258 assemble_([&](const Element& element)
259 {
260 LocalAssembler localAssembler(*this, element, curSol);
261 localAssembler.assembleResidual(r);
262 });
263 }
264
270 void setLinearSystem(std::shared_ptr<JacobianMatrix> A,
271 std::shared_ptr<ResidualType> r)
272 {
273 jacobian_ = A;
274 residual_ = r;
275
276 // check and/or set the BCRS matrix's build mode
277 if (jacobian_->buildMode() == JacobianMatrix::BuildMode::unknown)
278 jacobian_->setBuildMode(JacobianMatrix::random);
279 else if (jacobian_->buildMode() != JacobianMatrix::BuildMode::random)
280 DUNE_THROW(Dune::NotImplemented, "Only BCRS matrices with random build mode are supported at the moment");
281
282 setResidualSize_();
283 setJacobianPattern_();
284 }
285
291 {
292 jacobian_ = std::make_shared<JacobianMatrix>();
293 jacobian_->setBuildMode(JacobianMatrix::random);
294 residual_ = std::make_shared<ResidualType>();
295
296 setResidualSize_();
297 setJacobianPattern_();
298 }
299
304 {
305 setResidualSize_();
306 setJacobianPattern_();
307 maybeComputeColors_();
308 }
309
311 std::size_t numDofs() const
312 { return gridGeometry_->numDofs(); }
313
315 const Problem& problem() const
316 { return *problem_; }
317
320 { return *gridGeometry_; }
321
323 const GridView& gridView() const
324 { return gridGeometry().gridView(); }
325
328 { return *gridVariables_; }
329
332 { return *gridVariables_; }
333
336 { return *jacobian_; }
337
340 { return *residual_; }
341
343 const SolutionVector& prevSol() const
344 { return *prevSol_; }
345
350 void setTimeLoop(std::shared_ptr<const TimeLoop> timeLoop)
351 { timeLoop_ = timeLoop; isStationaryProblem_ = !static_cast<bool>(timeLoop); }
352
358 { prevSol_ = &u; }
359
364 { return isStationaryProblem_; }
365
369 LocalResidual localResidual() const
370 { return LocalResidual(problem_.get(), timeLoop_.get()); }
371
376 {
377 gridVariables().update(cursol);
378 }
379
383 void resetTimeStep(const SolutionVector &cursol)
384 {
385 gridVariables().resetTimeStep(cursol);
386 }
387
388private:
392 void setJacobianPattern_()
393 {
394 // resize the jacobian and the residual
395 const auto numDofs = this->numDofs();
396 jacobian_->setSize(numDofs, numDofs);
397
398 // create occupation pattern of the jacobian
399 const auto occupationPattern = getJacobianPattern<isImplicit>(gridGeometry());
400
401 // export pattern to jacobian
402 occupationPattern.exportIdx(*jacobian_);
403 }
404
406 void setResidualSize_()
407 { residual_->resize(numDofs()); }
408
410 void maybeComputeColors_()
411 {
412 if (enableMultithreading_)
413 elementSets_ = computeColoring(gridGeometry()).sets;
414 }
415
416 // reset the residual vector to 0.0
417 void resetResidual_()
418 {
419 if(!residual_)
420 {
421 residual_ = std::make_shared<ResidualType>();
422 setResidualSize_();
423 }
424
425 (*residual_) = 0.0;
426 }
427
428 // reset the Jacobian matrix to 0.0
429 template <class PartialReassembler = DefaultPartialReassembler>
430 void resetJacobian_(const PartialReassembler *partialReassembler = nullptr)
431 {
432 if(!jacobian_)
433 {
434 jacobian_ = std::make_shared<JacobianMatrix>();
435 jacobian_->setBuildMode(JacobianMatrix::random);
436 setJacobianPattern_();
437 }
438
439 if (partialReassembler)
440 partialReassembler->resetJacobian(*this);
441 else
442 *jacobian_ = 0.0;
443 }
444
445 // check if the assembler is in a correct state for assembly
446 void checkAssemblerState_() const
447 {
448 if (!isStationaryProblem_ && !prevSol_)
449 DUNE_THROW(Dune::InvalidStateException, "Assembling instationary problem but previous solution was not set!");
450 }
451
457 template<typename AssembleElementFunc>
458 void assemble_(AssembleElementFunc&& assembleElement) const
459 {
460 // a state that will be checked on all processes
461 bool succeeded = false;
462
463 // try assembling using the local assembly function
464 try
465 {
466 if (enableMultithreading_)
467 {
468 assert(elementSets_.size() > 0);
469
470 // make this element loop run in parallel
471 // for this we have to color the elements so that we don't get
472 // race conditions when writing into the global matrix
473 // each color can be assembled using multiple threads
474 for (const auto& elements : elementSets_)
475 {
476 Dumux::parallelFor(elements.size(), [&](const std::size_t i)
477 {
478 const auto element = gridView().grid().entity(elements[i]);
479 assembleElement(element);
480 });
481 }
482 }
483 else
484 for (const auto& element : elements(gridView()))
485 assembleElement(element);
486
487 // if we get here, everything worked well on this process
488 succeeded = true;
489 }
490 // throw exception if a problem occurred
491 catch (NumericalProblem &e)
492 {
493 std::cout << "rank " << gridView().comm().rank()
494 << " caught an exception while assembling:" << e.what()
495 << "\n";
496 succeeded = false;
497 }
498
499 // make sure everything worked well on all processes
500 if (gridView().comm().size() > 1)
501 succeeded = gridView().comm().min(succeeded);
502
503 // if not succeeded rethrow the error on all processes
504 if (!succeeded)
505 DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system");
506 }
507
508 template<class GG>
509 void enforcePeriodicConstraints_(JacobianMatrix& jac, ResidualType& res, const SolutionVector& curSol, const GG& gridGeometry)
510 {
511 if constexpr (Detail::hasPeriodicDofMap<GG>())
512 {
513 for (const auto& m : gridGeometry.periodicDofMap())
514 {
515 if (m.first < m.second)
516 {
517 // add the second row to the first
518 res[m.first] += res[m.second];
519 const auto end = jac[m.second].end();
520 for (auto it = jac[m.second].begin(); it != end; ++it)
521 jac[m.first][it.index()] += (*it);
522
523 // enforce constraint in second row
524 res[m.second] = curSol[m.second] - curSol[m.first];
525
526 // set derivatives accordingly in jacobian, i.e. id for m.second and -id for m.first
527 auto setMatrixBlock = [] (auto& matrixBlock, double diagValue)
528 {
529 for (int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
530 matrixBlock[eIdx][eIdx] = diagValue;
531 };
532
533 for (auto it = jac[m.second].begin(); it != end; ++it)
534 {
535 auto& matrixBlock = *it;
536 matrixBlock = 0.0;
537
538 assert(matrixBlock.N() == matrixBlock.M());
539 if(it.index() == m.second)
540 setMatrixBlock(matrixBlock, 1.0);
541
542 if(it.index() == m.first)
543 setMatrixBlock(matrixBlock, -1.0);
544
545 }
546 }
547 }
548 }
549 }
550
551 template<class Problem, class GG, typename ApplyFunction>
552 void enforceGlobalDirichletConstraints_(const Problem& problem, const GG& gridGeometry, const ApplyFunction& applyDirichletConstraint)
553 {
554 if constexpr (Detail::hasGlobalConstraints<Problem>())
555 {
556 for (const auto& constraintData : problem.constraints())
557 {
558 const auto& constraintInfo = constraintData.constraintInfo();
559 const auto& values = constraintData.values();
560 const auto dofIdx = constraintData.dofIndex();
561 // set the constraint in residual and jacobian
562 for (int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
563 {
564 if (constraintInfo.isConstraintEquation(eqIdx))
565 {
566 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
567 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
568 applyDirichletConstraint(dofIdx, values, eqIdx, pvIdx);
569 }
570 }
571 }
572 }
573 }
574
576 std::shared_ptr<const Problem> problem_;
577
579 std::shared_ptr<const GridGeometry> gridGeometry_;
580
582 std::shared_ptr<GridVariables> gridVariables_;
583
585 std::shared_ptr<const TimeLoop> timeLoop_;
586
588 const SolutionVector* prevSol_ = nullptr;
589
591 bool isStationaryProblem_;
592
594 std::shared_ptr<JacobianMatrix> jacobian_;
595 std::shared_ptr<ResidualType> residual_;
596
598 bool enableMultithreading_ = false;
599 std::deque<std::vector<ElementSeed>> elementSets_;
600};
601
602} // namespace Dumux
603
604#endif
An assembler for Jacobian and residual contribution per element (cell-centered methods)
Definition: assembly/cclocalassembler.hh:124
An assembler for Jacobian and residual contribution per element (CVFE methods)
Definition: assembly/cvfelocalassembler.hh:317
A linear system assembler (residual and Jacobian) for finite volume schemes (box, tpfa,...
Definition: assembly/fvassembler.hh:103
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:357
GridGeo GridGeometry
Definition: assembly/fvassembler.hh:123
GetPropType< TypeTag, Properties::GridVariables > GridVariables
Definition: assembly/fvassembler.hh:121
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:154
GridVariables & gridVariables()
The global grid variables.
Definition: assembly/fvassembler.hh:327
std::size_t numDofs() const
Returns the number of degrees of freedom.
Definition: assembly/fvassembler.hh:311
const GridVariables & gridVariables() const
The global grid variables.
Definition: assembly/fvassembler.hh:331
LocalResidual localResidual() const
Create a local residual object (used by the local assembler)
Definition: assembly/fvassembler.hh:369
GetPropType< TypeTag, Properties::SolutionVector > SolutionVector
Definition: assembly/fvassembler.hh:118
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:179
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition: assembly/fvassembler.hh:303
const Problem & problem() const
The problem.
Definition: assembly/fvassembler.hh:315
bool isStationaryProblem() const
Whether we are assembling a stationary or instationary problem.
Definition: assembly/fvassembler.hh:363
const GridGeometry & gridGeometry() const
The global finite volume geometry.
Definition: assembly/fvassembler.hh:319
void assembleResidual(ResidualType &r, const SolutionVector &curSol) const
assemble a residual r
Definition: assembly/fvassembler.hh:254
typename Detail::NativeDuneVectorType< SolutionVector >::type ResidualType
Definition: assembly/fvassembler.hh:119
void setTimeLoop(std::shared_ptr< const TimeLoop > timeLoop)
Set time loop for instationary problems.
Definition: assembly/fvassembler.hh:350
void resetTimeStep(const SolutionVector &cursol)
Reset the gridVariables.
Definition: assembly/fvassembler.hh:383
void assembleJacobian(const SolutionVector &curSol)
Assembles only the global Jacobian of the residual.
Definition: assembly/fvassembler.hh:212
void updateGridVariables(const SolutionVector &cursol)
Update the grid variables.
Definition: assembly/fvassembler.hh:375
JacobianMatrix & jacobian()
The jacobian matrix.
Definition: assembly/fvassembler.hh:335
void setLinearSystem(std::shared_ptr< JacobianMatrix > A, std::shared_ptr< ResidualType > r)
Tells the assembler which jacobian and residual to use. This also resizes the containers to the requi...
Definition: assembly/fvassembler.hh:270
GetPropType< TypeTag, Properties::JacobianMatrix > JacobianMatrix
Definition: assembly/fvassembler.hh:117
GetPropType< TypeTag, Properties::Problem > Problem
Definition: assembly/fvassembler.hh:124
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition: assembly/fvassembler.hh:290
const SolutionVector & prevSol() const
The solution of the previous time step.
Definition: assembly/fvassembler.hh:343
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:131
const GridView & gridView() const
The gridview.
Definition: assembly/fvassembler.hh:323
ResidualType & residual()
The residual vector (rhs)
Definition: assembly/fvassembler.hh:339
void assembleResidual(const SolutionVector &curSol)
compute the residuals using the internal residual
Definition: assembly/fvassembler.hh:238
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: assembly/fvassembler.hh:116
An assembler for Jacobian and residual contribution per element (Face-centered methods)
Definition: fclocalassembler.hh:288
detects which entries in the Jacobian have to be recomputed
Definition: partialreassembler.hh:420
Manages the handling of time dependent problems.
Definition: common/timeloop.hh:84
Coloring schemes for shared-memory-parallel assembly.
Defines all properties used in Dumux.
Manages the handling of time dependent problems.
An enum class to define various differentiation methods available in order to compute the derivatives...
Helper to extract native Dune vector types from particular Dumux types.
An assembler for Jacobian and residual contribution per element (cell-centered methods)
An assembler for Jacobian and residual contribution per element (CVFE methods)
An assembler for Jacobian and residual contribution per element (face-centered staggered methods)
dune-grid capabilities compatibility layer
constexpr bool isSerial()
Checking whether the backend is serial.
Definition: multithreading.hh:45
void parallelFor(const std::size_t count, const FunctorType &functor)
A parallel for loop (multithreading)
Definition: parallel_for.hh:160
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:296
Helper function to generate Jacobian pattern for different discretization methods.
The available discretization methods in Dumux.
Multithreading in Dumux.
Definition: cvfelocalresidual.hh:28
constexpr bool hasGlobalConstraints()
Definition: assembly/fvassembler.hh:86
decltype(std::declval< P >().constraints()) ProblemConstraintsDetector
helper struct detecting if problem has a constraints() function
Definition: assembly/fvassembler.hh:83
typename LocalAssemblerChooser< typename GetPropType< TypeTag, Properties::GridGeometry >::DiscretizationMethod >::template type< TypeTag, Impl, diffMethod, isImplicit > LocalAssemblerChooser_t
Definition: assembly/fvassembler.hh:79
constexpr Box box
Definition: method.hh:147
bool supportsMultithreading(const GridView &gridView)
Definition: gridcapabilities.hh:34
Definition: adapt.hh:17
auto computeColoring(const GridGeometry &gg, int verbosity=1)
Compute iterable lists of element seeds partitioned by color.
Definition: coloring.hh:239
Parallel for loop (multithreading)
Provides a helper class for nonoverlapping decomposition.
Type traits to detect periodicity support.
Definition: assembly/fvassembler.hh:46
typename NativeDuneVectorTypeImpl< V, Dune::Std::is_detected< Detail::DuneVectors::StateDetector, V >{} >::type type
Definition: dunevectors.hh:59
Traits specifying if a given discretization tag supports coloring.
Definition: coloring.hh:292
Type traits to be used with vector types.