45 using GlobalCapillaryPressureDetector =
decltype(std::declval<T>().globalCapillaryPressure());
48 static constexpr bool hasGlobalCapillaryPressure()
49 {
return Dune::Std::is_detected<GlobalCapillaryPressureDetector, T>::value; }
51 enum class EventType {invasion, snapOff,
none};
58 invadedCurrentIteration_.resize(problem.gridGeometry().gridView().size(0));
59 invadedPreviousTimeStep_.resize(problem.gridGeometry().gridView().size(0));
61 for (
auto&& element : elements(problem.gridGeometry().gridView()))
63 const auto eIdx = problem.gridGeometry().elementMapper().index(element);
64 invadedCurrentIteration_[eIdx] = problem.initialInvasionState(element);
65 invadedPreviousTimeStep_[eIdx] = invadedCurrentIteration_[eIdx];
68 numThroatsInvaded_ = std::count(invadedCurrentIteration_.begin(), invadedCurrentIteration_.end(),
true);
70 restrictToGlobalCapillaryPressure_ =
getParamFromGroup<bool>(problem.paramGroup(),
"InvasionState.RestrictInvasionToGlobalCapillaryPressure",
false);
72 if constexpr (hasGlobalCapillaryPressure<Problem>())
74 if (restrictToGlobalCapillaryPressure_)
75 std::cout <<
"\n *** Invasion behavior is restricted by a global capillary pressure defined in the problem! *** \n" << std::endl;
77 std::cout <<
"\n *** WARNING: global capillary pressure defined in the problem but InvasionState.RestrictInvasionToGlobalCapillaryPressure is set to false.\n"
78 <<
" Invasion behavior will NOT be restricted! ***\n" << std::endl;
83 template<
class Element>
84 bool invaded(
const Element& element)
const
86 const auto eIdx = problem_.gridGeometry().elementMapper().index(element);
87 return invadedCurrentIteration_[eIdx];
92 {
return numThroatsInvaded_; }
95 template<
class SolutionVector,
class Gr
idVolumeVariables,
class Gr
idFluxVariablesCache>
96 bool update(
const SolutionVector& sol,
const GridVolumeVariables& gridVolVars, GridFluxVariablesCache& gridFluxVarsCache)
98 hasChangedInCurrentIteration_ =
false;
99 for (
auto&& element : elements(problem_.gridGeometry().gridView()))
101 auto fvGeometry =
localView(problem_.gridGeometry());
102 fvGeometry.bindElement(element);
104 auto elemVolVars =
localView(gridVolVars);
105 elemVolVars.bind(element, fvGeometry, sol);
107 auto elemFluxVarsCache =
localView(gridFluxVarsCache);
108 elemFluxVarsCache.bind(element, fvGeometry, elemVolVars);
110 for (
auto&& scvf : scvfs(fvGeometry))
113 if (
const auto invasionResult = invasionSwitch_(element, elemVolVars, elemFluxVarsCache[scvf]); invasionResult)
115 hasChangedInCurrentIteration_ =
true;
116 if constexpr (GridFluxVariablesCache::cachingEnabled)
118 const auto eIdx = problem_.gridGeometry().elementMapper().index(element);
119 gridFluxVarsCache.cache(eIdx, scvf.index()).update(problem_, element, fvGeometry, elemVolVars, scvf, invadedCurrentIteration_[eIdx]);
124 numThroatsInvaded_ = std::count(invadedCurrentIteration_.begin(), invadedCurrentIteration_.end(),
true);
125 return hasChangedInCurrentIteration_;
131 hasChangedInCurrentIteration_ =
false;
132 invadedCurrentIteration_ = invadedPreviousTimeStep_;
137 {
return hasChangedComparedToPreviousTimestep_; }
141 {
return hasChangedInCurrentIteration_; }
146 hasChangedComparedToPreviousTimestep_ = (invadedPreviousTimeStep_ != invadedCurrentIteration_);
147 invadedPreviousTimeStep_ = invadedCurrentIteration_;
150 template<
class SolutionVector,
class Gr
idVolumeVariables,
class Gr
idFluxVariablesCache>
152 const GridVolumeVariables& gridVolVars,
153 const GridFluxVariablesCache& gridFluxVarsCache)
const
155 using Scalar =
typename SolutionVector::block_type::value_type;
156 static const Scalar accuracyCriterion =
getParamFromGroup<Scalar>(problem_.paramGroup(),
"InvasionState.AccuracyCriterion", -1.0);
158 if (accuracyCriterion < 0.0)
161 for (
auto&& element : elements(problem_.gridGeometry().gridView()))
164 const auto eIdx = problem_.gridGeometry().elementMapper().index(element);
165 if (!invadedCurrentIteration_[eIdx] || invadedPreviousTimeStep_[eIdx] == invadedCurrentIteration_[eIdx])
168 auto fvGeometry =
localView(problem_.gridGeometry());
169 fvGeometry.bindElement(element);
171 auto elemVolVars =
localView(gridVolVars);
172 elemVolVars.bind(element, fvGeometry, sol);
174 auto elemFluxVarsCache =
localView(gridFluxVarsCache);
175 elemFluxVarsCache.bind(element, fvGeometry, elemVolVars);
177 for (
auto&& scvf : scvfs(fvGeometry))
180 const auto& fluxVarsCache = elemFluxVarsCache[scvf];
183 const Scalar pc = max(elemVolVars[0].capillaryPressure(), elemVolVars[1].capillaryPressure());
185 if (pc < accuracyCriterion * fluxVarsCache.pcEntry())
186 DUNE_THROW(
NumericalProblem,
"At element " << eIdx <<
": pc " << pc <<
" too far away form pcEntry " << fluxVarsCache.pcEntry());
194 template<
class Element,
class ElementVolumeVariables,
class FluxVariablesCache>
195 auto invasionSwitch_(
const Element& element,
196 const ElementVolumeVariables& elemVolVars,
197 const FluxVariablesCache& fluxVarsCache)
200 using Scalar =
typename ElementVolumeVariables::VolumeVariables::PrimaryVariables::value_type;
201 const auto& gridGeometry = problem_.gridGeometry();
202 const auto& spatialParams = problem_.spatialParams();
203 const auto eIdx = gridGeometry.elementMapper().index(element);
204 bool invadedBeforeSwitch = invadedCurrentIteration_[eIdx];
205 bool invadedAfterSwitch = invadedBeforeSwitch;
211 std::uint8_t localScvIdxWithCriticalPc;
213 EventType
event = EventType::none;
215 operator bool()
const
216 {
return event != EventType::none; }
221 if (!blockNonwettingPhase.empty() && std::find(blockNonwettingPhase.begin(), blockNonwettingPhase.end(), gridGeometry.throatLabel(eIdx)) != blockNonwettingPhase.end())
223 invadedCurrentIteration_[eIdx] =
false;
228 const std::array<Scalar, 2> pc = { elemVolVars[0].capillaryPressure(), elemVolVars[1].capillaryPressure() };
229 const auto pcMax = std::max_element(pc.begin(), pc.end());
230 const Scalar pcEntry = fluxVarsCache.pcEntry();
231 const Scalar pcSnapoff = fluxVarsCache.pcSnapoff();
234 if (maybeRestrictToGlobalCapillaryPressure_(pcEntry))
236 if (*pcMax > pcEntry)
238 std::cout <<
"Throat " << eIdx <<
" would have been invaded by pc of " << *pcMax <<
"but a global capillary pressure restricion was set in the problem.";
239 std::cout <<
". pcEntry: " << spatialParams.pcEntry(element, elemVolVars) << std::endl;
242 invadedCurrentIteration_[eIdx] =
false;
246 if (*pcMax > pcEntry)
247 invadedAfterSwitch =
true;
248 else if (*pcMax <= pcSnapoff)
249 invadedAfterSwitch =
false;
251 invadedCurrentIteration_[eIdx] = invadedAfterSwitch;
253 if (invadedBeforeSwitch == invadedAfterSwitch)
258 result.localScvIdxWithCriticalPc = std::distance(pc.begin(), pcMax);
259 result.criticalPc = *pcMax;
260 result.event = !invadedBeforeSwitch && invadedAfterSwitch ? EventType::invasion : EventType::snapOff;
264 const auto wPhaseIdx = spatialParams.template wettingPhase<typename ElementVolumeVariables::VolumeVariables::FluidSystem>(element, elemVolVars);
265 const std::array sw = { elemVolVars[0].saturation(wPhaseIdx), elemVolVars[1].saturation(wPhaseIdx) };
266 const auto vIdx = gridGeometry.gridView().indexSet().subIndex(element, result.localScvIdxWithCriticalPc, 1);
267 if (result.event == EventType::invasion)
269 std::cout <<
"Throat " << eIdx <<
" was invaded from pore " << vIdx <<
" :";
270 std::cout <<
" pc: " << *pcMax;
271 std::cout <<
", pcEntry: " << spatialParams.pcEntry(element, elemVolVars);
272 std::cout <<
", sw: " << sw[result.localScvIdxWithCriticalPc] << std::endl;
276 std::cout <<
"Snap-off occured at throat " << eIdx <<
" from pore " << vIdx <<
" :";
277 std::cout <<
" pc: " << *pcMax;
278 std::cout <<
", pcSnapoff: " << spatialParams.pcSnapoff(element, elemVolVars);
279 std::cout <<
", sw: " << sw[result.localScvIdxWithCriticalPc] << std::endl;
289 template<
class Scalar>
290 bool maybeRestrictToGlobalCapillaryPressure_(
const Scalar pcEntry)
const
292 if constexpr (hasGlobalCapillaryPressure<Problem>())
293 return restrictToGlobalCapillaryPressure_ && (pcEntry > problem_.globalCapillaryPressure());
298 std::vector<bool> invadedCurrentIteration_;
299 std::vector<bool> invadedPreviousTimeStep_;
300 bool hasChangedInCurrentIteration_ =
false;
301 bool hasChangedComparedToPreviousTimestep_ =
false;
302 std::size_t numThroatsInvaded_;
304 bool restrictToGlobalCapillaryPressure_;
306 const Problem& problem_;