3.3.0
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
25#ifndef DUMUX_PRIMARY_VARIABLE_SWITCH_HH
26#define DUMUX_PRIMARY_VARIABLE_SWITCH_HH
27
28#include <iostream>
29
30#include <dune/common/exceptions.hh>
31#include <dune/common/fvector.hh>
34
35namespace Dumux {
36
42{
43public:
44 template<typename... Args>
46
47 template<typename... Args> void reset(Args&&...) {}
48 template<typename... Args> bool wasSwitched(Args&&...) const { return false; }
49 template<typename... Args> bool update(Args&&...) { return false; }
50 template<typename... Args> void updateSwitchedVolVars(Args&&...) {}
51 template<typename... Args> void updateSwitchedFluxVarsCache(Args&&...) {}
52};
53
58template<class Implementation>
60{
61public:
63 : verbosity_(verbosity)
64 {}
65
67 bool wasSwitched(std::size_t dofIdxGlobal) const
68 {
69 return wasSwitched_[dofIdxGlobal];
70 }
71
73 void reset(const std::size_t numDofs)
74 {
75 wasSwitched_.resize(numDofs, false);
76 }
77
86 template<class SolutionVector, class GridVariables, class Problem>
87 bool update(SolutionVector& curSol,
88 GridVariables& gridVariables,
89 const Problem& problem,
90 const typename GridVariables::GridGeometry& gridGeometry)
91 {
92 bool switched = false;
93 visited_.assign(wasSwitched_.size(), false);
94 std::size_t countSwitched = 0;
95 for (const auto& element : elements(gridGeometry.gridView()))
96 {
97 // make sure FVElementGeometry is bound to the element
98 auto fvGeometry = localView(gridGeometry);
99 fvGeometry.bindElement(element);
100
101 auto elemVolVars = localView(gridVariables.curGridVolVars());
102 elemVolVars.bindElement(element, fvGeometry, curSol);
103
104 const auto curElemSol = elementSolution(element, curSol, gridGeometry);
105 for (auto&& scv : scvs(fvGeometry))
106 {
107 if (!asImp_().skipDof_(element, fvGeometry, scv, problem))
108 {
109 const auto dofIdxGlobal = scv.dofIndex();
110 // Note this implies that volume variables don't differ
111 // in any sub control volume associated with the dof!
112 visited_[dofIdxGlobal] = true;
113 // Compute volVars on which grounds we decide
114 // if we need to switch the primary variables
115 auto& volVars = getVolVarAccess_(gridVariables.curGridVolVars(), elemVolVars, scv);
116 volVars.update(curElemSol, problem, element, scv);
117
118 if (asImp_().update_(curSol[dofIdxGlobal], volVars, dofIdxGlobal, scv.dofPosition()))
119 {
120 switched = true;
121 ++countSwitched;
122 }
123 }
124 }
125 }
126
127 if (verbosity_ > 0 && countSwitched > 0)
128 std::cout << "Switched primary variables at " << countSwitched << " dof locations on processor "
129 << gridGeometry.gridView().comm().rank() << "." << std::endl;
130
131 // make sure that if there was a variable switch in an
132 // other partition we will also set the switch flag for our partition.
133 if (gridGeometry.gridView().comm().size() > 1)
134 switched = gridGeometry.gridView().comm().max(switched);
135
136 return switched;
137 }
138
145 template<class Problem, class GridVariables, class SolutionVector>
146 void updateSwitchedVolVars(const Problem& problem,
147 const typename GridVariables::GridGeometry::GridView::template Codim<0>::Entity& element,
148 const typename GridVariables::GridGeometry& gridGeometry,
149 GridVariables& gridVariables,
150 const SolutionVector& sol)
151 {
152 if constexpr (GridVariables::GridVolumeVariables::cachingEnabled)
153 {
154 // make sure FVElementGeometry is bound to the element
155 auto fvGeometry = localView(gridGeometry);
156 fvGeometry.bindElement(element);
157
158 // update the secondary variables if global caching is enabled
159 for (auto&& scv : scvs(fvGeometry))
160 {
161 const auto dofIdxGlobal = scv.dofIndex();
162 if (asImp_().wasSwitched(dofIdxGlobal))
163 {
164 const auto elemSol = elementSolution(element, sol, gridGeometry);
165 auto& volVars = gridVariables.curGridVolVars().volVars(scv);
166 volVars.update(elemSol, problem, element, scv);
167 }
168 }
169 }
170 }
171
178 template<class Problem, class GridVariables, class SolutionVector>
179 void updateSwitchedFluxVarsCache(const Problem& problem,
180 const typename GridVariables::GridGeometry::GridView::template Codim<0>::Entity& element,
181 const typename GridVariables::GridGeometry& gridGeometry,
182 GridVariables& gridVariables,
183 const SolutionVector& sol)
184 {
185 if constexpr (GridVariables::GridFluxVariablesCache::cachingEnabled
186 && GridVariables::GridGeometry::discMethod != DiscretizationMethod::box)
187 {
188 // update the flux variables if global caching is enabled
189 const auto dofIdxGlobal = gridGeometry.dofMapper().index(element);
190
191 if (asImp_().wasSwitched(dofIdxGlobal))
192 {
193 // make sure FVElementGeometry and the volume variables are bound
194 auto fvGeometry = localView(gridGeometry);
195 fvGeometry.bind(element);
196 auto curElemVolVars = localView(gridVariables.curGridVolVars());
197 curElemVolVars.bind(element, fvGeometry, sol);
198 gridVariables.gridFluxVarsCache().updateElement(element, fvGeometry, curElemVolVars);
199 }
200 }
201 }
202
208 template<class Problem, class GridVariables, class SolutionVector>
209 [[deprecated("Use updateDirichletConstraints() instead. Will be remove after 3.3")]]
210 void updateBoundary(const Problem& problem,
211 const typename GridVariables::GridGeometry& gridGeometry,
212 GridVariables& gridVariables,
213 SolutionVector& sol)
214 {
215 updateDirichletConstraints(problem, gridGeometry, gridVariables, sol);
216 }
217
223 template<class Problem, class GridVariables, class SolutionVector>
224 void updateDirichletConstraints(const Problem& problem,
225 const typename GridVariables::GridGeometry& gridGeometry,
226 GridVariables& gridVariables,
227 SolutionVector& sol)
228 {
229 if constexpr (GridVariables::GridGeometry::discMethod == DiscretizationMethod::box || Problem::enableInternalDirichletConstraints())
230 {
231 std::vector<bool> stateChanged(sol.size(), false);
232 std::size_t countChanged = 0;
233
234 for (const auto& element : elements(gridGeometry.gridView()))
235 {
236 auto fvGeometry = localView(gridGeometry);
237 fvGeometry.bindElement(element);
238
239 // skip if the element is not at a boundary or if no internal Dirichlet constraints are set
240 if (!Problem::enableInternalDirichletConstraints() && !fvGeometry.hasBoundaryScvf())
241 continue;
242
243 auto elemVolVars = localView(gridVariables.curGridVolVars());
244 elemVolVars.bindElement(element, fvGeometry, sol);
245
246 for (const auto& scv : scvs(fvGeometry))
247 {
248 const auto dofIdx = scv.dofIndex();
249
250 if (stateChanged[dofIdx])
251 continue;
252
253 if constexpr (GridVariables::GridGeometry::discMethod == DiscretizationMethod::box)
254 {
255 if (gridGeometry.dofOnBoundary(dofIdx))
256 {
257 if (handleDirichletBoundaryCondition_(problem, element, scv, sol))
258 {
259 stateChanged[dofIdx] = true;
260 ++countChanged;
261 continue;
262 }
263 }
264 }
265
266 if constexpr (Problem::enableInternalDirichletConstraints())
267 {
268 if (handleInternalDirichletConstraint_(problem, element, scv, sol))
269 {
270 stateChanged[dofIdx] = true;
271 ++countChanged;
272 }
273 }
274 }
275
276 // update the volVars if caching is enabled
277 if constexpr (GridVariables::GridVolumeVariables::cachingEnabled)
278 {
279 if (countChanged > 0)
280 {
281 const auto curElemSol = elementSolution(element, sol, gridGeometry);
282 for (const auto& scv : scvs(fvGeometry))
283 {
284 if (stateChanged[scv.dofIndex()])
285 {
286 auto& volVars = getVolVarAccess_(gridVariables.curGridVolVars(), elemVolVars, scv);
287 volVars.update(curElemSol, problem, element, scv);
288 }
289 }
290 }
291 }
292 }
293
294 if (verbosity_ > 0 && countChanged > 0)
295 std::cout << "Changed primary variable states and solution values to Dirichlet states and values at " << countChanged << " dof locations on processor "
296 << gridGeometry.gridView().comm().rank() << "." << std::endl;
297 }
298 }
299
301 int verbosity() const
302 { return verbosity_; }
303
304protected:
305
307 Implementation &asImp_()
308 { return *static_cast<Implementation*>(this); }
309
311 const Implementation &asImp_() const
312 { return *static_cast<const Implementation*>(this); }
313
314 // Perform variable switch at a degree of freedom location
315 template<class VolumeVariables, class GlobalPosition>
316 bool update_(typename VolumeVariables::PrimaryVariables& priVars,
317 const VolumeVariables& volVars,
318 std::size_t dofIdxGlobal,
319 const GlobalPosition& globalPos)
320 {
321 // evaluate if the primary variable switch would switch
322 // to be implemented by the deriving class
323 DUNE_THROW(Dune::NotImplemented, "This model seems to use a primary variable switch but none is implemented!");
324 }
325
326 // Maybe skip the degree of freedom (do not switch variables at this dof)
327 template<class Geometry, class Problem>
328 bool skipDof_(const typename Geometry::GridGeometry::GridView::template Codim<0>::Entity& element,
329 const Geometry& fvGeometry,
330 const typename Geometry::SubControlVolume& scv,
331 const Problem& problem)
332 {
333 if (visited_[scv.dofIndex()])
334 return true;
335
336 if (isConstrainedDof_(element, fvGeometry, scv, problem))
337 return true;
338
339 return false;
340 }
341
342 template<class Geometry, class Problem>
343 bool isConstrainedDof_(const typename Geometry::GridGeometry::GridView::template Codim<0>::Entity& element,
344 const Geometry& fvGeometry,
345 const typename Geometry::SubControlVolume& scv,
346 const Problem& problem)
347 {
348 // Dofs can be only constrained when using the Box method or when imposing internal Dirichlet constraints
349 if constexpr (Geometry::GridGeometry::discMethod != DiscretizationMethod::box && !Problem::enableInternalDirichletConstraints())
350 return false;
351
352 // check for internally constrained Dofs
353 const auto isInternallyConstrainedDof = [&]()
354 {
355 if constexpr (!Problem::enableInternalDirichletConstraints())
356 return false;
357 else
358 {
359 const auto internalDirichletConstraints = problem.hasInternalDirichletConstraint(element, scv);
360 return internalDirichletConstraints.any();
361 }
362 };
363
364 if (isInternallyConstrainedDof())
365 return true;
366
367 // check for a Dirichlet BC when using the Box method
368 if constexpr (Geometry::GridGeometry::discMethod == DiscretizationMethod::box)
369 {
370 if (!fvGeometry.hasBoundaryScvf())
371 return false;
372
373 const auto dofIdx = scv.dofIndex();
374 if (!fvGeometry.gridGeometry().dofOnBoundary(dofIdx))
375 return false;
376
377 const auto bcTypes = problem.boundaryTypes(element, scv);
378 if (bcTypes.hasDirichlet())
379 return true;
380 }
381
382 return false;
383 }
384
385 template<class Problem, class Element, class SubControlVolume, class SolutionVector>
386 bool handleDirichletBoundaryCondition_(const Problem& problem,
387 const Element& element,
388 const SubControlVolume& scv,
389 SolutionVector& sol)
390 {
391 bool changed = false;
392 const auto bcTypes = problem.boundaryTypes(element, scv);
393 if (bcTypes.hasDirichlet())
394 {
395 const auto dirichletValues = problem.dirichlet(element, scv);
396 const auto dofIdx = scv.dofIndex();
397
398 if (sol[dofIdx].state() != dirichletValues.state())
399 {
400 if (verbosity() > 1)
401 std::cout << "Changing primary variable state at boundary (" << sol[dofIdx].state()
402 << ") to the one given by the Dirichlet condition (" << dirichletValues.state() << ") at dof " << dofIdx
403 << ", coordinates: " << scv.dofPosition()
404 << std::endl;
405
406 // make sure the solution vector has the right state (given by the Dirichlet BC)
407 sol[dofIdx].setState(dirichletValues.state());
408 changed = true;
409
410 // overwrite initial with Dirichlet values
411 for (int eqIdx = 0; eqIdx < SolutionVector::block_type::dimension; ++eqIdx)
412 {
413 if (bcTypes.isDirichlet(eqIdx))
414 {
415 const auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
416 sol[dofIdx][pvIdx] = dirichletValues[pvIdx];
417 }
418 }
419 }
420 }
421
422 return changed;
423 }
424
425 template<class Problem, class Element, class SubControlVolume, class SolutionVector>
426 bool handleInternalDirichletConstraint_(const Problem& problem,
427 const Element& element,
428 const SubControlVolume& scv,
429 SolutionVector& sol)
430 {
431 bool changed = false;
432
433 const auto internalDirichletConstraints = problem.hasInternalDirichletConstraint(element, scv);
434 if (internalDirichletConstraints.none())
435 return changed;
436
437 const auto dirichletValues = problem.internalDirichlet(element, scv);
438 const auto dofIdx = scv.dofIndex();
439
440 if (sol[dofIdx].state() != dirichletValues.state())
441 {
442 if (verbosity() > 1)
443 std::cout << "Changing primary variable state at internal DOF (" << sol[dofIdx].state()
444 << ") to the one given by the internal Dirichlet constraint (" << dirichletValues.state() << ") at dof " << dofIdx
445 << ", coordinates: " << scv.dofPosition()
446 << std::endl;
447
448 // make sure the solution vector has the right state (given by the Dirichlet constraint)
449 sol[dofIdx].setState(dirichletValues.state());
450 changed = true;
451
452 // overwrite initial with Dirichlet values
453 for (int pvIdx = 0; pvIdx < SolutionVector::block_type::dimension; ++pvIdx)
454 {
455 if (internalDirichletConstraints[pvIdx])
456 sol[dofIdx][pvIdx] = dirichletValues[pvIdx];
457 }
458 }
459
460 return changed;
461 }
462
463 std::vector<bool> wasSwitched_;
464 std::vector<bool> visited_;
465
466private:
467 template<class GridVolumeVariables, class ElementVolumeVariables, class SubControlVolume>
468 typename GridVolumeVariables::VolumeVariables&
469 getVolVarAccess_(GridVolumeVariables& gridVolVars, ElementVolumeVariables& elemVolVars, const SubControlVolume& scv) const
470 {
471 if constexpr (GridVolumeVariables::cachingEnabled)
472 return gridVolVars.volVars(scv);
473 else
474 return elemVolVars[scv];
475 }
476
477 int verbosity_;
478};
479
480} // end namespace dumux
481
482#endif
Element solution classes and factory functions.
The available discretization methods in Dumux.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:38
auto elementSolution(const Element &element, const SolutionVector &sol, const GridGeometry &gg) -> std::enable_if_t< GridGeometry::discMethod==DiscretizationMethod::box, BoxElementSolution< typename GridGeometry::LocalView, std::decay_t< decltype(std::declval< SolutionVector >()[0])> > >
Make an element solution for box schemes.
Definition: box/elementsolution.hh:115
Definition: adapt.hh:29
Empty class for models without pri var switch.
Definition: compositional/primaryvariableswitch.hh:42
void reset(Args &&...)
Definition: compositional/primaryvariableswitch.hh:47
void updateSwitchedVolVars(Args &&...)
Definition: compositional/primaryvariableswitch.hh:50
NoPrimaryVariableSwitch(Args &&...)
Definition: compositional/primaryvariableswitch.hh:45
bool wasSwitched(Args &&...) const
Definition: compositional/primaryvariableswitch.hh:48
bool update(Args &&...)
Definition: compositional/primaryvariableswitch.hh:49
void updateSwitchedFluxVarsCache(Args &&...)
Definition: compositional/primaryvariableswitch.hh:51
The primary variable switch controlling the phase presence state variable.
Definition: compositional/primaryvariableswitch.hh:60
bool wasSwitched(std::size_t dofIdxGlobal) const
If the primary variables were recently switched.
Definition: compositional/primaryvariableswitch.hh:67
std::vector< bool > wasSwitched_
Definition: compositional/primaryvariableswitch.hh:463
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:146
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:343
bool handleDirichletBoundaryCondition_(const Problem &problem, const Element &element, const SubControlVolume &scv, SolutionVector &sol)
Definition: compositional/primaryvariableswitch.hh:386
void updateBoundary(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:210
PrimaryVariableSwitch(int verbosity=1)
Definition: compositional/primaryvariableswitch.hh:62
bool handleInternalDirichletConstraint_(const Problem &problem, const Element &element, const SubControlVolume &scv, SolutionVector &sol)
Definition: compositional/primaryvariableswitch.hh:426
Implementation & asImp_()
Return actual implementation (static polymorphism)
Definition: compositional/primaryvariableswitch.hh:307
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:224
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:328
const Implementation & asImp_() const
Return actual implementation (static polymorphism)
Definition: compositional/primaryvariableswitch.hh:311
bool update(SolutionVector &curSol, GridVariables &gridVariables, const Problem &problem, const typename GridVariables::GridGeometry &gridGeometry)
Updates the variable switch / phase presence.
Definition: compositional/primaryvariableswitch.hh:87
int verbosity() const
The verbosity level.
Definition: compositional/primaryvariableswitch.hh:301
void reset(const std::size_t numDofs)
Reset all flags.
Definition: compositional/primaryvariableswitch.hh:73
bool update_(typename VolumeVariables::PrimaryVariables &priVars, const VolumeVariables &volVars, std::size_t dofIdxGlobal, const GlobalPosition &globalPos)
Definition: compositional/primaryvariableswitch.hh:316
std::vector< bool > visited_
Definition: compositional/primaryvariableswitch.hh:464
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:179