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 GridDisc::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 GridDiscretization = GridDisc;
103 using GridGeometry = GridDisc;
105
111 Assembler(std::shared_ptr<const Problem> problem,
112 std::shared_ptr<const GridDiscretization> gridDiscretization,
113 std::shared_ptr<GridVariables> gridVariables)
114 : problem_(problem)
115 , gridDiscretization_(gridDiscretization)
116 , gridVariables_(gridVariables)
117 , timeLoop_()
118 , isStationaryProblem_(true)
119 {
120 static_assert(isImplicit, "Explicit assembler for stationary problem doesn't make sense!");
122 && Grid::Capabilities::supportsMultithreading(gridDiscretization_->gridView())
124 && getParam<bool>("Assembly.Multithreading", true);
125
126 maybeComputeColors_();
127 }
128
134 Assembler(std::shared_ptr<const Problem> problem,
135 std::shared_ptr<const GridDiscretization> gridDiscretization,
136 std::shared_ptr<GridVariables> gridVariables,
137 std::shared_ptr<const TimeLoop> timeLoop,
138 const SolutionVector& prevSol)
139 : problem_(problem)
140 , gridDiscretization_(gridDiscretization)
141 , gridVariables_(gridVariables)
142 , timeLoop_(timeLoop)
143 , prevSol_(&prevSol)
144 , isStationaryProblem_(!timeLoop)
145 {
147 && Grid::Capabilities::supportsMultithreading(gridDiscretization_->gridView())
149 && getParam<bool>("Assembly.Multithreading", true);
150
151 maybeComputeColors_();
152 }
153
158 template<class PartialReassembler = DefaultPartialReassembler>
159 void assembleJacobianAndResidual(const SolutionVector& curSol, const PartialReassembler* partialReassembler = nullptr)
160 {
161 checkAssemblerState_();
162 resetJacobian_(partialReassembler);
163 resetResidual_();
164
165 assemble_([&](const Element& element)
166 {
167 LocalAssembler localAssembler(*this, element, curSol);
168 localAssembler.assembleJacobianAndResidual(*jacobian_, *residual_, *gridVariables_, partialReassembler);
169 });
170
171 enforcePeriodicConstraints_(*jacobian_, *residual_, curSol, *gridDiscretization_);
172
173 auto applyDirichletConstraint = [&] (const auto& dofIdx,
174 const auto& values,
175 const auto eqIdx,
176 const auto pvIdx)
177 {
178 (*residual_)[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
179
180 auto& row = (*jacobian_)[dofIdx];
181 for (auto col = row.begin(); col != row.end(); ++col)
182 row[col.index()][eqIdx] = 0.0;
183
184 (*jacobian_)[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
185 };
186 enforceProblemConstraints_(*problem_, *gridDiscretization_, applyDirichletConstraint);
187 }
188
193 {
194 checkAssemblerState_();
195 resetJacobian_();
196
197 assemble_([&](const Element& element)
198 {
199 LocalAssembler localAssembler(*this, element, curSol);
200 localAssembler.assembleJacobian(*jacobian_, *gridVariables_);
201 });
202
203 enforcePeriodicConstraints_(*jacobian_, curSol, *gridDiscretization_);
204
205 auto applyDirichletConstraint = [&] (const auto& dofIdx,
206 const auto& values,
207 const auto eqIdx,
208 const auto pvIdx)
209 {
210 auto& row = (*jacobian_)[dofIdx];
211 for (auto col = row.begin(); col != row.end(); ++col)
212 row[col.index()][eqIdx] = 0.0;
213
214 (*jacobian_)[dofIdx][dofIdx][eqIdx][pvIdx] = 1.0;
215 };
216 enforceProblemConstraints_(*problem_, *gridDiscretization_, applyDirichletConstraint);
217 }
218
221 {
222 resetResidual_();
223 assembleResidual(*residual_, curSol);
224 }
225
227 void assembleResidual(ResidualType& r, const SolutionVector& curSol) const
228 {
229 checkAssemblerState_();
230
231 assemble_([&](const Element& element)
232 {
233 LocalAssembler localAssembler(*this, element, curSol);
234 localAssembler.assembleResidual(r);
235 });
236
237 enforcePeriodicConstraints_(r, curSol, *gridDiscretization_);
238
239 auto applyDirichletConstraint = [&] (const auto& dofIdx,
240 const auto& values,
241 const auto eqIdx,
242 const auto pvIdx)
243 {
244 r[dofIdx][eqIdx] = curSol[dofIdx][pvIdx] - values[pvIdx];
245 };
246 enforceProblemConstraints_(*problem_, *gridDiscretization_, applyDirichletConstraint);
247 }
248
254 void setLinearSystem(std::shared_ptr<JacobianMatrix> A,
255 std::shared_ptr<ResidualType> r)
256 {
257 jacobian_ = A;
258 residual_ = r;
259
260 // check and/or set the BCRS matrix's build mode
261 if (jacobian_->buildMode() == JacobianMatrix::BuildMode::unknown)
262 jacobian_->setBuildMode(JacobianMatrix::random);
263 else if (jacobian_->buildMode() != JacobianMatrix::BuildMode::random)
264 DUNE_THROW(Dune::NotImplemented, "Only BCRS matrices with random build mode are supported at the moment");
265
266 setResidualSize_();
267 setJacobianPattern_();
268 }
269
275 {
276 jacobian_ = std::make_shared<JacobianMatrix>();
277 jacobian_->setBuildMode(JacobianMatrix::random);
278 residual_ = std::make_shared<ResidualType>();
279
280 setResidualSize_();
281 setJacobianPattern_();
282 }
283
288 {
289 setResidualSize_();
290 setJacobianPattern_();
291 maybeComputeColors_();
292 }
293
295 std::size_t numDofs() const
296 { return gridDiscretization_->numDofs(); }
297
299 const Problem& problem() const
300 { return *problem_; }
301
304 { return *gridDiscretization_; }
305
308 { return *gridDiscretization_; }
309
311 const GridView& gridView() const
312 { return gridDiscretization().gridView(); }
313
316 { return *gridVariables_; }
317
320 { return *gridVariables_; }
321
324 { return *jacobian_; }
325
328 { return *residual_; }
329
331 const SolutionVector& prevSol() const
332 { return *prevSol_; }
333
338 void setTimeLoop(std::shared_ptr<const TimeLoop> timeLoop)
339 { timeLoop_ = timeLoop; isStationaryProblem_ = !static_cast<bool>(timeLoop); }
340
346 { prevSol_ = &u; }
347
352 { return isStationaryProblem_; }
353
358 { return LocalResidual(problem_.get(), timeLoop_.get()); }
359
364 {
365 gridVariables().update(curSol);
366 }
367
371 void resetTimeStep(const SolutionVector& curSol)
372 {
373 gridVariables().resetTimeStep(curSol);
374 }
375
376private:
380 void setJacobianPattern_()
381 {
382 // resize the jacobian and the residual
383 const auto numDofs = this->numDofs();
384 jacobian_->setSize(numDofs, numDofs);
385
386 // create occupation pattern of the jacobian
387 const auto occupationPattern = getJacobianPattern<isImplicit>(gridDiscretization());
388
389 // export pattern to jacobian
390 occupationPattern.exportIdx(*jacobian_);
391 }
392
394 void setResidualSize_()
395 { residual_->resize(numDofs()); }
396
398 void maybeComputeColors_()
399 {
400 if (enableMultithreading_)
401 elementSets_ = computeColoring(gridDiscretization()).sets;
402 }
403
404 // reset the residual vector to 0.0
405 void resetResidual_()
406 {
407 if(!residual_)
408 {
409 residual_ = std::make_shared<ResidualType>();
410 setResidualSize_();
411 }
412
413 (*residual_) = 0.0;
414 }
415
416 // reset the Jacobian matrix to 0.0
417 template <class PartialReassembler = DefaultPartialReassembler>
418 void resetJacobian_(const PartialReassembler *partialReassembler = nullptr)
419 {
420 if(!jacobian_)
421 {
422 jacobian_ = std::make_shared<JacobianMatrix>();
423 jacobian_->setBuildMode(JacobianMatrix::random);
424 setJacobianPattern_();
425 }
426
427 if (partialReassembler)
428 partialReassembler->resetJacobian(*this);
429 else
430 *jacobian_ = 0.0;
431 }
432
433 // check if the assembler is in a correct state for assembly
434 void checkAssemblerState_() const
435 {
436 if (!isStationaryProblem_ && !prevSol_)
437 DUNE_THROW(Dune::InvalidStateException, "Assembling instationary problem but previous solution was not set!");
438 }
439
445 template<typename AssembleElementFunc>
446 void assemble_(AssembleElementFunc&& assembleElement) const
447 {
448 // a state that will be checked on all processes
449 bool succeeded = false;
450
451 // try assembling using the local assembly function
452 try
453 {
454 if (enableMultithreading_)
455 {
456 assert(elementSets_.size() > 0);
457
458 // make this element loop run in parallel
459 // for this we have to color the elements so that we don't get
460 // race conditions when writing into the global matrix
461 // each color can be assembled using multiple threads
462 for (const auto& elements : elementSets_)
463 {
464 Dumux::parallelFor(elements.size(), [&](const std::size_t i)
465 {
466 const auto element = gridView().grid().entity(elements[i]);
467 assembleElement(element);
468 });
469 }
470 }
471 else
472 for (const auto& element : elements(gridView()))
473 assembleElement(element);
474
475 // if we get here, everything worked well on this process
476 succeeded = true;
477 }
478 // throw exception if a problem occurred
479 catch (const NumericalProblem& e)
480 {
481 std::cout << "rank " << gridView().comm().rank()
482 << " caught an exception while assembling:" << e.what()
483 << "\n";
484 succeeded = false;
485 }
486
487 // make sure everything worked well on all processes
488 if (gridView().comm().size() > 1)
489 succeeded = gridView().comm().min(succeeded);
490
491 // if not succeeded rethrow the error on all processes
492 if (!succeeded)
493 DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system");
494 }
495
496 template<class GG>
497 void enforcePeriodicConstraints_(JacobianMatrix& jac, ResidualType& res, const SolutionVector& curSol, const GG& gridDiscretization) const
498 {
500 {
501 for (const auto& m : gridDiscretization.periodicDofMap())
502 {
503 if (m.first < m.second)
504 {
505 // add the second row to the first
506 res[m.first] += res[m.second];
507 const auto end = jac[m.second].end();
508 for (auto it = jac[m.second].begin(); it != end; ++it)
509 jac[m.first][it.index()] += (*it);
510
511 // enforce constraint in second row
512 res[m.second] = curSol[m.second] - curSol[m.first];
513
514 // set derivatives accordingly in jacobian, i.e. id for m.second and -id for m.first
515 auto setMatrixBlock = [] (auto& matrixBlock, double diagValue)
516 {
517 for (int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
518 matrixBlock[eIdx][eIdx] = diagValue;
519 };
520
521 for (auto it = jac[m.second].begin(); it != end; ++it)
522 {
523 auto& matrixBlock = *it;
524 matrixBlock = 0.0;
525
526 assert(matrixBlock.N() == matrixBlock.M());
527 if(it.index() == m.second)
528 setMatrixBlock(matrixBlock, 1.0);
529
530 if(it.index() == m.first)
531 setMatrixBlock(matrixBlock, -1.0);
532
533 }
534 }
535 }
536 }
537 }
538
539 template<class GG>
540 void enforcePeriodicConstraints_(JacobianMatrix& jac, const SolutionVector&, const GG& gridDiscretization) const
541 {
543 {
544 for (const auto& m : gridDiscretization.periodicDofMap())
545 {
546 if (m.first < m.second)
547 {
548 // add the second row to the first
549 const auto end = jac[m.second].end();
550 for (auto it = jac[m.second].begin(); it != end; ++it)
551 jac[m.first][it.index()] += (*it);
552
553 // set derivatives accordingly in jacobian, i.e. id for m.second and -id for m.first
554 auto setMatrixBlock = [] (auto& matrixBlock, double diagValue)
555 {
556 for (int eIdx = 0; eIdx < matrixBlock.N(); ++eIdx)
557 matrixBlock[eIdx][eIdx] = diagValue;
558 };
559
560 for (auto it = jac[m.second].begin(); it != end; ++it)
561 {
562 auto& matrixBlock = *it;
563 matrixBlock = 0.0;
564
565 assert(matrixBlock.N() == matrixBlock.M());
566 if(it.index() == m.second)
567 setMatrixBlock(matrixBlock, 1.0);
568
569 if(it.index() == m.first)
570 setMatrixBlock(matrixBlock, -1.0);
571
572 }
573 }
574 }
575 }
576 }
577
578 template<class GG>
579 void enforcePeriodicConstraints_(ResidualType& res, const SolutionVector& curSol, const GG& gridDiscretization) const
580 {
582 {
583 for (const auto& m : gridDiscretization.periodicDofMap())
584 {
585 if (m.first < m.second)
586 {
587 // add the second row to the first
588 res[m.first] += res[m.second];
589
590 // enforce constraint in second row
591 res[m.second] = curSol[m.second] - curSol[m.first];
592 }
593 }
594 }
595 }
596
597 template<class Problem, class GG, typename ApplyFunction>
598 void enforceProblemConstraints_(const Problem& problem, const GG&, const ApplyFunction& applyDirichletConstraint) const
599 {
601 {
602 for (const auto& constraintData : problem.constraints())
603 {
604 const auto& constraintInfo = constraintData.constraintInfo();
605 const auto& values = constraintData.values();
606 const auto dofIdx = constraintData.dofIndex();
607 // set the constraint in residual and jacobian
608 for (int eqIdx = 0; eqIdx < constraintInfo.size(); ++eqIdx)
609 {
610 if (constraintInfo.isConstraintEquation(eqIdx))
611 {
612 const auto pvIdx = constraintInfo.eqToPriVarIndex(eqIdx);
613 assert(0 <= pvIdx && pvIdx < constraintInfo.size());
614 applyDirichletConstraint(dofIdx, values, eqIdx, pvIdx);
615 }
616 }
617 }
618 }
619 }
620
622 std::shared_ptr<const Problem> problem_;
623
625 std::shared_ptr<const GridDiscretization> gridDiscretization_;
626
628 std::shared_ptr<GridVariables> gridVariables_;
629
631 std::shared_ptr<const TimeLoop> timeLoop_;
632
634 const SolutionVector* prevSol_ = nullptr;
635
637 bool isStationaryProblem_;
638
640 std::shared_ptr<JacobianMatrix> jacobian_;
641 std::shared_ptr<ResidualType> residual_;
642
644 bool enableMultithreading_ = false;
645 std::deque<std::vector<ElementSeed>> elementSets_;
646};
647
648} // namespace Dumux::Experimental
649
650#endif
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:363
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:220
LocalResidual localResidual() const
Create a local residual object (used by the local assembler).
Definition assembly/assembler.hh:357
ResidualType & residual()
The residual vector (rhs).
Definition assembly/assembler.hh:327
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:159
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition assembly/assembler.hh:94
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition assembly/assembler.hh:287
const GridDiscretization & gridDiscretization() const
Definition assembly/assembler.hh:303
const SolutionVector & prevSol() const
Definition assembly/assembler.hh:331
std::size_t numDofs() const
Returns the number of degrees of freedom.
Definition assembly/assembler.hh:295
void assembleResidual(ResidualType &r, const SolutionVector &curSol) const
assemble a residual r
Definition assembly/assembler.hh:227
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:134
GetPropType< TypeTag, Properties::SolutionVector > SolutionVector
Definition assembly/assembler.hh:96
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:111
void setTimeLoop(std::shared_ptr< const TimeLoop > timeLoop)
Set time loop for instationary problems.
Definition assembly/assembler.hh:338
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:254
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:345
const GridView & gridView() const
The gridview.
Definition assembly/assembler.hh:311
GetPropType< TypeTag, Properties::Problem > Problem
Definition assembly/assembler.hh:104
void assembleJacobian(const SolutionVector &curSol)
Assembles only the global Jacobian of the residual.
Definition assembly/assembler.hh:192
JacobianMatrix & jacobian()
The jacobian matrix.
Definition assembly/assembler.hh:323
bool isStationaryProblem() const
Whether we are assembling a stationary or instationary problem.
Definition assembly/assembler.hh:351
const GridVariables & gridVariables() const
The global grid variables.
Definition assembly/assembler.hh:319
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition assembly/assembler.hh:274
GetPropType< TypeTag, Properties::JacobianMatrix > JacobianMatrix
Definition assembly/assembler.hh:95
const GridDiscretization & gridGeometry() const
support old interfaces
Definition assembly/assembler.hh:307
GridVariables & gridVariables()
Definition assembly/assembler.hh:315
void resetTimeStep(const SolutionVector &curSol)
Reset the gridVariables.
Definition assembly/assembler.hh:371
const Problem & problem() const
Definition assembly/assembler.hh:299
An assembler for Jacobian and residual contribution per element (CVFE methods).
Definition experimental/assembly/cvfelocalassembler.hh:327
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 cvfe/hybrid/elementvariables.hh:31
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