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 <algorithm>
16#include <cassert>
17#include <iostream>
18#include <vector>
19#include <deque>
20#include <memory>
21#include <utility>
22
23#include <dune/common/std/type_traits.hh>
24#include <dune/grid/common/rangegenerators.hh>
25
33
36
40
43
44#include "cvfelocalassembler_.hh"
45
47
48template<class DiscretizationMethod>
50
51template<class DM>
53{
54 template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
56};
57
58template<class TypeTag, class Impl, DiffMethod diffMethod, bool isImplicit>
61>::template type<TypeTag, Impl, diffMethod, isImplicit>;
62
64template<class P>
65using ProblemConstraintsDetector = decltype(std::declval<P>().constraints());
66
67template<class P>
68constexpr inline bool hasGlobalConstraints()
69{ return Dune::Std::is_detected<ProblemConstraintsDetector, P>::value; }
70
71} // end namespace Dumux::Experimental::Detail
72
73namespace Dumux::Experimental {
74
83template<class TypeTag, DiffMethod diffMethod, bool isImplicit = true, class LocalResidual = GetPropType<TypeTag, Properties::LocalResidual>>
85{
87 using GridView = typename GridDisc::GridView;
88 using Element = typename GridView::template Codim<0>::Entity;
89 using ElementSeed = typename GridView::Grid::template Codim<0>::EntitySeed;
91
94
95public:
100
102
103 using GridDiscretization = GridDisc;
105 using GridGeometry = GridDisc;
107
113 Assembler(std::shared_ptr<const Problem> problem,
114 std::shared_ptr<const GridDiscretization> gridDiscretization,
115 std::shared_ptr<GridVariables> gridVariables)
116 : problem_(problem)
117 , gridDiscretization_(gridDiscretization)
118 , gridVariables_(gridVariables)
119 , timeLoop_()
120 , isStationaryProblem_(true)
121 {
122 static_assert(isImplicit, "Explicit assembler for stationary problem doesn't make sense!");
124 && Grid::Capabilities::supportsMultithreading(gridDiscretization_->gridView())
126 && getParam<bool>("Assembly.Multithreading", true);
127
128 maybeComputeColors_();
129 }
130
136 Assembler(std::shared_ptr<const Problem> problem,
137 std::shared_ptr<const GridDiscretization> gridDiscretization,
138 std::shared_ptr<GridVariables> gridVariables,
139 std::shared_ptr<const TimeLoop> timeLoop,
140 const SolutionVector& prevSol)
141 : problem_(problem)
142 , gridDiscretization_(gridDiscretization)
143 , gridVariables_(gridVariables)
144 , timeLoop_(timeLoop)
145 , prevSol_(&prevSol)
146 , isStationaryProblem_(!timeLoop)
147 {
149 && Grid::Capabilities::supportsMultithreading(gridDiscretization_->gridView())
151 && getParam<bool>("Assembly.Multithreading", true);
152
153 maybeComputeColors_();
154 }
155
160 template<class PartialReassembler = DefaultPartialReassembler>
161 void assembleJacobianAndResidual(const SolutionVector& curSol, const PartialReassembler* partialReassembler = nullptr)
162 {
163 checkAssemblerState_();
164 resetJacobian_(partialReassembler);
165 resetResidual_();
166
167 assemble_([&](const Element& element)
168 {
169 LocalAssembler localAssembler(*this, element, curSol);
170 localAssembler.assembleJacobianAndResidual(*jacobian_, *residual_, *gridVariables_, partialReassembler);
171 });
172
173 enforcePeriodicConstraints_(*jacobian_, *residual_, curSol, *gridDiscretization_);
174
175 auto applyDirichletConstraint = [&] (const auto& dofIdx,
176 const auto& values,
177 const auto eqIdx,
178 const auto pvIdx)
179 {
180 (*residual_)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
181
182 auto& row = (*jacobian_)[dofIdx];
183 for (auto col = row.begin(); col != row.end(); ++col)
184 row[col.index()][eqIdx] = 0.0;
185
186 (*jacobian_)[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
187 };
188 enforceProblemConstraints_(*problem_, *gridDiscretization_, applyDirichletConstraint);
189 }
190
195 {
196 checkAssemblerState_();
197 resetJacobian_();
198
199 assemble_([&](const Element& element)
200 {
201 LocalAssembler localAssembler(*this, element, curSol);
202 localAssembler.assembleJacobian(*jacobian_, *gridVariables_);
203 });
204
205 enforcePeriodicConstraints_(*jacobian_, curSol, *gridDiscretization_);
206
207 auto applyDirichletConstraint = [&] (const auto& dofIdx,
208 const auto& values,
209 const auto eqIdx,
210 const auto pvIdx)
211 {
212 auto& row = (*jacobian_)[dofIdx];
213 for (auto col = row.begin(); col != row.end(); ++col)
214 row[col.index()][eqIdx] = 0.0;
215
216 (*jacobian_)[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
217 };
218 enforceProblemConstraints_(*problem_, *gridDiscretization_, applyDirichletConstraint);
219 }
220
223 {
224 resetResidual_();
225 assembleResidual(*residual_, curSol);
226 }
227
229 void assembleResidual(ResidualType& r, const SolutionVector& curSol) const
230 {
231 checkAssemblerState_();
232
233 assemble_([&](const Element& element)
234 {
235 LocalAssembler localAssembler(*this, element, curSol);
236 localAssembler.assembleResidual(r);
237 });
238
239 enforcePeriodicConstraints_(r, curSol, *gridDiscretization_);
240
241 auto applyDirichletConstraint = [&] (const auto& dofIdx,
242 const auto& values,
243 const auto eqIdx,
244 const auto pvIdx)
245 {
246 r[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
247 };
248 enforceProblemConstraints_(*problem_, *gridDiscretization_, applyDirichletConstraint);
249 }
250
256 void setLinearSystem(std::shared_ptr<JacobianMatrix> A,
257 std::shared_ptr<ResidualType> r)
258 {
259 jacobian_ = A;
260 residual_ = r;
261
262 // check and/or set the BCRS matrix's build mode
263 if (jacobian_->buildMode() == JacobianMatrix::BuildMode::unknown)
264 jacobian_->setBuildMode(JacobianMatrix::random);
265 else if (jacobian_->buildMode() != JacobianMatrix::BuildMode::random)
266 DUNE_THROW(Dune::NotImplemented, "Only BCRS matrices with random build mode are supported at the moment");
267
268 setResidualSize_();
269 setJacobianPattern_();
270 }
271
277 {
278 jacobian_ = std::make_shared<JacobianMatrix>();
279 jacobian_->setBuildMode(JacobianMatrix::random);
280 residual_ = std::make_shared<ResidualType>();
281
282 setResidualSize_();
283 setJacobianPattern_();
284 }
285
290 {
291 setResidualSize_();
292 setJacobianPattern_();
293 maybeComputeColors_();
294 }
295
297 std::size_t numDofs() const
298 { return gridDiscretization_->numDofs(); }
299
301 const Problem& problem() const
302 { return *problem_; }
303
306 { return *gridDiscretization_; }
307
310 { return *gridDiscretization_; }
311
313 const GridView& gridView() const
314 { return gridDiscretization().gridView(); }
315
318 { return *gridVariables_; }
319
322 { return *gridVariables_; }
323
326 { return *jacobian_; }
327
330 { return *residual_; }
331
333 const SolutionVector& prevSol() const
334 { return *prevSol_; }
335
340 void setTimeLoop(std::shared_ptr<const TimeLoop> timeLoop)
341 { timeLoop_ = timeLoop; isStationaryProblem_ = !static_cast<bool>(timeLoop); }
342
348 { prevSol_ = &u; }
349
354 { return isStationaryProblem_; }
355
360 { return LocalResidual(problem_.get(), timeLoop_.get()); }
361
366 {
367 gridVariables().update(curSol);
368 }
369
373 void resetTimeStep(const SolutionVector& curSol)
374 {
375 gridVariables().resetTimeStep(curSol);
376 }
377
378private:
382 void setJacobianPattern_()
383 {
384 // resize the jacobian and the residual
385 const auto numDofs = this->numDofs();
386 jacobian_->setSize(numDofs, numDofs);
387
388 // create occupation pattern of the jacobian
389 const auto occupationPattern = getJacobianPattern<isImplicit>(gridDiscretization());
390
391 // export pattern to jacobian
392 occupationPattern.exportIdx(*jacobian_);
393 }
394
396 void setResidualSize_()
397 { residual_->resize(numDofs()); }
398
400 void maybeComputeColors_()
401 {
402 if (enableMultithreading_)
403 elementSets_ = computeColoring(gridDiscretization()).sets;
404 }
405
406 // reset the residual vector to 0.0
407 void resetResidual_()
408 {
409 if(!residual_)
410 {
411 residual_ = std::make_shared<ResidualType>();
412 setResidualSize_();
413 }
414
415 (*residual_) = 0.0;
416 }
417
418 // reset the Jacobian matrix to 0.0
419 template <class PartialReassembler = DefaultPartialReassembler>
420 void resetJacobian_(const PartialReassembler *partialReassembler = nullptr)
421 {
422 if(!jacobian_)
423 {
424 jacobian_ = std::make_shared<JacobianMatrix>();
425 jacobian_->setBuildMode(JacobianMatrix::random);
426 setJacobianPattern_();
427 }
428
429 if (partialReassembler)
430 partialReassembler->resetJacobian(*this);
431 else
432 *jacobian_ = 0.0;
433 }
434
435 // check if the assembler is in a correct state for assembly
436 void checkAssemblerState_() const
437 {
438 if (!isStationaryProblem_ && !prevSol_)
439 DUNE_THROW(Dune::InvalidStateException, "Assembling instationary problem but previous solution was not set!");
440 }
441
447 template<typename AssembleElementFunc>
448 void assemble_(AssembleElementFunc&& assembleElement) const
449 {
450 // a state that will be checked on all processes
451 bool succeeded = false;
452
453 // try assembling using the local assembly function
454 try
455 {
456 if (enableMultithreading_)
457 {
458 assert(elementSets_.size() > 0);
459
460 // make this element loop run in parallel
461 // for this we have to color the elements so that we don't get
462 // race conditions when writing into the global matrix
463 // each color can be assembled using multiple threads
464 for (const auto& elements : elementSets_)
465 {
466 Dumux::parallelFor(elements.size(), [&](const std::size_t i)
467 {
468 const auto element = gridView().grid().entity(elements[i]);
469 assembleElement(element);
470 });
471 }
472 }
473 else
474 for (const auto& element : elements(gridView()))
475 assembleElement(element);
476
477 // if we get here, everything worked well on this process
478 succeeded = true;
479 }
480 // throw exception if a problem occurred
481 catch (const NumericalProblem& e)
482 {
483 std::cout << "rank " << gridView().comm().rank()
484 << " caught an exception while assembling:" << e.what()
485 << "\n";
486 succeeded = false;
487 }
488
489 // make sure everything worked well on all processes
490 if (gridView().comm().size() > 1)
491 succeeded = gridView().comm().min(succeeded);
492
493 // if not succeeded rethrow the error on all processes
494 if (!succeeded)
495 DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system");
496 }
497
498 template<class GG>
499 void enforcePeriodicConstraints_(JacobianMatrix& jac, ResidualType& res, const SolutionVector& curSol, const GG& gridDiscretization) const
500 {
502 {
503 for (const auto& m : gridDiscretization.periodicDofMap())
504 {
505 const auto& periodicallyMappedDofs = Dumux::Deprecated::ensureRangeOfPeriodicDofs(m.second);
506 if (std::ranges::all_of(periodicallyMappedDofs, [&](auto second){ return m.first < second; }))
507 {
508 for (const auto& second : periodicallyMappedDofs)
509 {
510 // add the second row to the first
511 res[m.first] += res[second];
512 const auto end = jac[second].end();
513 for (auto it = jac[second].begin(); it != end; ++it)
514 jac[m.first][it.index()] += (*it);
515
516 // enforce constraint in second row
517 res[second] = curSol[second] - curSol[m.first];
518
519 // set derivatives accordingly in jacobian, i.e. id for second and -id for m.first
520 auto setMatrixBlock = [] (auto& matrixBlock, double diagValue)
521 {
522 for (int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
523 matrixBlock[eIdx][eIdx] = diagValue;
524 };
525
526 for (auto it = jac[second].begin(); it != end; ++it)
527 {
528 auto& matrixBlock = *it;
529 matrixBlock = 0.0;
530
531 assert(matrixBlock.N() == matrixBlock.M());
532 if(it.index() == second)
533 setMatrixBlock(matrixBlock, 1.0);
534
535 if(it.index() == m.first)
536 setMatrixBlock(matrixBlock, -1.0);
537
538 }
539 }
540 }
541 }
542 }
543 }
544
545 template<class GG>
546 void enforcePeriodicConstraints_(JacobianMatrix& jac, const SolutionVector&, const GG& gridDiscretization) const
547 {
549 {
550 for (const auto& m : gridDiscretization.periodicDofMap())
551 {
552 const auto& periodicallyMappedDofs = Dumux::Deprecated::ensureRangeOfPeriodicDofs(m.second);
553 if (std::ranges::all_of(periodicallyMappedDofs, [&](auto second){ return m.first < second; }))
554 {
555 for (const auto& second : periodicallyMappedDofs)
556 {
557 // add the second row to the first
558 const auto end = jac[second].end();
559 for (auto it = jac[second].begin(); it != end; ++it)
560 jac[m.first][it.index()] += (*it);
561
562 // set derivatives accordingly in jacobian, i.e. id for second and -id for m.first
563 auto setMatrixBlock = [] (auto& matrixBlock, double diagValue)
564 {
565 for (int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
566 matrixBlock[eIdx][eIdx] = diagValue;
567 };
568
569 for (auto it = jac[second].begin(); it != end; ++it)
570 {
571 auto& matrixBlock = *it;
572 matrixBlock = 0.0;
573
574 assert(matrixBlock.N() == matrixBlock.M());
575 if(it.index() == second)
576 setMatrixBlock(matrixBlock, 1.0);
577
578 if(it.index() == m.first)
579 setMatrixBlock(matrixBlock, -1.0);
580
581 }
582 }
583 }
584 }
585 }
586 }
587
588 template<class GG>
589 void enforcePeriodicConstraints_(ResidualType& res, const SolutionVector& curSol, const GG& gridDiscretization) const
590 {
592 {
593 for (const auto& m : gridDiscretization.periodicDofMap())
594 {
595 const auto& periodicallyMappedDofs = Dumux::Deprecated::ensureRangeOfPeriodicDofs(m.second);
596 if (std::ranges::all_of(periodicallyMappedDofs, [&](auto second){ return m.first < second; }))
597 {
598 for (const auto& second : periodicallyMappedDofs)
599 {
600 // add the second row to the first
601 res[m.first] += res[second];
602
603 // enforce constraint in second row
604 res[second] = curSol[second] - curSol[m.first];
605 }
606 }
607 }
608 }
609 }
610
611 template<class Problem, class GG, typename ApplyFunction>
612 void enforceProblemConstraints_(const Problem& problem, const GG&, const ApplyFunction& applyDirichletConstraint) const
613 {
615 {
616 for (const auto& constraintData : problem.constraints())
617 {
618 const auto& constraintInfo = constraintData.constraintInfo();
619 const auto& values = constraintData.values();
620 const auto dofIdx = constraintData.dofIndex();
621 // set the constraint in residual and jacobian
622 for (int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
623 {
624 if (constraintInfo.isConstraintEquation(eqIdx))
625 {
626 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
627 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
628 applyDirichletConstraint(dofIdx, values, eqIdx, pvIdx);
629 }
630 }
631 }
632 }
633 }
634
636 std::shared_ptr<const Problem> problem_;
637
639 std::shared_ptr<const GridDiscretization> gridDiscretization_;
640
642 std::shared_ptr<GridVariables> gridVariables_;
643
645 std::shared_ptr<const TimeLoop> timeLoop_;
646
648 const SolutionVector* prevSol_ = nullptr;
649
651 bool isStationaryProblem_;
652
654 std::shared_ptr<JacobianMatrix> jacobian_;
655 std::shared_ptr<ResidualType> residual_;
656
658 bool enableMultithreading_ = false;
659 std::deque<std::vector<ElementSeed>> elementSets_;
660};
661
662} // namespace Dumux::Experimental
663
664#endif
typename Dumux::Detail::NativeDuneVectorType< SolutionVector >::type ResidualType
Definition assembly/assembler.hh:99
void updateGridVariables(const SolutionVector &curSol)
Update the grid variables.
Definition assembly/assembler.hh:365
GetPropType< TypeTag, Properties::GridVariables > GridVariables
Definition assembly/assembler.hh:101
void assembleResidual(const SolutionVector &curSol)
compute the residuals using the internal residual
Definition assembly/assembler.hh:222
LocalResidual localResidual() const
Create a local residual object (used by the local assembler).
Definition assembly/assembler.hh:359
ResidualType & residual()
The residual vector (rhs).
Definition assembly/assembler.hh:329
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:161
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition assembly/assembler.hh:96
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition assembly/assembler.hh:289
const GridDiscretization & gridDiscretization() const
Definition assembly/assembler.hh:305
const SolutionVector & prevSol() const
Definition assembly/assembler.hh:333
std::size_t numDofs() const
Returns the number of degrees of freedom.
Definition assembly/assembler.hh:297
void assembleResidual(ResidualType &r, const SolutionVector &curSol) const
assemble a residual r
Definition assembly/assembler.hh:229
Assembler(std::shared_ptr< const Problem > problem, std::shared_ptr< const GridDiscretization > gridDiscretization, std::shared_ptr< GridVariables > gridVariables, std::shared_ptr< const TimeLoop > timeLoop, const SolutionVector &prevSol)
The constructor for instationary problems.
Definition assembly/assembler.hh:136
GetPropType< TypeTag, Properties::SolutionVector > SolutionVector
Definition assembly/assembler.hh:98
Assembler(std::shared_ptr< const Problem > problem, std::shared_ptr< const GridDiscretization > gridDiscretization, std::shared_ptr< GridVariables > gridVariables)
The constructor for stationary problems.
Definition assembly/assembler.hh:113
void setTimeLoop(std::shared_ptr< const TimeLoop > timeLoop)
Set time loop for instationary problems.
Definition assembly/assembler.hh:340
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:256
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:347
const GridView & gridView() const
The gridview.
Definition assembly/assembler.hh:313
GetPropType< TypeTag, Properties::Problem > Problem
Definition assembly/assembler.hh:106
void assembleJacobian(const SolutionVector &curSol)
Assembles only the global Jacobian of the residual.
Definition assembly/assembler.hh:194
JacobianMatrix & jacobian()
The jacobian matrix.
Definition assembly/assembler.hh:325
bool isStationaryProblem() const
Whether we are assembling a stationary or instationary problem.
Definition assembly/assembler.hh:353
const GridVariables & gridVariables() const
The global grid variables.
Definition assembly/assembler.hh:321
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition assembly/assembler.hh:276
GetPropType< TypeTag, Properties::JacobianMatrix > JacobianMatrix
Definition assembly/assembler.hh:97
const GridDiscretization & gridGeometry() const
support old interfaces
Definition assembly/assembler.hh:309
GridVariables & gridVariables()
Definition assembly/assembler.hh:317
void resetTimeStep(const SolutionVector &curSol)
Reset the gridVariables.
Definition assembly/assembler.hh:373
const Problem & problem() const
Definition assembly/assembler.hh:301
An assembler for Jacobian and residual contribution per element (CVFE methods).
Definition experimental/assembly/cvfelocalassembler.hh:335
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:418
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.
Helpers for deprecation.
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:29
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:155
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 cvfe/hybrid/elementvariables.hh:32
Definition assembly/assembler.hh:46
constexpr bool hasGlobalConstraints()
Definition assembly/assembler.hh:68
decltype(std::declval< P >().constraints()) ProblemConstraintsDetector
helper struct detecting if problem has a constraints() function
Definition assembly/assembler.hh:65
typename LocalAssemblerChooser< typename GetPropType< TypeTag, Properties::GridGeometry >::DiscretizationMethod >::template type< TypeTag, Impl, diffMethod, isImplicit > LocalAssemblerChooser_t
Definition assembly/assembler.hh:59
Definition assembly/assembler.hh:46
bool supportsMultithreading(const GridView &gridView)
Definition gridcapabilities.hh:36
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:55
Definition assembly/assembler.hh:49
Traits specifying if a given discretization tag supports coloring.
Definition coloring.hh:296