version 3.11-dev
Loading...
Searching...
No Matches
assembly/assembler.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_ASSEMBLER_HH
13#define DUMUX_ASSEMBLER_HH
14
15#include <cassert>
16#include <iostream>
17#include <vector>
18#include <deque>
19#include <memory>
20#include <utility>
21
22#include <dune/common/std/type_traits.hh>
23#include <dune/grid/common/rangegenerators.hh>
24
31
34
38
41
42#include "cvfelocalassembler_.hh"
43
45
46template<class DiscretizationMethod>
48
49template<class DM>
51{
52 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
54};
55
56template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
59>::template type<TypeTag, Impl, diffMethod, isImplicit>;
60
62template<class P>
63using ProblemConstraintsDetector = decltype(std::declval<P>().constraints());
64
65template<class P>
66constexpr inline bool hasGlobalConstraints()
67{ return Dune::Std::is_detected<ProblemConstraintsDetector, P>::value; }
68
69} // end namespace Dumux::Experimental::Detail
70
71namespace Dumux::Experimental {
72
81template<class TypeTag, DiffMethod diffMethod, bool isImplicit = true, class LocalResidual = GetPropType<TypeTag, Properties::LocalResidual>>
83{
85 using GridView = typename GridGeo::GridView;
86 using Element = typename GridView::template Codim<0>::Entity;
87 using ElementSeed = typename GridView::Grid::template Codim<0>::EntitySeed;
89
92
93public:
98
100
101 using GridGeometry = GridGeo;
103
109 Assembler(std::shared_ptr<const Problem> problem,
110 std::shared_ptr<const GridGeometry> gridGeometry,
111 std::shared_ptr<GridVariables> gridVariables)
112 : problem_(problem)
113 , gridGeometry_(gridGeometry)
114 , gridVariables_(gridVariables)
115 , timeLoop_()
116 , isStationaryProblem_(true)
117 {
118 static_assert(isImplicit, "Explicit assembler for stationary problem doesn't make sense!");
120 && Grid::Capabilities::supportsMultithreading(gridGeometry_->gridView())
122 && getParam<bool>("Assembly.Multithreading", true);
123
124 maybeComputeColors_();
125 }
126
132 Assembler(std::shared_ptr<const Problem> problem,
133 std::shared_ptr<const GridGeometry> gridGeometry,
134 std::shared_ptr<GridVariables> gridVariables,
135 std::shared_ptr<const TimeLoop> timeLoop,
136 const SolutionVector& prevSol)
137 : problem_(problem)
138 , gridGeometry_(gridGeometry)
139 , gridVariables_(gridVariables)
140 , timeLoop_(timeLoop)
141 , prevSol_(&prevSol)
142 , isStationaryProblem_(!timeLoop)
143 {
145 && Grid::Capabilities::supportsMultithreading(gridGeometry_->gridView())
147 && getParam<bool>("Assembly.Multithreading", true);
148
149 maybeComputeColors_();
150 }
151
156 template<class PartialReassembler = DefaultPartialReassembler>
157 void assembleJacobianAndResidual(const SolutionVector& curSol, const PartialReassembler* partialReassembler = nullptr)
158 {
159 checkAssemblerState_();
160 resetJacobian_(partialReassembler);
161 resetResidual_();
162
163 assemble_([&](const Element& element)
164 {
165 LocalAssembler localAssembler(*this, element, curSol);
166 localAssembler.assembleJacobianAndResidual(*jacobian_, *residual_, *gridVariables_, partialReassembler);
167 });
168
169 enforcePeriodicConstraints_(*jacobian_, *residual_, curSol, *gridGeometry_);
170
171 auto applyDirichletConstraint = [&] (const auto& dofIdx,
172 const auto& values,
173 const auto eqIdx,
174 const auto pvIdx)
175 {
176 (*residual_)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
177
178 auto& row = (*jacobian_)[dofIdx];
179 for (auto col = row.begin(); col != row.end(); ++col)
180 row[col.index()][eqIdx] = 0.0;
181
182 (*jacobian_)[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
183 };
184 enforceProblemConstraints_(*problem_, *gridGeometry_, applyDirichletConstraint);
185 }
186
191 {
192 checkAssemblerState_();
193 resetJacobian_();
194
195 assemble_([&](const Element& element)
196 {
197 LocalAssembler localAssembler(*this, element, curSol);
198 localAssembler.assembleJacobian(*jacobian_, *gridVariables_);
199 });
200
201 enforcePeriodicConstraints_(*jacobian_, curSol, *gridGeometry_);
202
203 auto applyDirichletConstraint = [&] (const auto& dofIdx,
204 const auto& values,
205 const auto eqIdx,
206 const auto pvIdx)
207 {
208 auto& row = (*jacobian_)[dofIdx];
209 for (auto col = row.begin(); col != row.end(); ++col)
210 row[col.index()][eqIdx] = 0.0;
211
212 (*jacobian_)[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
213 };
214 enforceProblemConstraints_(*problem_, *gridGeometry_, applyDirichletConstraint);
215 }
216
219 {
220 resetResidual_();
221 assembleResidual(*residual_, curSol);
222 }
223
225 void assembleResidual(ResidualType& r, const SolutionVector& curSol) const
226 {
227 checkAssemblerState_();
228
229 assemble_([&](const Element& element)
230 {
231 LocalAssembler localAssembler(*this, element, curSol);
232 localAssembler.assembleResidual(r);
233 });
234
235 enforcePeriodicConstraints_(r, curSol, *gridGeometry_);
236
237 auto applyDirichletConstraint = [&] (const auto& dofIdx,
238 const auto& values,
239 const auto eqIdx,
240 const auto pvIdx)
241 {
242 r[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
243 };
244 enforceProblemConstraints_(*problem_, *gridGeometry_, applyDirichletConstraint);
245 }
246
252 void setLinearSystem(std::shared_ptr<JacobianMatrix> A,
253 std::shared_ptr<ResidualType> r)
254 {
255 jacobian_ = A;
256 residual_ = r;
257
258 // check and/or set the BCRS matrix's build mode
259 if (jacobian_->buildMode() == JacobianMatrix::BuildMode::unknown)
260 jacobian_->setBuildMode(JacobianMatrix::random);
261 else if (jacobian_->buildMode() != JacobianMatrix::BuildMode::random)
262 DUNE_THROW(Dune::NotImplemented, "Only BCRS matrices with random build mode are supported at the moment");
263
264 setResidualSize_();
265 setJacobianPattern_();
266 }
267
273 {
274 jacobian_ = std::make_shared<JacobianMatrix>();
275 jacobian_->setBuildMode(JacobianMatrix::random);
276 residual_ = std::make_shared<ResidualType>();
277
278 setResidualSize_();
279 setJacobianPattern_();
280 }
281
286 {
287 setResidualSize_();
288 setJacobianPattern_();
289 maybeComputeColors_();
290 }
291
293 std::size_t numDofs() const
294 { return gridGeometry_->numDofs(); }
295
297 const Problem& problem() const
298 { return *problem_; }
299
302 { return *gridGeometry_; }
303
305 const GridView& gridView() const
306 { return gridGeometry().gridView(); }
307
310 { return *gridVariables_; }
311
314 { return *gridVariables_; }
315
318 { return *jacobian_; }
319
322 { return *residual_; }
323
325 const SolutionVector& prevSol() const
326 { return *prevSol_; }
327
332 void setTimeLoop(std::shared_ptr<const TimeLoop> timeLoop)
333 { timeLoop_ = timeLoop; isStationaryProblem_ = !static_cast<bool>(timeLoop); }
334
340 { prevSol_ = &u; }
341
346 { return isStationaryProblem_; }
347
352 { return LocalResidual(problem_.get(), timeLoop_.get()); }
353
358 {
359 gridVariables().update(curSol);
360 }
361
365 void resetTimeStep(const SolutionVector& curSol)
366 {
367 gridVariables().resetTimeStep(curSol);
368 }
369
370private:
374 void setJacobianPattern_()
375 {
376 // resize the jacobian and the residual
377 const auto numDofs = this->numDofs();
378 jacobian_->setSize(numDofs, numDofs);
379
380 // create occupation pattern of the jacobian
381 const auto occupationPattern = getJacobianPattern<isImplicit>(gridGeometry());
382
383 // export pattern to jacobian
384 occupationPattern.exportIdx(*jacobian_);
385 }
386
388 void setResidualSize_()
389 { residual_->resize(numDofs()); }
390
392 void maybeComputeColors_()
393 {
394 if (enableMultithreading_)
395 elementSets_ = computeColoring(gridGeometry()).sets;
396 }
397
398 // reset the residual vector to 0.0
399 void resetResidual_()
400 {
401 if(!residual_)
402 {
403 residual_ = std::make_shared<ResidualType>();
404 setResidualSize_();
405 }
406
407 (*residual_) = 0.0;
408 }
409
410 // reset the Jacobian matrix to 0.0
411 template <class PartialReassembler = DefaultPartialReassembler>
412 void resetJacobian_(const PartialReassembler *partialReassembler = nullptr)
413 {
414 if(!jacobian_)
415 {
416 jacobian_ = std::make_shared<JacobianMatrix>();
417 jacobian_->setBuildMode(JacobianMatrix::random);
418 setJacobianPattern_();
419 }
420
421 if (partialReassembler)
422 partialReassembler->resetJacobian(*this);
423 else
424 *jacobian_ = 0.0;
425 }
426
427 // check if the assembler is in a correct state for assembly
428 void checkAssemblerState_() const
429 {
430 if (!isStationaryProblem_ && !prevSol_)
431 DUNE_THROW(Dune::InvalidStateException, "Assembling instationary problem but previous solution was not set!");
432 }
433
439 template<typename AssembleElementFunc>
440 void assemble_(AssembleElementFunc&& assembleElement) const
441 {
442 // a state that will be checked on all processes
443 bool succeeded = false;
444
445 // try assembling using the local assembly function
446 try
447 {
448 if (enableMultithreading_)
449 {
450 assert(elementSets_.size() > 0);
451
452 // make this element loop run in parallel
453 // for this we have to color the elements so that we don't get
454 // race conditions when writing into the global matrix
455 // each color can be assembled using multiple threads
456 for (const auto& elements : elementSets_)
457 {
458 Dumux::parallelFor(elements.size(), [&](const std::size_t i)
459 {
460 const auto element = gridView().grid().entity(elements[i]);
461 assembleElement(element);
462 });
463 }
464 }
465 else
466 for (const auto& element : elements(gridView()))
467 assembleElement(element);
468
469 // if we get here, everything worked well on this process
470 succeeded = true;
471 }
472 // throw exception if a problem occurred
473 catch (const NumericalProblem& e)
474 {
475 std::cout << "rank " << gridView().comm().rank()
476 << " caught an exception while assembling:" << e.what()
477 << "\n";
478 succeeded = false;
479 }
480
481 // make sure everything worked well on all processes
482 if (gridView().comm().size() > 1)
483 succeeded = gridView().comm().min(succeeded);
484
485 // if not succeeded rethrow the error on all processes
486 if (!succeeded)
487 DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system");
488 }
489
490 template<class GG>
491 void enforcePeriodicConstraints_(JacobianMatrix& jac, ResidualType& res, const SolutionVector& curSol, const GG& gridGeometry) const
492 {
494 {
495 for (const auto& m : gridGeometry.periodicDofMap())
496 {
497 if (m.first < m.second)
498 {
499 // add the second row to the first
500 res[m.first] += res[m.second];
501 const auto end = jac[m.second].end();
502 for (auto it = jac[m.second].begin(); it != end; ++it)
503 jac[m.first][it.index()] += (*it);
504
505 // enforce constraint in second row
506 res[m.second] = curSol[m.second] - curSol[m.first];
507
508 // set derivatives accordingly in jacobian, i.e. id for m.second and -id for m.first
509 auto setMatrixBlock = [] (auto& matrixBlock, double diagValue)
510 {
511 for (int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
512 matrixBlock[eIdx][eIdx] = diagValue;
513 };
514
515 for (auto it = jac[m.second].begin(); it != end; ++it)
516 {
517 auto& matrixBlock = *it;
518 matrixBlock = 0.0;
519
520 assert(matrixBlock.N() == matrixBlock.M());
521 if(it.index() == m.second)
522 setMatrixBlock(matrixBlock, 1.0);
523
524 if(it.index() == m.first)
525 setMatrixBlock(matrixBlock, -1.0);
526
527 }
528 }
529 }
530 }
531 }
532
533 template<class GG>
534 void enforcePeriodicConstraints_(JacobianMatrix& jac, const SolutionVector&, const GG& gridGeometry) const
535 {
537 {
538 for (const auto& m : gridGeometry.periodicDofMap())
539 {
540 if (m.first < m.second)
541 {
542 // add the second row to the first
543 const auto end = jac[m.second].end();
544 for (auto it = jac[m.second].begin(); it != end; ++it)
545 jac[m.first][it.index()] += (*it);
546
547 // set derivatives accordingly in jacobian, i.e. id for m.second and -id for m.first
548 auto setMatrixBlock = [] (auto& matrixBlock, double diagValue)
549 {
550 for (int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
551 matrixBlock[eIdx][eIdx] = diagValue;
552 };
553
554 for (auto it = jac[m.second].begin(); it != end; ++it)
555 {
556 auto& matrixBlock = *it;
557 matrixBlock = 0.0;
558
559 assert(matrixBlock.N() == matrixBlock.M());
560 if(it.index() == m.second)
561 setMatrixBlock(matrixBlock, 1.0);
562
563 if(it.index() == m.first)
564 setMatrixBlock(matrixBlock, -1.0);
565
566 }
567 }
568 }
569 }
570 }
571
572 template<class GG>
573 void enforcePeriodicConstraints_(ResidualType& res, const SolutionVector& curSol, const GG& gridGeometry) const
574 {
576 {
577 for (const auto& m : gridGeometry.periodicDofMap())
578 {
579 if (m.first < m.second)
580 {
581 // add the second row to the first
582 res[m.first] += res[m.second];
583
584 // enforce constraint in second row
585 res[m.second] = curSol[m.second] - curSol[m.first];
586 }
587 }
588 }
589 }
590
591 template<class Problem, class GG, typename ApplyFunction>
592 void enforceProblemConstraints_(const Problem& problem, const GG&, const ApplyFunction& applyDirichletConstraint) const
593 {
595 {
596 for (const auto& constraintData : problem.constraints())
597 {
598 const auto& constraintInfo = constraintData.constraintInfo();
599 const auto& values = constraintData.values();
600 const auto dofIdx = constraintData.dofIndex();
601 // set the constraint in residual and jacobian
602 for (int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
603 {
604 if (constraintInfo.isConstraintEquation(eqIdx))
605 {
606 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
607 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
608 applyDirichletConstraint(dofIdx, values, eqIdx, pvIdx);
609 }
610 }
611 }
612 }
613 }
614
616 std::shared_ptr<const Problem> problem_;
617
619 std::shared_ptr<const GridGeometry> gridGeometry_;
620
622 std::shared_ptr<GridVariables> gridVariables_;
623
625 std::shared_ptr<const TimeLoop> timeLoop_;
626
628 const SolutionVector* prevSol_ = nullptr;
629
631 bool isStationaryProblem_;
632
634 std::shared_ptr<JacobianMatrix> jacobian_;
635 std::shared_ptr<ResidualType> residual_;
636
638 bool enableMultithreading_ = false;
639 std::deque<std::vector<ElementSeed>> elementSets_;
640};
641
642} // namespace Dumux::Experimental
643
644#endif
Assembler(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/assembler.hh:132
typename Dumux::Detail::NativeDuneVectorType< SolutionVector >::type ResidualType
Definition assembly/assembler.hh:97
void updateGridVariables(const SolutionVector &curSol)
Update the grid variables.
Definition assembly/assembler.hh:357
GetPropType< TypeTag, Properties::GridVariables > GridVariables
Definition assembly/assembler.hh:99
void assembleResidual(const SolutionVector &curSol)
compute the residuals using the internal residual
Definition assembly/assembler.hh:218
Assembler(std::shared_ptr< const Problem > problem, std::shared_ptr< const GridGeometry > gridGeometry, std::shared_ptr< GridVariables > gridVariables)
The constructor for stationary problems.
Definition assembly/assembler.hh:109
LocalResidual localResidual() const
Create a local residual object (used by the local assembler).
Definition assembly/assembler.hh:351
ResidualType & residual()
The residual vector (rhs).
Definition assembly/assembler.hh:321
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/assembler.hh:157
const GridGeometry & gridGeometry() const
Definition assembly/assembler.hh:301
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition assembly/assembler.hh:94
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition assembly/assembler.hh:285
const SolutionVector & prevSol() const
Definition assembly/assembler.hh:325
std::size_t numDofs() const
Returns the number of degrees of freedom.
Definition assembly/assembler.hh:293
void assembleResidual(ResidualType &r, const SolutionVector &curSol) const
assemble a residual r
Definition assembly/assembler.hh:225
GetPropType< TypeTag, Properties::SolutionVector > SolutionVector
Definition assembly/assembler.hh:96
void setTimeLoop(std::shared_ptr< const TimeLoop > timeLoop)
Set time loop for instationary problems.
Definition assembly/assembler.hh:332
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/assembler.hh:252
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/assembler.hh:339
const GridView & gridView() const
The gridview.
Definition assembly/assembler.hh:305
GetPropType< TypeTag, Properties::Problem > Problem
Definition assembly/assembler.hh:102
void assembleJacobian(const SolutionVector &curSol)
Assembles only the global Jacobian of the residual.
Definition assembly/assembler.hh:190
JacobianMatrix & jacobian()
The jacobian matrix.
Definition assembly/assembler.hh:317
bool isStationaryProblem() const
Whether we are assembling a stationary or instationary problem.
Definition assembly/assembler.hh:345
const GridVariables & gridVariables() const
The global grid variables.
Definition assembly/assembler.hh:313
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition assembly/assembler.hh:272
GetPropType< TypeTag, Properties::JacobianMatrix > JacobianMatrix
Definition assembly/assembler.hh:95
GridVariables & gridVariables()
Definition assembly/assembler.hh:309
void resetTimeStep(const SolutionVector &curSol)
Reset the gridVariables.
Definition assembly/assembler.hh:365
const Problem & problem() const
Definition assembly/assembler.hh:297
An assembler for Jacobian and residual contribution per element (CVFE methods).
Definition experimental/assembly/cvfelocalassembler.hh:326
The element-wise residual for grid-based discretization schemes.
Definition assembly/localresidual.hh:39
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.
Some exceptions thrown in DuMux.
dune-grid capabilities compatibility layer
Dune::MatrixIndexSet getJacobianPattern(const GridGeometry &gridGeometry)
Helper function to generate Jacobian pattern for cell-centered methods.
Definition jacobianpattern.hh:28
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
T getParam(Args &&... args)
A free function to get a parameter from the parameter tree singleton.
Definition parameters.hh:139
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.
constexpr bool hasPeriodicDofMap()
Definition periodic.hh:24
Definition method.hh:20
Definition hybrid/elementvariables.hh:30
Definition assembly/assembler.hh:44
constexpr bool hasGlobalConstraints()
Definition assembly/assembler.hh:66
decltype(std::declval< P >().constraints()) ProblemConstraintsDetector
helper struct detecting if problem has a constraints() function
Definition assembly/assembler.hh:63
typename LocalAssemblerChooser< typename GetPropType< TypeTag, Properties::GridGeometry >::DiscretizationMethod >::template type< TypeTag, Impl, diffMethod, isImplicit > LocalAssemblerChooser_t
Definition assembly/assembler.hh:57
Definition assembly/assembler.hh:44
bool supportsMultithreading(const GridView &gridView)
Definition gridcapabilities.hh:34
const Scalar PengRobinsonMixture< Scalar, StaticParameters >::u
Definition pengrobinsonmixture.hh:138
auto computeColoring(const GridGeometry &gg, int verbosity=1)
Compute iterable lists of element seeds partitioned by color.
Definition coloring.hh:243
Parallel for loop (multithreading).
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
Type traits to detect periodicity support.
typename NativeDuneVectorTypeImpl< V, Dune::Std::is_detected< Detail::DuneVectors::StateDetector, V >{} >::type type
Definition dunevectors.hh:57
Dumux::Experimental::CVFELocalAssembler< TypeTag, Impl, diffMethod, isImplicit > type
Definition assembly/assembler.hh:53
Definition assembly/assembler.hh:47
Traits specifying if a given discretization tag supports coloring.
Definition coloring.hh:296