version 3.10-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-FileCopyrightInfo: 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 visited_.assign(wasSwitched_.size(), false);
83 std::size_t countSwitched = 0;
84
85 auto fvGeometry = localView(gridGeometry);
86 auto elemVolVars = localView(gridVariables.curGridVolVars());
87
88 for (const auto& element : elements(gridGeometry.gridView()))
89 {
90 // make sure FVElementGeometry is bound to the element
91 fvGeometry.bindElement(element);
92 elemVolVars.bindElement(element, fvGeometry, curSol);
93
94 const auto curElemSol = elementSolution(element, curSol, gridGeometry);
95 for (auto&& scv : scvs(fvGeometry))
96 {
97 if (!asImp_().skipDof_(element, fvGeometry, scv, problem))
98 {
99 const auto dofIdxGlobal = scv.dofIndex();
100 // Note this implies that volume variables don't differ
101 // in any sub control volume associated with the dof!
102 visited_[dofIdxGlobal] = true;
103 // Compute volVars on which grounds we decide
104 // if we need to switch the primary variables
105 auto& volVars = getVolVarAccess_(gridVariables.curGridVolVars(), elemVolVars, scv);
106 volVars.update(curElemSol, problem, element, scv);
107
108 if (asImp_().update_(curSol[dofIdxGlobal], volVars, dofIdxGlobal, scv.dofPosition()))
109 {
110 switched = true;
111 ++countSwitched;
112 }
113 }
114 }
115 }
116
117 if (verbosity_ > 0 && countSwitched > 0)
118 std::cout << "Switched primary variables at " << countSwitched << " dof locations on processor "
119 << gridGeometry.gridView().comm().rank() << "." << std::endl;
120
121 // make sure that if there was a variable switch in an
122 // other partition we will also set the switch flag for our partition.
123 if (gridGeometry.gridView().comm().size() > 1)
124 switched = gridGeometry.gridView().comm().max(switched);
125
126 return switched;
127 }
128
135 template<class Problem, class GridVariables, class SolutionVector>
136 void updateSwitchedVolVars(const Problem& problem,
137 const typename GridVariables::GridGeometry::GridView::template Codim<0>::Entity& element,
138 const typename GridVariables::GridGeometry& gridGeometry,
139 GridVariables& gridVariables,
140 const SolutionVector& sol)
141 {
142 if constexpr (GridVariables::GridVolumeVariables::cachingEnabled)
143 {
144 // make sure FVElementGeometry is bound to the element
145 const auto fvGeometry = localView(gridGeometry).bindElement(element);
146
147 // update the secondary variables if global caching is enabled
148 for (auto&& scv : scvs(fvGeometry))
149 {
150 const auto dofIdxGlobal = scv.dofIndex();
151 if (asImp_().wasSwitched(dofIdxGlobal))
152 {
153 const auto elemSol = elementSolution(element, sol, gridGeometry);
154 auto& volVars = gridVariables.curGridVolVars().volVars(scv);
155 volVars.update(elemSol, problem, element, scv);
156 }
157 }
158 }
159 }
160
167 template<class Problem, class GridVariables, class SolutionVector>
168 void updateSwitchedFluxVarsCache(const Problem& problem,
169 const typename GridVariables::GridGeometry::GridView::template Codim<0>::Entity& element,
170 const typename GridVariables::GridGeometry& gridGeometry,
171 GridVariables& gridVariables,
172 const SolutionVector& sol)
173 {
174 if constexpr (GridVariables::GridFluxVariablesCache::cachingEnabled
175 && GridVariables::GridGeometry::discMethod != DiscretizationMethods::box)
176 {
177 // update the flux variables if global caching is enabled
178 const auto dofIdxGlobal = gridGeometry.dofMapper().index(element);
179
180 if (asImp_().wasSwitched(dofIdxGlobal))
181 {
182 // make sure FVElementGeometry and the volume variables are bound
183 const auto fvGeometry = localView(gridGeometry).bind(element);
184 const auto curElemVolVars = localView(gridVariables.curGridVolVars()).bind(element, fvGeometry, sol);
185 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
186 }
187 }
188 }
189
195 template<class Problem, class GridVariables, class SolutionVector>
196 void updateDirichletConstraints(const Problem& problem,
197 const typename GridVariables::GridGeometry& gridGeometry,
198 GridVariables& gridVariables,
199 SolutionVector& sol)
200 {
201 if constexpr (GridVariables::GridGeometry::discMethod == DiscretizationMethods::box || Problem::enableInternalDirichletConstraints())
202 {
203 std::vector<bool> stateChanged(sol.size(), false);
204 std::size_t countChanged = 0;
205
206 for (const auto& element : elements(gridGeometry.gridView()))
207 {
208 const auto fvGeometry = localView(gridGeometry).bindElement(element);
209
210 // skip if the element is not at a boundary or if no internal Dirichlet constraints are set
211 if (!Problem::enableInternalDirichletConstraints() && !fvGeometry.hasBoundaryScvf())
212 continue;
213
214 const auto elemVolVars = localView(gridVariables.curGridVolVars()).bindElement(element, fvGeometry, sol);
215
216 for (const auto& scv : scvs(fvGeometry))
217 {
218 const auto dofIdx = scv.dofIndex();
219
220 if (stateChanged[dofIdx])
221 continue;
222
223 if constexpr (GridVariables::GridGeometry::discMethod == DiscretizationMethods::box)
224 {
225 if (gridGeometry.dofOnBoundary(dofIdx))
226 {
227 if (handleDirichletBoundaryCondition_(problem, element, scv, sol))
228 {
229 stateChanged[dofIdx] = true;
230 ++countChanged;
231 continue;
232 }
233 }
234 }
235
236 if constexpr (Problem::enableInternalDirichletConstraints())
237 {
238 if (handleInternalDirichletConstraint_(problem, element, scv, sol))
239 {
240 stateChanged[dofIdx] = true;
241 ++countChanged;
242 }
243 }
244 }
245
246 // update the volVars if caching is enabled
247 if constexpr (GridVariables::GridVolumeVariables::cachingEnabled)
248 {
249 if (countChanged > 0)
250 {
251 const auto curElemSol = elementSolution(element, sol, gridGeometry);
252 for (const auto& scv : scvs(fvGeometry))
253 {
254 if (stateChanged[scv.dofIndex()])
255 {
256 auto& volVars = getVolVarAccess_(gridVariables.curGridVolVars(), elemVolVars, scv);
257 volVars.update(curElemSol, problem, element, scv);
258 }
259 }
260 }
261 }
262 }
263
264 if (verbosity_ > 0 && countChanged > 0)
265 std::cout << "Changed primary variable states and solution values to Dirichlet states and values at " << countChanged << " dof locations on processor "
266 << gridGeometry.gridView().comm().rank() << "." << std::endl;
267 }
268 }
269
271 int verbosity() const
272 { return verbosity_; }
273
274protected:
275
277 Implementation &asImp_()
278 { return *static_cast<Implementation*>(this); }
279
281 const Implementation &asImp_() const
282 { return *static_cast<const Implementation*>(this); }
283
284 // Perform variable switch at a degree of freedom location
285 template<class VolumeVariables, class GlobalPosition>
286 bool update_(typename VolumeVariables::PrimaryVariables& priVars,
287 const VolumeVariables& volVars,
288 std::size_t dofIdxGlobal,
289 const GlobalPosition& globalPos)
290 {
291 // evaluate if the primary variable switch would switch
292 // to be implemented by the deriving class
293 DUNE_THROW(Dune::NotImplemented, "This model seems to use a primary variable switch but none is implemented!");
294 }
295
296 // Maybe skip the degree of freedom (do not switch variables at this dof)
297 template<class Geometry, class Problem>
298 bool skipDof_(const typename Geometry::GridGeometry::GridView::template Codim<0>::Entity& element,
299 const Geometry& fvGeometry,
300 const typename Geometry::SubControlVolume& scv,
301 const Problem& problem)
302 {
303 if (visited_[scv.dofIndex()])
304 return true;
305
306 if (isConstrainedDof_(element, fvGeometry, scv, problem))
307 return true;
308
309 return false;
310 }
311
312 template<class Geometry, class Problem>
313 bool isConstrainedDof_(const typename Geometry::GridGeometry::GridView::template Codim<0>::Entity& element,
314 const Geometry& fvGeometry,
315 const typename Geometry::SubControlVolume& scv,
316 const Problem& problem)
317 {
318 // Dofs can be only constrained when using the Box method or when imposing internal Dirichlet constraints
319 if constexpr (Geometry::GridGeometry::discMethod != DiscretizationMethods::box && !Problem::enableInternalDirichletConstraints())
320 return false;
321
322 // check for internally constrained Dofs
323 const auto isInternallyConstrainedDof = [&]()
324 {
325 if constexpr (!Problem::enableInternalDirichletConstraints())
326 return false;
327 else
328 {
329 const auto internalDirichletConstraints = problem.hasInternalDirichletConstraint(element, scv);
330 return internalDirichletConstraints.any();
331 }
332 };
333
334 if (isInternallyConstrainedDof())
335 return true;
336
337 // check for a Dirichlet BC when using the Box method
338 if constexpr (Geometry::GridGeometry::discMethod == DiscretizationMethods::box)
339 {
340 if (!fvGeometry.hasBoundaryScvf())
341 return false;
342
343 const auto dofIdx = scv.dofIndex();
344 if (!fvGeometry.gridGeometry().dofOnBoundary(dofIdx))
345 return false;
346
347 const auto bcTypes = problem.boundaryTypes(element, scv);
348 if (bcTypes.hasDirichlet())
349 return true;
350 }
351
352 return false;
353 }
354
355 template<class Problem, class Element, class SubControlVolume, class SolutionVector>
356 bool handleDirichletBoundaryCondition_(const Problem& problem,
357 const Element& element,
358 const SubControlVolume& scv,
359 SolutionVector& sol)
360 {
361 bool changed = false;
362 const auto bcTypes = problem.boundaryTypes(element, scv);
363 if (bcTypes.hasDirichlet())
364 {
365 const auto dirichletValues = problem.dirichlet(element, scv);
366 const auto dofIdx = scv.dofIndex();
367
368 if (sol[dofIdx].state() != dirichletValues.state())
369 {
370 if (verbosity() > 1)
371 std::cout << "Changing primary variable state at boundary (" << sol[dofIdx].state()
372 << ") to the one given by the Dirichlet condition (" << dirichletValues.state() << ") at dof " << dofIdx
373 << ", coordinates: " << scv.dofPosition()
374 << std::endl;
375
376 // make sure the solution vector has the right state (given by the Dirichlet BC)
377 sol[dofIdx].setState(dirichletValues.state());
378 changed = true;
379
380 // overwrite initial with Dirichlet values
381 for (int eqIdx = 0; eqIdx < SolutionVector::block_type::dimension; ++eqIdx)
382 {
383 if (bcTypes.isDirichlet(eqIdx))
384 {
385 const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
386 sol[dofIdx][pvIdx] = dirichletValues[pvIdx];
387 }
388 }
389 }
390 }
391
392 return changed;
393 }
394
395 template<class Problem, class Element, class SubControlVolume, class SolutionVector>
396 bool handleInternalDirichletConstraint_(const Problem& problem,
397 const Element& element,
398 const SubControlVolume& scv,
399 SolutionVector& sol)
400 {
401 bool changed = false;
402
403 const auto internalDirichletConstraints = problem.hasInternalDirichletConstraint(element, scv);
404 if (internalDirichletConstraints.none())
405 return changed;
406
407 const auto dirichletValues = problem.internalDirichlet(element, scv);
408 const auto dofIdx = scv.dofIndex();
409
410 if (sol[dofIdx].state() != dirichletValues.state())
411 {
412 if (verbosity() > 1)
413 std::cout << "Changing primary variable state at internal DOF (" << sol[dofIdx].state()
414 << ") to the one given by the internal Dirichlet constraint (" << dirichletValues.state() << ") at dof " << dofIdx
415 << ", coordinates: " << scv.dofPosition()
416 << std::endl;
417
418 // make sure the solution vector has the right state (given by the Dirichlet constraint)
419 sol[dofIdx].setState(dirichletValues.state());
420 changed = true;
421
422 // overwrite initial with Dirichlet values
423 for (int pvIdx = 0; pvIdx < SolutionVector::block_type::dimension; ++pvIdx)
424 {
425 if (internalDirichletConstraints[pvIdx])
426 sol[dofIdx][pvIdx] = dirichletValues[pvIdx];
427 }
428 }
429
430 return changed;
431 }
432
433 std::vector<bool> wasSwitched_;
434 std::vector<bool> visited_;
435
436private:
437 template<class GridVolumeVariables, class ElementVolumeVariables, class SubControlVolume>
438 typename GridVolumeVariables::VolumeVariables&
439 getVolVarAccess_(GridVolumeVariables& gridVolVars, ElementVolumeVariables& elemVolVars, const SubControlVolume& scv) const
440 {
441 if constexpr (GridVolumeVariables::cachingEnabled)
442 return gridVolVars.volVars(scv);
443 else
444 return elemVolVars[scv];
445 }
446
447 int verbosity_;
448};
449
450} // end namespace dumux
451
452#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
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:433
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:136
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:313
bool handleDirichletBoundaryCondition_(const Problem &problem, const Element &element, const SubControlVolume &scv, SolutionVector &sol)
Definition: compositional/primaryvariableswitch.hh:356
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:396
Implementation & asImp_()
Return actual implementation (static polymorphism)
Definition: compositional/primaryvariableswitch.hh:277
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:196
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:298
const Implementation & asImp_() const
Return actual implementation (static polymorphism)
Definition: compositional/primaryvariableswitch.hh:281
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:271
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:286
std::vector< bool > visited_
Definition: compositional/primaryvariableswitch.hh:434
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:168
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