version 3.11-dev
Loading...
Searching...
No Matches
multistagefvassembler.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//
13#ifndef DUMUX_EXPERIMENTAL_MULTISTAGE_FV_ASSEMBLER_HH
14#define DUMUX_EXPERIMENTAL_MULTISTAGE_FV_ASSEMBLER_HH
15
16#include <vector>
17#include <deque>
18#include <type_traits>
19#include <memory>
20
21#include <dune/istl/matrixindexset.hh>
22
26
30
34
37
41
44
46
47template<class DiscretizationMethod>
49
50template<class DM>
51struct LocalAssemblerChooser<DiscretizationMethods::CVFE<DM>>
52{
53 template<class TypeTag, class Impl, DiffMethod diffMethod>
55};
56
57template<>
59{
60 template<class TypeTag, class Impl, DiffMethod diffMethod>
62};
63
64template<>
66{
67 template<class TypeTag, class Impl, DiffMethod diffMethod>
69};
70
71template<class TypeTag, class Impl, DiffMethod diffMethod>
74>::template type<TypeTag, Impl, diffMethod>;
75
76} // end namespace Dumux::Detail
77
78namespace Dumux::Experimental {
79
87template<class TypeTag, DiffMethod diffMethod>
89{
91 using GridView = typename GridGeo::GridView;
93 using Element = typename GridView::template Codim<0>::Entity;
94 using ElementSeed = typename GridView::Grid::template Codim<0>::EntitySeed;
95
96 static constexpr bool isBox = GridGeo::discMethod == DiscretizationMethods::box;
97
100
101public:
107
109
110 using GridGeometry = GridGeo;
112
118 MultiStageFVAssembler(std::shared_ptr<const Problem> problem,
119 std::shared_ptr<const GridGeometry> gridGeometry,
120 std::shared_ptr<GridVariables> gridVariables,
121 std::shared_ptr<const Experimental::MultiStageMethod<Scalar>> msMethod,
122 const SolutionVector& prevSol)
123 : timeSteppingMethod_(msMethod)
124 , problem_(problem)
125 , gridGeometry_(gridGeometry)
126 , gridVariables_(gridVariables)
127 , prevSol_(&prevSol)
128 {
130 && Grid::Capabilities::supportsMultithreading(gridGeometry_->gridView())
132 && getParam<bool>("Assembly.Multithreading", true);
133
134 maybeComputeColors_();
135 }
136
141 template<class PartialReassembler = DefaultPartialReassembler>
142 void assembleJacobianAndResidual(const SolutionVector& curSol, const PartialReassembler* partialReassembler = nullptr)
143 {
144 resetJacobian_(partialReassembler);
145
146 resetResidual_();
147 spatialOperatorEvaluations_.back() = 0.0;
148 temporalOperatorEvaluations_.back() = 0.0;
149
150 if (stageParams_->size() != spatialOperatorEvaluations_.size())
151 DUNE_THROW(Dune::InvalidStateException, "Wrong number of residuals");
152
153 assemble_([&](const Element& element)
154 {
155 LocalAssembler localAssembler(*this, element, curSol);
156 localAssembler.assembleJacobianAndResidual(
157 *jacobian_, *residual_, *gridVariables_,
158 *stageParams_,
159 temporalOperatorEvaluations_.back(),
160 spatialOperatorEvaluations_.back(),
161 constrainedDofs_,
162 partialReassembler
163 );
164 });
165
166 // Autonomous spatial operator: finalize the previous stage's stored evaluation for
167 // free. On the first assembly of this stage, curSol is the converged previous-stage
168 // solution and the value just assembled into the current slot equals R/M at that
169 // solution; time-independence makes the stage time irrelevant, so a copy suffices
170 // (no extra evaluation, no dependence on the solver re-assembling at convergence).
171 const auto curStage = stageParams_->size() - 1;
172 if (curStage > 1 && autonomousSpatialOperator_ && firstStageAssembly_)
173 {
174 spatialOperatorEvaluations_[curStage-1] = spatialOperatorEvaluations_.back();
175 temporalOperatorEvaluations_[curStage-1] = temporalOperatorEvaluations_.back();
176 }
177 firstStageAssembly_ = false;
178
179 // assemble the full residual for the time integration stage
180 auto constantResidualComponent = (*residual_);
181 constantResidualComponent = 0.0;
182 for (std::size_t k = 0; k < stageParams_->size()-1; ++k)
183 {
184 if (!stageParams_->skipTemporal(k))
185 constantResidualComponent.axpy(stageParams_->temporalWeight(k), temporalOperatorEvaluations_[k]);
186 if (!stageParams_->skipSpatial(k))
187 constantResidualComponent.axpy(stageParams_->spatialWeight(k), spatialOperatorEvaluations_[k]);
188 }
189
190 // masked summation of constant residual component onto this stage's resiudal component
191 for (std::size_t i = 0; i < constantResidualComponent.size(); ++i)
192 for (std::size_t ii = 0; ii < constantResidualComponent[i].size(); ++ii)
193 (*residual_)[i][ii] += constrainedDofs_[i][ii] > 0.5 ? 0.0 : constantResidualComponent[i][ii];
194 }
195
198 { DUNE_THROW(Dune::NotImplemented, "residual"); }
199
205 {
206 jacobian_ = std::make_shared<JacobianMatrix>();
207 jacobian_->setBuildMode(JacobianMatrix::random);
208 residual_ = std::make_shared<ResidualType>();
209
210 setResidualSize_(*residual_);
211 setJacobianPattern_();
212 }
213
218 {
219 setResidualSize_(*residual_);
220 setJacobianPattern_();
221 maybeComputeColors_();
222 }
223
225 std::size_t numDofs() const
226 { return gridGeometry_->numDofs(); }
227
229 const Problem& problem() const
230 { return *problem_; }
231
234 { return *gridGeometry_; }
235
237 const GridView& gridView() const
238 { return gridGeometry().gridView(); }
239
242 { return *gridVariables_; }
243
246 { return *gridVariables_; }
247
250 { return *jacobian_; }
251
254 { return *residual_; }
255
257 const SolutionVector& prevSol() const
258 { return *prevSol_; }
259
264 { return { LocalResidual{problem_.get(), nullptr} }; }
265
270 { gridVariables().update(cursol); }
271
275 void resetTimeStep(const SolutionVector &cursol)
276 {
277 gridVariables().resetTimeStep(cursol);
278 this->clearStages();
279 }
280
282 {
283 spatialOperatorEvaluations_.clear();
284 temporalOperatorEvaluations_.clear();
285 stageParams_.reset();
286 }
287
288 template<class StageParams>
290 {
291 stageParams_ = std::move(params);
292 const auto curStage = stageParams_->size() - 1;
293 firstStageAssembly_ = true;
294
295 // in the first stage, also assemble the residual
296 // at the previous time level (stage 0 residual)
297 if (curStage == 1)
298 {
299 // update time in variables?
300 setProblemTime_(*problem_, stageParams_->timeAtStage(0));
301
302 resetResidual_(); // residual resized and zero
303
304 assert(spatialOperatorEvaluations_.size() >= 0);
305 if (spatialOperatorEvaluations_.size() == 0)
306 {
307 spatialOperatorEvaluations_.push_back(*residual_);
308 temporalOperatorEvaluations_.push_back(*residual_);
309
310 // assemble stage 0 residuals
311 assemble_([&](const auto& element)
312 {
313 LocalAssembler localAssembler(*this, element, *prevSol_);
314 localAssembler.localResidual().spatialWeight(1.0);
315 localAssembler.localResidual().temporalWeight(1.0);
316 localAssembler.assembleCurrentResidual(spatialOperatorEvaluations_.back(), temporalOperatorEvaluations_.back());
317 });
318 }
319
320 // we don't delete the first stage so it can be reused in a restarted
321 // time integration step. The evaluations are only deleted
322 // when explicitly requested by calling clearStages().
323 // So if here the vector is non-empty, we don't need to evaluate again
324 // (this should only occur if we are restarting time integration, e.g.
325 // with a different time step size)
326 else if (spatialOperatorEvaluations_.size() > 0)
327 {
329 spatialOperatorEvaluations_.resize(1);
330 temporalOperatorEvaluations_.resize(1);
331 }
332 }
333
334 // Non-autonomous spatial operator: the constant residual component reuses each previous
335 // stage's operators at its *converged* solution. During the stage solve the residual
336 // assembly stored them at the solver's last iterate — correct for solvers that re-assemble
337 // at the converged solution (e.g. NewtonSolver), but stale for single-assembly solvers
338 // (e.g. LinearPDESolver). So we re-evaluate here at the converged solution and the previous
339 // stage's time level (which matters for time-dependent operators), making multi-stage
340 // schemes correct for any solver. This is one extra residual (no Jacobian) evaluation per
341 // stage; it is skipped entirely for an autonomous operator, where the value is instead
342 // reused for free in assembleJacobianAndResidual (see setAutonomousSpatialOperator).
343 if (curStage > 1 && !autonomousSpatialOperator_)
344 {
345 setProblemTime_(*problem_, stageParams_->timeAtStage(curStage-1));
346 spatialOperatorEvaluations_.back() = 0.0;
347 temporalOperatorEvaluations_.back() = 0.0;
348 assemble_([&](const auto& element)
349 {
350 LocalAssembler localAssembler(*this, element, x);
351 localAssembler.localResidual().spatialWeight(1.0);
352 localAssembler.localResidual().temporalWeight(1.0);
353 localAssembler.assembleCurrentResidual(spatialOperatorEvaluations_.back(), temporalOperatorEvaluations_.back());
354 });
355 }
356
357 // update time in variables?
358 setProblemTime_(*problem_, stageParams_->timeAtStage(curStage));
359
360 resetResidual_(); // residual resized and zero
361
362 if (spatialOperatorEvaluations_.size() != curStage)
363 DUNE_THROW(Dune::InvalidStateException,
364 "Invalid state. Maybe you forgot to call clearStages()");
365
366 // allocate memory for this stage
367 spatialOperatorEvaluations_.push_back(*residual_);
368 temporalOperatorEvaluations_.push_back(*residual_);
369 }
370
373 { return false; }
374
375 bool isImplicit() const
376 { return timeSteppingMethod_->implicit(); }
377
387 { autonomousSpatialOperator_ = a; }
388
389private:
393 void setJacobianPattern_()
394 {
395 // resize the jacobian and the residual
396 const auto numDofs = this->numDofs();
397 jacobian_->setSize(numDofs, numDofs);
398
399 // create occupation pattern of the jacobian
400 if (timeSteppingMethod_->implicit())
401 getJacobianPattern<true>(gridGeometry()).exportIdx(*jacobian_);
402 else
403 getJacobianPattern<false>(gridGeometry()).exportIdx(*jacobian_);
404 }
405
407 void setResidualSize_(ResidualType& res)
408 { res.resize(numDofs()); }
409
411 void maybeComputeColors_()
412 {
413 if (enableMultithreading_)
414 elementSets_ = computeColoring(gridGeometry()).sets;
415 }
416
417 // reset the residual vector to 0.0
418 void resetResidual_()
419 {
420 if(!residual_)
421 {
422 residual_ = std::make_shared<ResidualType>();
423 setResidualSize_(*residual_);
424 }
425
426 setResidualSize_(constrainedDofs_);
427
428 (*residual_) = 0.0;
429 constrainedDofs_ = 0.0;
430 }
431
432 // reset the Jacobian matrix to 0.0
433 template <class PartialReassembler = DefaultPartialReassembler>
434 void resetJacobian_(const PartialReassembler *partialReassembler = nullptr)
435 {
436 if(!jacobian_)
437 {
438 jacobian_ = std::make_shared<JacobianMatrix>();
439 jacobian_->setBuildMode(JacobianMatrix::random);
440 setJacobianPattern_();
441 }
442
443 if (partialReassembler)
444 partialReassembler->resetJacobian(*this);
445 else
446 *jacobian_ = 0.0;
447 }
448
454 template<typename AssembleElementFunc>
455 void assemble_(AssembleElementFunc&& assembleElement) const
456 {
457 // a state that will be checked on all processes
458 bool succeeded = false;
459
460 // try assembling using the local assembly function
461 try
462 {
463 if (enableMultithreading_)
464 {
465 assert(elementSets_.size() > 0);
466
467 // make this element loop run in parallel
468 // for this we have to color the elements so that we don't get
469 // race conditions when writing into the global matrix
470 // each color can be assembled using multiple threads
471 for (const auto& elements : elementSets_)
472 {
473 Dumux::parallelFor(elements.size(), [&](const std::size_t i)
474 {
475 const auto element = gridView().grid().entity(elements[i]);
476 assembleElement(element);
477 });
478 }
479 }
480 else
481 for (const auto& element : elements(gridView()))
482 assembleElement(element);
483
484 // if we get here, everything worked well on this process
485 succeeded = true;
486 }
487 // throw exception if a problem occurred
488 catch (NumericalProblem &e)
489 {
490 std::cout << "rank " << gridView().comm().rank()
491 << " caught an exception while assembling:" << e.what()
492 << "\n";
493 succeeded = false;
494 }
495
496 // make sure everything worked well on all processes
497 if (gridView().comm().size() > 1)
498 succeeded = gridView().comm().min(succeeded);
499
500 // if not succeeded rethrow the error on all processes
501 if (!succeeded)
502 DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system");
503 }
504
505 template<class P>
506 void setProblemTime_(const P& p, const Scalar t)
507 {
508 if constexpr (requires { p.setTime(t); })
509 p.setTime(t);
510 else
511 static_assert(!requires (P& q) { q.setTime(Scalar{}); },
512 "The multi-stage assembler sets the stage time through a const problem: setTime has to be const.");
513 }
514
515 std::shared_ptr<const Experimental::MultiStageMethod<Scalar>> timeSteppingMethod_;
516 std::vector<ResidualType> spatialOperatorEvaluations_;
517 std::vector<ResidualType> temporalOperatorEvaluations_;
518 ResidualType constrainedDofs_;
519 std::shared_ptr<const StageParams> stageParams_;
520
522 std::shared_ptr<const Problem> problem_;
523
525 std::shared_ptr<const GridGeometry> gridGeometry_;
526
528 std::shared_ptr<GridVariables> gridVariables_;
529
531 const SolutionVector* prevSol_ = nullptr;
532
534 std::shared_ptr<JacobianMatrix> jacobian_;
535 std::shared_ptr<ResidualType> residual_;
536
538 bool autonomousSpatialOperator_ = false;
539
541 bool firstStageAssembly_ = false;
542
544 bool enableMultithreading_ = false;
545 std::deque<std::vector<ElementSeed>> elementSets_;
546};
547
548} // namespace Dumux
549
550#endif
An assembler for Jacobian and residual contribution per element (cell-centered methods).
Definition experimental/assembly/cclocalassembler.hh:186
An assembler for Jacobian and residual contribution per element (CVFE methods).
Definition experimental/assembly/cvfelocalassembler.hh:330
const Problem & problem() const
The problem.
Definition multistagefvassembler.hh:229
void assembleResidual(const SolutionVector &curSol)
compute the residuals using the internal residual
Definition multistagefvassembler.hh:197
std::size_t numDofs() const
Returns the number of degrees of freedom.
Definition multistagefvassembler.hh:225
MultiStageFVLocalOperator< LocalResidual > localResidual() const
Create a local residual object (used by the local assembler).
Definition multistagefvassembler.hh:263
void setAutonomousSpatialOperator(bool a)
Definition multistagefvassembler.hh:386
typename Dumux::Detail::NativeDuneVectorType< SolutionVector >::type ResidualType
Definition multistagefvassembler.hh:106
void resetTimeStep(const SolutionVector &cursol)
Reset the gridVariables.
Definition multistagefvassembler.hh:275
GetPropType< TypeTag, Properties::JacobianMatrix > JacobianMatrix
Definition multistagefvassembler.hh:104
ResidualType & residual()
The residual vector (rhs).
Definition multistagefvassembler.hh:253
void clearStages()
Definition multistagefvassembler.hh:281
MultiStageFVAssembler(std::shared_ptr< const Problem > problem, std::shared_ptr< const GridGeometry > gridGeometry, std::shared_ptr< GridVariables > gridVariables, std::shared_ptr< const Experimental::MultiStageMethod< Scalar > > msMethod, const SolutionVector &prevSol)
The constructor for instationary problems.
Definition multistagefvassembler.hh:118
bool isStationaryProblem() const
TODO get rid of this (called by Newton but shouldn't be necessary).
Definition multistagefvassembler.hh:372
Experimental::MultiStageParams< Scalar > StageParams
Definition multistagefvassembler.hh:103
void setLinearSystem()
The version without arguments uses the default constructor to create the jacobian and residual object...
Definition multistagefvassembler.hh:204
void prepareStage(SolutionVector &x, StageParams params)
Definition multistagefvassembler.hh:289
GetPropType< TypeTag, Properties::GridVariables > GridVariables
Definition multistagefvassembler.hh:108
void updateAfterGridAdaption()
Resizes jacobian and residual and recomputes colors.
Definition multistagefvassembler.hh:217
const GridView & gridView() const
The gridview.
Definition multistagefvassembler.hh:237
GridGeo GridGeometry
Definition multistagefvassembler.hh:110
const SolutionVector & prevSol() const
The solution of the previous time step.
Definition multistagefvassembler.hh:257
GridVariables & gridVariables()
The global grid variables.
Definition multistagefvassembler.hh:241
GetPropType< TypeTag, Properties::Problem > Problem
Definition multistagefvassembler.hh:111
void updateGridVariables(const SolutionVector &cursol)
Update the grid variables.
Definition multistagefvassembler.hh:269
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition multistagefvassembler.hh:102
GetPropType< TypeTag, Properties::SolutionVector > SolutionVector
Definition multistagefvassembler.hh:105
bool isImplicit() const
Definition multistagefvassembler.hh:375
const GridVariables & gridVariables() const
The global grid variables.
Definition multistagefvassembler.hh:245
void assembleJacobianAndResidual(const SolutionVector &curSol, const PartialReassembler *partialReassembler=nullptr)
Assembles the global Jacobian of the residual and the residual for the current solution.
Definition multistagefvassembler.hh:142
const GridGeometry & gridGeometry() const
The global finite volume geometry.
Definition multistagefvassembler.hh:233
JacobianMatrix & jacobian()
The jacobian matrix.
Definition multistagefvassembler.hh:249
Definition multistagefvlocaloperator.hh:23
Abstract interface for one-step multi-stage method parameters in Shu/Osher form.
Definition multistagemethods.hh:75
Data object for the parameters of a given stage.
Definition multistagetimestepper.hh:31
detects which entries in the Jacobian have to be recomputed
Definition partialreassembler.hh:418
Coloring schemes for shared-memory-parallel assembly.
Defines all properties used in Dumux.
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).
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: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.
A local operator wrapper for multi-stage time stepping schemes.
Parameters for different multistage time stepping methods.
A time stepper performing a single time step of a transient simulation.
Multithreading in Dumux.
Definition cellcentered/mpfa/elementvolumevariables.hh:24
Definition method.hh:20
constexpr Box box
Definition method.hh:176
Definition assembly/assembler.hh:44
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:36
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).
Provides a helper class for nonoverlapping decomposition.
typename NativeDuneVectorTypeImpl< V, Dune::Std::is_detected< Detail::DuneVectors::StateDetector, V >{} >::type type
Definition dunevectors.hh:57
Experimental::CCLocalAssembler< TypeTag, Impl, diffMethod > type
Definition multistagefvassembler.hh:61
Experimental::CCLocalAssembler< TypeTag, Impl, diffMethod > type
Definition multistagefvassembler.hh:68
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
Type traits to be used with vector types.