12#ifndef DUMUX_PNM_2P_INVASIONSTATE_HH
13#define DUMUX_PNM_2P_INVASIONSTATE_HH
17#include <dune/common/std/type_traits.hh>
33 using GlobalCapillaryPressureDetector =
decltype(std::declval<T>().globalCapillaryPressure());
36 static constexpr bool hasGlobalCapillaryPressure()
37 {
return Dune::Std::is_detected<GlobalCapillaryPressureDetector, T>::value; }
39 enum class EventType {invasion, snapOff, none};
46 invadedCurrentIteration_.resize(problem.gridGeometry().gridView().size(0));
47 invadedPreviousTimeStep_.resize(problem.gridGeometry().gridView().size(0));
49 for (
auto&& element : elements(problem.gridGeometry().gridView()))
51 const auto eIdx = problem.gridGeometry().elementMapper().index(element);
52 invadedCurrentIteration_[eIdx] = problem.initialInvasionState(element);
53 invadedPreviousTimeStep_[eIdx] = invadedCurrentIteration_[eIdx];
56 numThroatsInvaded_ = std::count(invadedCurrentIteration_.begin(), invadedCurrentIteration_.end(),
true);
57 verbose_ = getParamFromGroup<bool>(problem.paramGroup(),
"InvasionState.Verbosity",
true);
58 restrictToGlobalCapillaryPressure_ = getParamFromGroup<bool>(problem.paramGroup(),
"InvasionState.RestrictInvasionToGlobalCapillaryPressure",
false);
60 if constexpr (hasGlobalCapillaryPressure<Problem>())
62 if (restrictToGlobalCapillaryPressure_)
63 std::cout <<
"\n *** Invasion behavior is restricted by a global capillary pressure defined in the problem! *** \n" << std::endl;
65 std::cout <<
"\n *** WARNING: global capillary pressure defined in the problem but InvasionState.RestrictInvasionToGlobalCapillaryPressure is set to false.\n"
66 <<
" Invasion behavior will NOT be restricted! ***\n" << std::endl;
71 template<
class Element>
72 bool invaded(
const Element& element)
const
74 const auto eIdx = problem_.gridGeometry().elementMapper().index(element);
75 return invadedCurrentIteration_[eIdx];
80 {
return numThroatsInvaded_; }
83 template<
class SolutionVector,
class Gr
idVolumeVariables,
class Gr
idFluxVariablesCache>
84 bool update(
const SolutionVector& sol,
const GridVolumeVariables& gridVolVars, GridFluxVariablesCache& gridFluxVarsCache)
86 hasChangedInCurrentIteration_ =
false;
87 auto fvGeometry =
localView(problem_.gridGeometry());
88 auto elemVolVars =
localView(gridVolVars);
89 auto elemFluxVarsCache =
localView(gridFluxVarsCache);
90 for (
auto&& element : elements(problem_.gridGeometry().gridView()))
92 fvGeometry.bindElement(element);
93 elemVolVars.bind(element, fvGeometry, sol);
94 elemFluxVarsCache.bind(element, fvGeometry, elemVolVars);
96 for (
auto&& scvf : scvfs(fvGeometry))
99 if (
const auto invasionResult = invasionSwitch_(element, elemVolVars, elemFluxVarsCache[scvf]); invasionResult)
101 hasChangedInCurrentIteration_ =
true;
102 if constexpr (GridFluxVariablesCache::cachingEnabled)
104 const auto eIdx = problem_.gridGeometry().elementMapper().index(element);
105 gridFluxVarsCache.cache(eIdx, scvf.index()).
update(problem_, element, fvGeometry, elemVolVars, scvf, invadedCurrentIteration_[eIdx]);
110 numThroatsInvaded_ = std::count(invadedCurrentIteration_.begin(), invadedCurrentIteration_.end(),
true);
111 return hasChangedInCurrentIteration_;
117 hasChangedInCurrentIteration_ =
false;
118 invadedCurrentIteration_ = invadedPreviousTimeStep_;
123 {
return hasChangedComparedToPreviousTimestep_; }
127 {
return hasChangedInCurrentIteration_; }
132 hasChangedComparedToPreviousTimestep_ = (invadedPreviousTimeStep_ != invadedCurrentIteration_);
133 invadedPreviousTimeStep_ = invadedCurrentIteration_;
136 template<
class SolutionVector,
class Gr
idVolumeVariables,
class Gr
idFluxVariablesCache>
138 const GridVolumeVariables& gridVolVars,
139 const GridFluxVariablesCache& gridFluxVarsCache)
const
141 using Scalar =
typename SolutionVector::block_type::value_type;
142 static const Scalar accuracyCriterion = getParamFromGroup<Scalar>(problem_.paramGroup(),
"InvasionState.AccuracyCriterion", -1.0);
144 if (accuracyCriterion < 0.0)
147 auto fvGeometry =
localView(problem_.gridGeometry());
148 auto elemVolVars =
localView(gridVolVars);
149 auto elemFluxVarsCache =
localView(gridFluxVarsCache);
150 for (
auto&& element : elements(problem_.gridGeometry().gridView()))
153 const auto eIdx = problem_.gridGeometry().elementMapper().index(element);
154 if (!invadedCurrentIteration_[eIdx] || invadedPreviousTimeStep_[eIdx] == invadedCurrentIteration_[eIdx])
157 fvGeometry.bindElement(element);
158 elemVolVars.bind(element, fvGeometry, sol);
159 elemFluxVarsCache.bind(element, fvGeometry, elemVolVars);
161 for (
auto&& scvf : scvfs(fvGeometry))
164 const auto& fluxVarsCache = elemFluxVarsCache[scvf];
169 if (pc < accuracyCriterion * fluxVarsCache.pcEntry())
170 DUNE_THROW(
NumericalProblem,
"At element " << eIdx <<
": pc " << pc <<
" too far away form pcEntry " << fluxVarsCache.pcEntry());
178 template<
class Element,
class ElementVolumeVariables,
class FluxVariablesCache>
179 auto invasionSwitch_(
const Element& element,
180 const ElementVolumeVariables& elemVolVars,
181 const FluxVariablesCache& fluxVarsCache)
184 using Scalar =
typename ElementVolumeVariables::VolumeVariables::PrimaryVariables::value_type;
185 const auto& gridGeometry = problem_.gridGeometry();
186 const auto& spatialParams = problem_.spatialParams();
187 const auto eIdx = gridGeometry.elementMapper().index(element);
188 bool invadedBeforeSwitch = invadedCurrentIteration_[eIdx];
189 bool invadedAfterSwitch = invadedBeforeSwitch;
195 std::uint8_t localScvIdxWithCriticalPc;
197 EventType
event = EventType::none;
199 operator bool()
const
200 {
return event != EventType::none; }
204 static const auto blockNonwettingPhase = getParamFromGroup<std::vector<int>>(problem_.paramGroup(),
"InvasionState.BlockNonwettingPhaseAtThroatLabel", std::vector<int>{});
205 if (!blockNonwettingPhase.empty() && std::find(blockNonwettingPhase.begin(), blockNonwettingPhase.end(), gridGeometry.throatLabel(eIdx)) != blockNonwettingPhase.end())
207 invadedCurrentIteration_[eIdx] =
false;
212 const std::array<Scalar, 2> pc = { elemVolVars[0].capillaryPressure(), elemVolVars[1].capillaryPressure() };
213 const auto pcMax = std::max_element(pc.begin(), pc.end());
214 const Scalar
pcEntry = fluxVarsCache.pcEntry();
215 const Scalar
pcSnapoff = fluxVarsCache.pcSnapoff();
218 if (maybeRestrictToGlobalCapillaryPressure_(
pcEntry))
222 std::cout <<
"Throat " << eIdx <<
" would have been invaded by pc of " << *pcMax <<
"but a global capillary pressure restricion was set in the problem.";
223 std::cout <<
". pcEntry: " << spatialParams.pcEntry(element, elemVolVars) << std::endl;
226 invadedCurrentIteration_[eIdx] =
false;
231 invadedAfterSwitch =
true;
233 invadedAfterSwitch =
false;
235 invadedCurrentIteration_[eIdx] = invadedAfterSwitch;
237 if (invadedBeforeSwitch == invadedAfterSwitch)
242 result.localScvIdxWithCriticalPc =
std::distance(pc.begin(), pcMax);
243 result.criticalPc = *pcMax;
244 result.event = !invadedBeforeSwitch && invadedAfterSwitch ? EventType::invasion : EventType::snapOff;
248 const auto wPhaseIdx = spatialParams.template wettingPhase<typename ElementVolumeVariables::VolumeVariables::FluidSystem>(element, elemVolVars);
249 const std::array sw = { elemVolVars[0].saturation(wPhaseIdx), elemVolVars[1].saturation(wPhaseIdx) };
250 const auto vIdx = gridGeometry.gridView().indexSet().subIndex(element, result.localScvIdxWithCriticalPc, 1);
251 if (result.event == EventType::invasion)
253 std::cout <<
"Throat " << eIdx <<
" was invaded from pore " << vIdx <<
" :";
254 std::cout <<
" pc: " << *pcMax;
255 std::cout <<
", pcEntry: " << spatialParams.pcEntry(element, elemVolVars);
256 std::cout <<
", sw: " << sw[result.localScvIdxWithCriticalPc] << std::endl;
260 std::cout <<
"Snap-off occurred at throat " << eIdx <<
" from pore " << vIdx <<
" :";
261 std::cout <<
" pc: " << *pcMax;
262 std::cout <<
", pcSnapoff: " << spatialParams.pcSnapoff(element, elemVolVars);
263 std::cout <<
", sw: " << sw[result.localScvIdxWithCriticalPc] << std::endl;
273 template<
class Scalar>
274 bool maybeRestrictToGlobalCapillaryPressure_(
const Scalar
pcEntry)
const
276 if constexpr (hasGlobalCapillaryPressure<Problem>())
277 return restrictToGlobalCapillaryPressure_ && (
pcEntry > problem_.globalCapillaryPressure());
282 std::vector<bool> invadedCurrentIteration_;
283 std::vector<bool> invadedPreviousTimeStep_;
284 bool hasChangedInCurrentIteration_ =
false;
285 bool hasChangedComparedToPreviousTimestep_ =
false;
286 std::size_t numThroatsInvaded_;
288 bool restrictToGlobalCapillaryPressure_;
290 const Problem& problem_;
Exception thrown if a fixable numerical problem occurs.
Definition: exceptions.hh:27
This class updates the invasion state for the two-phase PNM.
Definition: invasionstate.hh:29
void checkIfCapillaryPressureIsCloseToEntryPressure(const SolutionVector &sol, const GridVolumeVariables &gridVolVars, const GridFluxVariablesCache &gridFluxVarsCache) const
Definition: invasionstate.hh:137
bool hasChangedInCurrentIteration() const
Return whether an invasion or snap-off occurred anywhere during the current Newton iteration.
Definition: invasionstate.hh:126
bool invaded(const Element &element) const
Return whether a given throat is invaded or not.
Definition: invasionstate.hh:72
bool hasChanged() const
Return whether an invasion or snap-off occurred anywhere. Can be used, e.g., for output file writing ...
Definition: invasionstate.hh:122
bool update(const SolutionVector &sol, const GridVolumeVariables &gridVolVars, GridFluxVariablesCache &gridFluxVarsCache)
Update the invasion state of all throats. This is done after each Newton step by a call from the Newt...
Definition: invasionstate.hh:84
TwoPInvasionState(const Problem &problem)
Definition: invasionstate.hh:43
void advance()
This is called after the Newton method has successfully finished one time step.
Definition: invasionstate.hh:130
std::size_t numThroatsInvaded() const
Return the number of currently invaded throats.
Definition: invasionstate.hh:79
void reset()
Restore the old invasion state after a Newton iteration has failed.
Definition: invasionstate.hh:115
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition: localview.hh:26
static ctype distance(const Dune::FieldVector< ctype, dimWorld > &a, const Dune::FieldVector< ctype, dimWorld > &b)
Compute the shortest distance between two points.
Definition: distance.hh:282
Defines labels for pores and throats.
std::string capillaryPressure() noexcept
I/O name of capillary pressure.
Definition: name.hh:123
Scalar pcSnapoff(const Scalar surfaceTension, const Scalar contactAngle, const Scalar inscribedRadius, const Throat::Shape shape)
The snap-off capillary pressure of a pore throat It checks if the cross section shape of the throat i...
Definition: thresholdcapillarypressures.hh:65
Scalar pcEntry(const Scalar surfaceTension, const Scalar contactAngle, const Scalar inscribedRadius, const Scalar shapeFactor) noexcept
The entry capillary pressure of a pore throat.
Definition: thresholdcapillarypressures.hh:82
Definition: discretization/porenetwork/fvelementgeometry.hh:24
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.