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);
 
   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];
 
  167                const Scalar pc = max(elemVolVars[0].capillaryPressure(), elemVolVars[1].capillaryPressure());
 
  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))
 
  220            if (*pcMax > 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;
 
  230        if (*pcMax > pcEntry)
 
  231           invadedAfterSwitch = 
true;
 
  232        else if (*pcMax <= pcSnapoff)
 
  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_;
 
 
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