version 3.11-dev
compositional/primaryvariableswitch.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_PRIMARY_VARIABLE_SWITCH_HH
14#define DUMUX_PRIMARY_VARIABLE_SWITCH_HH
15
16#include <iostream>
17
18#include <dune/common/exceptions.hh>
19#include <dune/common/fvector.hh>
22
23namespace Dumux {
24
30{
31public:
32 template<typename... Args>
34
35 template<typename... Args> void reset(Args&&...) {}
36 template<typename... Args> bool wasSwitched(Args&&...) const { return false; }
37 template<typename... Args> bool update(Args&&...) { return false; }
38 template<typename... Args> void updateSwitchedVolVars(Args&&...) {}
39 template<typename... Args> void updateSwitchedFluxVarsCache(Args&&...) {}
40 template<typename... Args> void updateDirichletConstraints(Args&&...) {}
41};
42
47template<class Implementation>
49{
50public:
52 : verbosity_(verbosity)
53 {}
54
56 bool wasSwitched(std::size_t dofIdxGlobal) const
57 {
58 return wasSwitched_[dofIdxGlobal];
59 }
60
62 void reset(const std::size_t numDofs)
63 {
64 wasSwitched_.assign(numDofs, false);
65 }
66
75 template<class SolutionVector, class GridVariables, class Problem>
76 bool update(SolutionVector& curSol,
77 GridVariables& gridVariables,
78 const Problem& problem,
79 const typename GridVariables::GridGeometry& gridGeometry)
80 {
81 bool switched = false;
82 bool successfulUpdate = false;
83 const auto& comm = gridGeometry.gridView().comm();
84
85 try {
86 visited_.assign(wasSwitched_.size(), false);
87 std::size_t countSwitched = 0;
88
89 auto fvGeometry = localView(gridGeometry);
90 auto elemVolVars = localView(gridVariables.curGridVolVars());
91
92 for (const auto& element : elements(gridGeometry.gridView()))
93 {
94 // make sure FVElementGeometry is bound to the element
95 fvGeometry.bindElement(element);
96 elemVolVars.bindElement(element, fvGeometry, curSol);
97
98 const auto curElemSol = elementSolution(element, curSol, gridGeometry);
99 for (auto&& scv : scvs(fvGeometry))
100 {
101 if (!asImp_().skipDof_(element, fvGeometry, scv, problem))
102 {
103 const auto dofIdxGlobal = scv.dofIndex();
104 // Note this implies that volume variables don't differ
105 // in any sub control volume associated with the dof!
106 visited_[dofIdxGlobal] = true;
107 // Compute volVars on which grounds we decide
108 // if we need to switch the primary variables
109 auto& volVars = getVolVarAccess_(gridVariables.curGridVolVars(), elemVolVars, scv);
110 volVars.update(curElemSol, problem, element, scv);
111
112 if (asImp_().update_(curSol[dofIdxGlobal], volVars, dofIdxGlobal, scv.dofPosition()))
113 {
114 switched = true;
115 ++countSwitched;
116 }
117 }
118 }
119 }
120
121 if (verbosity_ > 0 && countSwitched > 0)
122 std::cout << "Switched primary variables at " << countSwitched << " dof locations on processor "
123 << comm.rank() << "." << std::endl;
124
125 successfulUpdate = true;
126 }
127 catch (const Dumux::NumericalProblem& e)
128 {
129 if (verbosity_ > 0)
130 std::cout << "Primary variable switch caught: \"" << e.what() << "\"\n";
131
132 successfulUpdate = false;
133 }
134
135 // make sure all processes were successful
136 int successfulUpdateRemote = static_cast<int>(successfulUpdate);
137 if (comm.size() > 1)
138 successfulUpdateRemote = comm.min(static_cast<int>(successfulUpdate));
139
140 if (!successfulUpdate)
141 DUNE_THROW(NumericalProblem, "Primary variable switch caught exception on process " << comm.rank());
142
143 else if (!successfulUpdateRemote)
144 DUNE_THROW(NumericalProblem, "Primary variable switch caught exception on a remote process");
145
146 // make sure that if there was a variable switch in an
147 // other partition we will also set the switch flag for our partition.
148 if (comm.size() > 1)
149 switched = comm.max(switched);
150
151 return switched;
152 }
153
160 template<class Problem, class GridVariables, class SolutionVector>
161 void updateSwitchedVolVars(const Problem& problem,
162 const typename GridVariables::GridGeometry::GridView::template Codim<0>::Entity& element,
163 const typename GridVariables::GridGeometry& gridGeometry,
164 GridVariables& gridVariables,
165 const SolutionVector& sol)
166 {
167 if constexpr (GridVariables::GridVolumeVariables::cachingEnabled)
168 {
169 // make sure FVElementGeometry is bound to the element
170 const auto fvGeometry = localView(gridGeometry).bindElement(element);
171
172 // update the secondary variables if global caching is enabled
173 for (auto&& scv : scvs(fvGeometry))
174 {
175 const auto dofIdxGlobal = scv.dofIndex();
176 if (asImp_().wasSwitched(dofIdxGlobal))
177 {
178 const auto elemSol = elementSolution(element, sol, gridGeometry);
179 auto& volVars = gridVariables.curGridVolVars().volVars(scv);
180 volVars.update(elemSol, problem, element, scv);
181 }
182 }
183 }
184 }
185
192 template<class Problem, class GridVariables, class SolutionVector>
193 void updateSwitchedFluxVarsCache(const Problem& problem,
194 const typename GridVariables::GridGeometry::GridView::template Codim<0>::Entity& element,
195 const typename GridVariables::GridGeometry& gridGeometry,
196 GridVariables& gridVariables,
197 const SolutionVector& sol)
198 {
199 if constexpr (GridVariables::GridFluxVariablesCache::cachingEnabled
200 && GridVariables::GridGeometry::discMethod != DiscretizationMethods::box)
201 {
202 // update the flux variables if global caching is enabled
203 const auto dofIdxGlobal = gridGeometry.dofMapper().index(element);
204
205 if (asImp_().wasSwitched(dofIdxGlobal))
206 {
207 // make sure FVElementGeometry and the volume variables are bound
208 const auto fvGeometry = localView(gridGeometry).bind(element);
209 const auto curElemVolVars = localView(gridVariables.curGridVolVars()).bind(element, fvGeometry, sol);
210 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
211 }
212 }
213 }
214
220 template<class Problem, class GridVariables, class SolutionVector>
221 void updateDirichletConstraints(const Problem& problem,
222 const typename GridVariables::GridGeometry& gridGeometry,
223 GridVariables& gridVariables,
224 SolutionVector& sol)
225 {
226 if constexpr (GridVariables::GridGeometry::discMethod == DiscretizationMethods::box || Problem::enableInternalDirichletConstraints())
227 {
228 std::vector<bool> stateChanged(sol.size(), false);
229 std::size_t countChanged = 0;
230
231 for (const auto& element : elements(gridGeometry.gridView()))
232 {
233 const auto fvGeometry = localView(gridGeometry).bindElement(element);
234
235 // skip if the element is not at a boundary or if no internal Dirichlet constraints are set
236 if (!Problem::enableInternalDirichletConstraints() && !fvGeometry.hasBoundaryScvf())
237 continue;
238
239 const auto elemVolVars = localView(gridVariables.curGridVolVars()).bindElement(element, fvGeometry, sol);
240
241 for (const auto& scv : scvs(fvGeometry))
242 {
243 const auto dofIdx = scv.dofIndex();
244
245 if (stateChanged[dofIdx])
246 continue;
247
248 if constexpr (GridVariables::GridGeometry::discMethod == DiscretizationMethods::box)
249 {
250 if (gridGeometry.dofOnBoundary(dofIdx))
251 {
252 if (handleDirichletBoundaryCondition_(problem, element, scv, sol))
253 {
254 stateChanged[dofIdx] = true;
255 ++countChanged;
256 continue;
257 }
258 }
259 }
260
261 if constexpr (Problem::enableInternalDirichletConstraints())
262 {
263 if (handleInternalDirichletConstraint_(problem, element, scv, sol))
264 {
265 stateChanged[dofIdx] = true;
266 ++countChanged;
267 }
268 }
269 }
270
271 // update the volVars if caching is enabled
272 if constexpr (GridVariables::GridVolumeVariables::cachingEnabled)
273 {
274 if (countChanged > 0)
275 {
276 const auto curElemSol = elementSolution(element, sol, gridGeometry);
277 for (const auto& scv : scvs(fvGeometry))
278 {
279 if (stateChanged[scv.dofIndex()])
280 {
281 auto& volVars = getVolVarAccess_(gridVariables.curGridVolVars(), elemVolVars, scv);
282 volVars.update(curElemSol, problem, element, scv);
283 }
284 }
285 }
286 }
287 }
288
289 if (verbosity_ > 0 && countChanged > 0)
290 std::cout << "Changed primary variable states and solution values to Dirichlet states and values at " << countChanged << " dof locations on processor "
291 << gridGeometry.gridView().comm().rank() << "." << std::endl;
292 }
293 }
294
296 int verbosity() const
297 { return verbosity_; }
298
299protected:
300
302 Implementation &asImp_()
303 { return *static_cast<Implementation*>(this); }
304
306 const Implementation &asImp_() const
307 { return *static_cast<const Implementation*>(this); }
308
309 // Perform variable switch at a degree of freedom location
310 template<class VolumeVariables, class GlobalPosition>
311 bool update_(typename VolumeVariables::PrimaryVariables& priVars,
312 const VolumeVariables& volVars,
313 std::size_t dofIdxGlobal,
314 const GlobalPosition& globalPos)
315 {
316 // evaluate if the primary variable switch would switch
317 // to be implemented by the deriving class
318 DUNE_THROW(Dune::NotImplemented, "This model seems to use a primary variable switch but none is implemented!");
319 }
320
321 // Maybe skip the degree of freedom (do not switch variables at this dof)
322 template<class Geometry, class Problem>
323 bool skipDof_(const typename Geometry::GridGeometry::GridView::template Codim<0>::Entity& element,
324 const Geometry& fvGeometry,
325 const typename Geometry::SubControlVolume& scv,
326 const Problem& problem)
327 {
328 if (visited_[scv.dofIndex()])
329 return true;
330
331 if (isConstrainedDof_(element, fvGeometry, scv, problem))
332 return true;
333
334 return false;
335 }
336
337 template<class Geometry, class Problem>
338 bool isConstrainedDof_(const typename Geometry::GridGeometry::GridView::template Codim<0>::Entity& element,
339 const Geometry& fvGeometry,
340 const typename Geometry::SubControlVolume& scv,
341 const Problem& problem)
342 {
343 // Dofs can be only constrained when using the Box method or when imposing internal Dirichlet constraints
344 if constexpr (Geometry::GridGeometry::discMethod != DiscretizationMethods::box && !Problem::enableInternalDirichletConstraints())
345 return false;
346
347 // check for internally constrained Dofs
348 const auto isInternallyConstrainedDof = [&]()
349 {
350 if constexpr (!Problem::enableInternalDirichletConstraints())
351 return false;
352 else
353 {
354 const auto internalDirichletConstraints = problem.hasInternalDirichletConstraint(element, scv);
355 return internalDirichletConstraints.any();
356 }
357 };
358
359 if (isInternallyConstrainedDof())
360 return true;
361
362 // check for a Dirichlet BC when using the Box method
363 if constexpr (Geometry::GridGeometry::discMethod == DiscretizationMethods::box)
364 {
365 if (!fvGeometry.hasBoundaryScvf())
366 return false;
367
368 const auto dofIdx = scv.dofIndex();
369 if (!fvGeometry.gridGeometry().dofOnBoundary(dofIdx))
370 return false;
371
372 const auto bcTypes = problem.boundaryTypes(element, scv);
373 if (bcTypes.hasDirichlet())
374 return true;
375 }
376
377 return false;
378 }
379
380 template<class Problem, class Element, class SubControlVolume, class SolutionVector>
381 bool handleDirichletBoundaryCondition_(const Problem& problem,
382 const Element& element,
383 const SubControlVolume& scv,
384 SolutionVector& sol)
385 {
386 bool changed = false;
387 const auto bcTypes = problem.boundaryTypes(element, scv);
388 if (bcTypes.hasDirichlet())
389 {
390 const auto dirichletValues = problem.dirichlet(element, scv);
391 const auto dofIdx = scv.dofIndex();
392
393 if (sol[dofIdx].state() != dirichletValues.state())
394 {
395 if (verbosity() > 1)
396 std::cout << "Changing primary variable state at boundary (" << sol[dofIdx].state()
397 << ") to the one given by the Dirichlet condition (" << dirichletValues.state() << ") at dof " << dofIdx
398 << ", coordinates: " << scv.dofPosition()
399 << std::endl;
400
401 // make sure the solution vector has the right state (given by the Dirichlet BC)
402 sol[dofIdx].setState(dirichletValues.state());
403 changed = true;
404
405 // overwrite initial with Dirichlet values
406 for (int eqIdx = 0; eqIdx < SolutionVector::block_type::dimension; ++eqIdx)
407 {
408 if (bcTypes.isDirichlet(eqIdx))
409 {
410 const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
411 sol[dofIdx][pvIdx] = dirichletValues[pvIdx];
412 }
413 }
414 }
415 }
416
417 return changed;
418 }
419
420 template<class Problem, class Element, class SubControlVolume, class SolutionVector>
421 bool handleInternalDirichletConstraint_(const Problem& problem,
422 const Element& element,
423 const SubControlVolume& scv,
424 SolutionVector& sol)
425 {
426 bool changed = false;
427
428 const auto internalDirichletConstraints = problem.hasInternalDirichletConstraint(element, scv);
429 if (internalDirichletConstraints.none())
430 return changed;
431
432 const auto dirichletValues = problem.internalDirichlet(element, scv);
433 const auto dofIdx = scv.dofIndex();
434
435 if (sol[dofIdx].state() != dirichletValues.state())
436 {
437 if (verbosity() > 1)
438 std::cout << "Changing primary variable state at internal DOF (" << sol[dofIdx].state()
439 << ") to the one given by the internal Dirichlet constraint (" << dirichletValues.state() << ") at dof " << dofIdx
440 << ", coordinates: " << scv.dofPosition()
441 << std::endl;
442
443 // make sure the solution vector has the right state (given by the Dirichlet constraint)
444 sol[dofIdx].setState(dirichletValues.state());
445 changed = true;
446
447 // overwrite initial with Dirichlet values
448 for (int pvIdx = 0; pvIdx < SolutionVector::block_type::dimension; ++pvIdx)
449 {
450 if (internalDirichletConstraints[pvIdx])
451 sol[dofIdx][pvIdx] = dirichletValues[pvIdx];
452 }
453 }
454
455 return changed;
456 }
457
458 std::vector<bool> wasSwitched_;
459 std::vector<bool> visited_;
460
461private:
462 template<class GridVolumeVariables, class ElementVolumeVariables, class SubControlVolume>
463 typename GridVolumeVariables::VolumeVariables&
464 getVolVarAccess_(GridVolumeVariables& gridVolVars, ElementVolumeVariables& elemVolVars, const SubControlVolume& scv) const
465 {
466 if constexpr (GridVolumeVariables::cachingEnabled)
467 return gridVolVars.volVars(scv);
468 else
469 return elemVolVars[scv];
470 }
471
472 int verbosity_;
473};
474
475} // end namespace dumux
476
477#endif
Empty class for models without pri var switch.
Definition: compositional/primaryvariableswitch.hh:30
void reset(Args &&...)
Definition: compositional/primaryvariableswitch.hh:35
void updateSwitchedVolVars(Args &&...)
Definition: compositional/primaryvariableswitch.hh:38
NoPrimaryVariableSwitch(Args &&...)
Definition: compositional/primaryvariableswitch.hh:33
bool wasSwitched(Args &&...) const
Definition: compositional/primaryvariableswitch.hh:36
bool update(Args &&...)
Definition: compositional/primaryvariableswitch.hh:37
void updateDirichletConstraints(Args &&...)
Definition: compositional/primaryvariableswitch.hh:40
void updateSwitchedFluxVarsCache(Args &&...)
Definition: compositional/primaryvariableswitch.hh:39
Exception thrown if a fixable numerical problem occurs.
Definition: exceptions.hh:27
The primary variable switch controlling the phase presence state variable.
Definition: compositional/primaryvariableswitch.hh:49
bool wasSwitched(std::size_t dofIdxGlobal) const
If the primary variables were recently switched.
Definition: compositional/primaryvariableswitch.hh:56
std::vector< bool > wasSwitched_
Definition: compositional/primaryvariableswitch.hh:458
void updateSwitchedVolVars(const Problem &problem, const typename GridVariables::GridGeometry::GridView::template Codim< 0 >::Entity &element, const typename GridVariables::GridGeometry &gridGeometry, GridVariables &gridVariables, const SolutionVector &sol)
Updates the volume variables whose primary variables were switched.
Definition: compositional/primaryvariableswitch.hh:161
bool isConstrainedDof_(const typename Geometry::GridGeometry::GridView::template Codim< 0 >::Entity &element, const Geometry &fvGeometry, const typename Geometry::SubControlVolume &scv, const Problem &problem)
Definition: compositional/primaryvariableswitch.hh:338
bool handleDirichletBoundaryCondition_(const Problem &problem, const Element &element, const SubControlVolume &scv, SolutionVector &sol)
Definition: compositional/primaryvariableswitch.hh:381
PrimaryVariableSwitch(int verbosity=1)
Definition: compositional/primaryvariableswitch.hh:51
bool handleInternalDirichletConstraint_(const Problem &problem, const Element &element, const SubControlVolume &scv, SolutionVector &sol)
Definition: compositional/primaryvariableswitch.hh:421
Implementation & asImp_()
Return actual implementation (static polymorphism)
Definition: compositional/primaryvariableswitch.hh:302
void updateDirichletConstraints(const Problem &problem, const typename GridVariables::GridGeometry &gridGeometry, GridVariables &gridVariables, SolutionVector &sol)
Updates the the primary variables state at the boundary.
Definition: compositional/primaryvariableswitch.hh:221
bool skipDof_(const typename Geometry::GridGeometry::GridView::template Codim< 0 >::Entity &element, const Geometry &fvGeometry, const typename Geometry::SubControlVolume &scv, const Problem &problem)
Definition: compositional/primaryvariableswitch.hh:323
const Implementation & asImp_() const
Return actual implementation (static polymorphism)
Definition: compositional/primaryvariableswitch.hh:306
bool update(SolutionVector &curSol, GridVariables &gridVariables, const Problem &problem, const typename GridVariables::GridGeometry &gridGeometry)
Updates the variable switch / phase presence.
Definition: compositional/primaryvariableswitch.hh:76
int verbosity() const
The verbosity level.
Definition: compositional/primaryvariableswitch.hh:296
void reset(const std::size_t numDofs)
Reset all flags.
Definition: compositional/primaryvariableswitch.hh:62
bool update_(typename VolumeVariables::PrimaryVariables &priVars, const VolumeVariables &volVars, std::size_t dofIdxGlobal, const GlobalPosition &globalPos)
Definition: compositional/primaryvariableswitch.hh:311
std::vector< bool > visited_
Definition: compositional/primaryvariableswitch.hh:459
void updateSwitchedFluxVarsCache(const Problem &problem, const typename GridVariables::GridGeometry::GridView::template Codim< 0 >::Entity &element, const typename GridVariables::GridGeometry &gridGeometry, GridVariables &gridVariables, const SolutionVector &sol)
Updates the fluxVars cache for dof whose primary variables were switched.
Definition: compositional/primaryvariableswitch.hh:193
Element solution classes and factory functions.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethods::cctpfa||GridGeometry::discMethod==DiscretizationMethods::ccmpfa, CCElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for cell-centered schemes.
Definition: cellcentered/elementsolution.hh:101
The available discretization methods in Dumux.
constexpr Box box
Definition: method.hh:147
Definition: adapt.hh:17
std::ranges::range auto scvs(const FVElementGeometry &fvGeometry, const LocalDof &localDof)
Definition: localdof.hh:79