diff --git a/dumux/flux/porenetwork/fourierslaw.hh b/dumux/flux/porenetwork/fourierslaw.hh
index 6db79c10cc4b2405b5f1880f1364ed5ae54ed418..2f091f6a20db667fce4a24f20ba5c3b608aed6cd 100644
--- a/dumux/flux/porenetwork/fourierslaw.hh
+++ b/dumux/flux/porenetwork/fourierslaw.hh
@@ -26,13 +26,22 @@
 #define DUMUX_FLUX_PNM_FOURIERS_LAW_HH
 
 #include <dumux/common/math.hh>
+#include <dumux/flux/referencesystemformulation.hh>
+#include <type_traits>
 
 namespace Dumux::PoreNetwork {
 
+namespace Detail {
+
+struct NoDiffusionType {};
+
+} // end namespace Detail
+
  /*!
   * \ingroup PoreNetworkModels
   * \brief Specialization of Fourier's Law for the pore-network model.
   */
+template<class MolecularDiffusionType = Detail::NoDiffusionType>
 struct PNMFouriersLaw
 {
 
@@ -68,7 +77,41 @@ struct PNMFouriersLaw
             const Scalar gradT = deltaT/fluxVarsCache.throatLength();
 
             heatflux += thermalConductivity*gradT*area;
+
+            if constexpr (!std::is_same_v<MolecularDiffusionType, Detail::NoDiffusionType>)
+                heatflux += componentEnthalpyFlux_(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache, phaseIdx);
+        }
+
+        return heatflux;
+    }
+
+private:
+    template<class Problem, class Element, class FVElementGeometry,
+             class ElementVolumeVariables, class ElementFluxVariablesCache>
+    static auto componentEnthalpyFlux_(const Problem& problem,
+                                       const Element& element,
+                                       const FVElementGeometry& fvGeometry,
+                                       const ElementVolumeVariables& elemVolVars,
+                                       const typename FVElementGeometry::SubControlVolumeFace& scvf,
+                                       const ElementFluxVariablesCache& elemFluxVarsCache,
+                                       const int phaseIdx)
+    {
+        using Scalar = typename ElementVolumeVariables::VolumeVariables::PrimaryVariables::value_type;
+        Scalar heatflux = 0.0;
+        using FluidSystem = typename ElementVolumeVariables::VolumeVariables::FluidSystem;
+        const auto diffusiveFlux = MolecularDiffusionType::flux(problem, element, fvGeometry, elemVolVars, scvf, phaseIdx, elemFluxVarsCache);
+        for (int compIdx = 0; compIdx < ElementVolumeVariables::VolumeVariables::numFluidComponents(); ++compIdx)
+        {
+            const bool insideIsUpstream = diffusiveFlux[compIdx] > 0.0;
+            const auto& upstreamVolVars = insideIsUpstream ? elemVolVars[scvf.insideScvIdx()] : elemVolVars[scvf.outsideScvIdx()];
+            const Scalar componentEnthalpy = FluidSystem::componentEnthalpy(upstreamVolVars.fluidState(), phaseIdx, compIdx);
+
+            if (MolecularDiffusionType::referenceSystemFormulation() == ReferenceSystemFormulation::massAveraged)
+                heatflux += diffusiveFlux[compIdx] * componentEnthalpy;
+            else
+                heatflux += diffusiveFlux[compIdx] * FluidSystem::molarMass(compIdx) * componentEnthalpy;
         }
+
         return heatflux;
     }
 };
diff --git a/dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/localrulesforplatonicbody.hh b/dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/localrulesforplatonicbody.hh
index e13600e8b6969f5ef85c130d609107e4fb78c0c4..c97b28fcc132065e4704ec0b226b47a7aa272033 100644
--- a/dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/localrulesforplatonicbody.hh
+++ b/dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/localrulesforplatonicbody.hh
@@ -57,10 +57,8 @@ struct PlatonicBodyParams
                        const ElemSol& elemSol)
     : shape_(spatialParams.gridGeometry().poreGeometry()[scv.dofIndex()])
     , radius_(spatialParams.poreInscribedRadius(element, scv, elemSol))
-    {
-        static const Scalar surfaceTension = getParam<Scalar>("SpatialParams.SurfaceTension", 0.0725); // TODO
-        surfaceTension_ = surfaceTension;
-    }
+    , surfaceTension_(spatialParams.surfaceTension(element, scv, elemSol))
+    {}
 
     template<class SpatialParams, class Element, class SubControlVolume, class ElemSol>
     void update(const SpatialParams& spatialParams,
@@ -71,9 +69,7 @@ struct PlatonicBodyParams
         const auto& gridGeometry = spatialParams.gridGeometry();
         shape_ = gridGeometry.poreGeometry()[scv.dofIndex()];
         radius_ = spatialParams.poreInscribedRadius(element, scv, elemSol);
-
-        static const Scalar surfaceTension = getParam<Scalar>("SpatialParams.SurfaceTension", 0.0725); // TODO
-        surfaceTension_ = surfaceTension;
+        surfaceTension_ = spatialParams.surfaceTension(element, scv, elemSol);
     }
 
     Pore::Shape poreShape() const { return shape_; }
@@ -321,11 +317,6 @@ private:
         if (sw < pcLowSw_)
             return pcLowSwPcValue_() + pcDerivativeLowSw_() * (sw - pcLowSw_);
 
-        auto linearCurveForHighSw = [&]()
-        {
-            return pcDerivativeHighSwEnd_()*(sw - 1.0);
-        };
-
         if (sw <= pcHighSw_)
             return {}; // standard
         else if (sw < 1.0) // regularized part below sw = 1.0
@@ -335,7 +326,10 @@ private:
                 return pcHighSwPcValue_() * pow(((1.0-sw)/(1.0-pcHighSw_)), 1.0/3.0);
 
             else if (highSwRegularizationMethod_ == HighSwRegularizationMethod::linear)
-                return linearCurveForHighSw();
+            {
+                const Scalar slope = -pcHighSwPcValue_() / (1.0 - pcHighSw_);
+                return pcHighSwPcValue_() + (sw - pcHighSw_) * slope;
+            }
 
             else if (highSwRegularizationMethod_ == HighSwRegularizationMethod::spline)
                 return pcSpline_().eval(sw);
@@ -344,7 +338,7 @@ private:
                 DUNE_THROW(Dune::NotImplemented, "Regularization not method not implemented");
         }
         else // regularized part above sw = 1.0
-            return linearCurveForHighSw();
+            return pcDerivativeHighSwEnd_()*(sw - 1.0);
     }
 
     /*!
@@ -516,6 +510,9 @@ private:
 
         baseLawParamsPtr_ = &m->basicParams();
 
+        static const auto highSwFixedSlopeInput = getParamFromGroup<Scalar>(paramGroup, "RegularizationHighSwFixedSlope", std::numeric_limits<Scalar>::quiet_NaN());
+        highSwFixedSlope_ = highSwFixedSlopeInput;
+
         // Note: we do not pre-calculate all end-point values (e.g.,  pcLowSwPcValue_ and pcDerivativeLowSw_)
         // as done in, e.g., VanGenuchten. This is because this law will generally be instantiated only as
         // a temporary object since all pore bodies generally have different parameters.
@@ -550,7 +547,11 @@ private:
     // dpc_dsw at Sw = 1.0
     Scalar pcDerivativeHighSwEnd_() const
     {
-        return (0.0 - pcHighSwPcValue_()) / (1.0 - pcHighSw_);
+        using std::isnan;
+        if (!isnan(highSwFixedSlope_))
+            return highSwFixedSlope_;
+        else
+            return (0.0 - pcHighSwPcValue_()) / (1.0 - pcHighSw_);
     }
 
     const Spline<Scalar>& pcSpline_() const
@@ -574,6 +575,7 @@ private:
     const BaseLawParams* baseLawParamsPtr_;
     mutable std::optional<Spline<Scalar>> optionalPcSpline_;
     bool highSwSplineZeroSlope_;
+    Scalar highSwFixedSlope_;
 };
 
 /*!
diff --git a/dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/multishapelocalrules.hh b/dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/multishapelocalrules.hh
index e248654efbd0c1dc622956f53e5c3b0118bf0240..5f3bab10a793a4fb85b8f5de947f634259a9d2f6 100644
--- a/dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/multishapelocalrules.hh
+++ b/dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/multishapelocalrules.hh
@@ -34,11 +34,11 @@ namespace Dumux::PoreNetwork::FluidMatrix {
 template<class ScalarT>
 struct LocalRulesTraits
 {
-    using Tetrahedron = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::tetrahedron>;
-    using Cube = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::cube>;
-    using Octahedron = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::octahedron>;
-    using Icosahedron = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::icosahedron>;
-    using Dodecahedron = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::dodecahedron>;
+    using Tetrahedron = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::tetrahedron, ScalarT>;
+    using Cube = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::cube, ScalarT>;
+    using Octahedron = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::octahedron, ScalarT>;
+    using Icosahedron = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::icosahedron, ScalarT>;
+    using Dodecahedron = TwoPLocalRulesPlatonicBodyDefault<Pore::Shape::dodecahedron, ScalarT>;
 };
 
 template<class ScalarT>
@@ -102,6 +102,7 @@ public:
     { return 2; }
 
     template<class SpatialParams, class Element, class SubControlVolume, class ElemSol>
+    [[deprecated("Use constructor of BasicParams directly. Will be removed before release 3.4")]]
     static BasicParams makeParams(const SpatialParams& spatialParams,
                                   const Element& element,
                                   const SubControlVolume& scv,
diff --git a/dumux/material/spatialparams/porenetwork/porenetwork2p.hh b/dumux/material/spatialparams/porenetwork/porenetwork2p.hh
index 415bca66c6535c20789234566f3bb0a390720a7c..8ec48f9de5649117a959cabd70ec2f3382672d1f 100644
--- a/dumux/material/spatialparams/porenetwork/porenetwork2p.hh
+++ b/dumux/material/spatialparams/porenetwork/porenetwork2p.hh
@@ -157,9 +157,23 @@ public:
     }
 
     /*!
-     * \brief Returns the parameter object for the Brooks-Corey material law.
+     * \brief Returns the surface tension \f$ N/m\f$
      *
-     * In this test, we use element-wise distributed material parameters.
+     * \param element The current element
+     * \param scv The sub-control volume inside the element.
+     * \param elemSol The solution at the dofs connected to the element.
+     */
+    template<class ElementSolution>
+    Scalar surfaceTension(const Element& element,
+                          const SubControlVolume& scv,
+                          const ElementSolution& elemSol) const
+    {
+        static const Scalar gamma = getParam<Scalar>("SpatialParams.SurfaceTension", 0.0725); // default to surface tension of water/air
+        return gamma;
+    }
+
+    /*!
+     * \brief Returns the parameter object for the pore-local pc-Sw law
      *
      * \param element The current element
      * \param scv The sub-control volume inside the element.
@@ -171,7 +185,7 @@ public:
                                 const SubControlVolume& scv,
                                 const ElementSolution& elemSol) const
     {
-        const auto params = LocalRules::makeParams(*this, element, scv, elemSol);
+        const auto params = typename LocalRules::BasicParams(*this, element, scv, elemSol);
         return makeFluidMatrixInteraction(LocalRules(params, "SpatialParams"));
     }
 
diff --git a/dumux/porenetwork/1pnc/model.hh b/dumux/porenetwork/1pnc/model.hh
index 807f6e20b61a958a5a3f10d298c7f202595051c2..7619f8c2dc1322d65332042a1cbf595d98841659 100644
--- a/dumux/porenetwork/1pnc/model.hh
+++ b/dumux/porenetwork/1pnc/model.hh
@@ -242,5 +242,12 @@ struct ThermalConductivityModel<TypeTag, TTag::PNMOnePNCNI>
     using type = ThermalConductivityAverage<GetPropType<TypeTag, Properties::Scalar>>;
 }; //!< Use the average for effective conductivities
 
+// template<class TypeTag>
+// struct HeatConductionType<TypeTag, TTag::PNMOnePNCNI>
+// {
+//     TODO uncomment this as soon as there is a generalized approach for component enthalpies in all fluid systems
+//     using type = Dumux::PoreNetwork::PNMFouriersLaw<GetPropType<TypeTag, MolecularDiffusionType>>;
+// }; //!< Use Fourier's law and also consider enthalpy transport by molecular diffusion
+
 } // end namespace Dumux::Properties
 #endif
diff --git a/dumux/porenetwork/2p/gridfluxvariablescache.hh b/dumux/porenetwork/2p/gridfluxvariablescache.hh
index af5d4afa8805c910009d0b34556fd7302026a36b..a6a1969aa39ec9a7224baa0851f62ac3807bec44 100644
--- a/dumux/porenetwork/2p/gridfluxvariablescache.hh
+++ b/dumux/porenetwork/2p/gridfluxvariablescache.hh
@@ -36,13 +36,12 @@ namespace Dumux::PoreNetwork {
  * \ingroup PNMTwoPModel
  * \brief Flux variable caches traits
  */
-template<class P, class FVC, class I, class L>
+template<class P, class FVC, class IS = TwoPInvasionState<P>>
 struct PNMTwoPDefaultGridFVCTraits
 {
     using Problem = P;
     using FluxVariablesCache = FVC;
-    using Indices = I;
-    using Labels = L;
+    using InvasionState = IS;
 
     template<class GridFluxVariablesCache, bool cachingEnabled>
     using LocalView = PNMTwoPElementFluxVariablesCache<GridFluxVariablesCache, cachingEnabled>;
@@ -69,9 +68,9 @@ class PNMTwoPGridFluxVariablesCache<P, FVC, true, Traits>
 {
     using Problem = typename Traits::Problem;
     using ThisType = PNMTwoPGridFluxVariablesCache<P, FVC, true, Traits>;
-    using InvasionState = TwoPInvasionState<Problem>;
+    using InvasionState = typename Traits::InvasionState;
 
-    public:
+public:
     //! export the flux variable cache type
     using FluxVariablesCache = typename Traits::FluxVariablesCache;
 
@@ -140,7 +139,7 @@ class PNMTwoPGridFluxVariablesCache<P, FVC, false, Traits>
 {
     using Problem = typename Traits::Problem;
     using ThisType = PNMTwoPGridFluxVariablesCache<P, FVC, false, Traits>;
-    using InvasionState = TwoPInvasionState<Problem>;
+    using InvasionState = typename Traits::InvasionState;
 
     public:
     //! export the flux variable cache type
diff --git a/dumux/porenetwork/2p/invasionstate.hh b/dumux/porenetwork/2p/invasionstate.hh
index e6fce845b847e3f6482120d1682d872156fba694..8100a46bb500d937ab2e32423a4309173bbca493 100644
--- a/dumux/porenetwork/2p/invasionstate.hh
+++ b/dumux/porenetwork/2p/invasionstate.hh
@@ -19,42 +19,37 @@
 /*!
  * \file
  * \ingroup PNMTwoPModel
- * \brief Global flux variable cache
+ * \brief Invasion state class for the two-phase PNM.
  */
 #ifndef DUMUX_PNM_2P_INVASIONSTATE_HH
 #define DUMUX_PNM_2P_INVASIONSTATE_HH
 
 #include <vector>
 #include <type_traits>
+#include <dune/common/std/type_traits.hh>
 #include <dumux/common/parameters.hh>
-#include <dumux/common/typetraits/isvalid.hh>
 #include <dumux/porenetwork/common/labels.hh>
 
 namespace Dumux::PoreNetwork {
 
-#ifndef DOXYGEN
-namespace Detail {
-// helper struct detecting if the user-defined problem params class has a globalCapillaryPressure function
-struct hasGlobalCapillaryPressure
-{
-    template<class Problem>
-    auto operator()(const Problem& p)
-    -> decltype(p.globalCapillaryPressure())
-    {}
-};
-} // end namespace Detail
-#endif
-
 /*!
  * \ingroup PNMTwoPModel
- * \brief The grid flux variables cache for the two-phase PNM hodling the invasion state of the throats
- * \note The flux caches of the gridview are stored which is memory intensive but faster
+ * \brief This class updates the invasion state for the two-phase PNM.
  */
 template<class P>
 class TwoPInvasionState
 {
     using Problem = P;
 
+    template <class T>
+    using GlobalCapillaryPressureDetector = decltype(std::declval<T>().globalCapillaryPressure());
+
+    template<class T>
+    static constexpr bool hasGlobalCapillaryPressure()
+    { return Dune::Std::is_detected<GlobalCapillaryPressureDetector, T>::value; }
+
+    enum class EventType {invasion, snapOff, none};
+
 public:
 
     TwoPInvasionState(const Problem& problem) : problem_(problem)
@@ -71,10 +66,10 @@ public:
         }
 
         numThroatsInvaded_ = std::count(invadedCurrentIteration_.begin(), invadedCurrentIteration_.end(), true);
-        verbose_ = getParamFromGroup<bool>(problem.paramGroup(), "InvasionState.InvasionStateVerbosity", true);
+        verbose_ = getParamFromGroup<bool>(problem.paramGroup(), "InvasionState.Verbosity", true);
         restrictToGlobalCapillaryPressure_ = getParamFromGroup<bool>(problem.paramGroup(), "InvasionState.RestrictInvasionToGlobalCapillaryPressure", false);
 
-        if (decltype(isValid(Detail::hasGlobalCapillaryPressure())(problem)){})
+        if constexpr (hasGlobalCapillaryPressure<Problem>())
         {
             if (restrictToGlobalCapillaryPressure_)
                 std::cout << "\n *** Invasion behavior is restricted by a global capillary pressure defined in the problem! *** \n" << std::endl;
@@ -115,11 +110,14 @@ public:
             for (auto&& scvf : scvfs(fvGeometry))
             {
                 // checks if invasion or snap-off occured after Newton iteration step
-                if (invasionSwitch_(element, elemVolVars, elemFluxVarsCache[scvf]))
+                if (const auto invasionResult = invasionSwitch_(element, elemVolVars, elemFluxVarsCache[scvf]); invasionResult)
                 {
                     hasChangedInCurrentIteration_ = true;
-                    static constexpr auto cachingEnabled = std::integral_constant<bool, GridFluxVariablesCache::cachingEnabled>{};
-                    updateChangedFluxVarCache_(element, fvGeometry, gridFluxVarsCache, elemVolVars, scvf, cachingEnabled);
+                    if constexpr (GridFluxVariablesCache::cachingEnabled)
+                    {
+                        const auto eIdx = problem_.gridGeometry().elementMapper().index(element);
+                        gridFluxVarsCache.cache(eIdx, scvf.index()).update(problem_, element, fvGeometry, elemVolVars, scvf, invadedCurrentIteration_[eIdx]);
+                    }
                 }
             }
         }
@@ -194,36 +192,46 @@ private:
 
     //! The switch for determining the invasion state of a pore throat. Called at the end of each Newton step.
     template<class Element, class ElementVolumeVariables, class FluxVariablesCache>
-    bool invasionSwitch_(const Element& element,
+    auto invasionSwitch_(const Element& element,
                          const ElementVolumeVariables& elemVolVars,
                          const FluxVariablesCache& fluxVarsCache)
 
     {
+        using Scalar = typename ElementVolumeVariables::VolumeVariables::PrimaryVariables::value_type;
         const auto& gridGeometry = problem_.gridGeometry();
         const auto& spatialParams = problem_.spatialParams();
         const auto eIdx = gridGeometry.elementMapper().index(element);
         bool invadedBeforeSwitch = invadedCurrentIteration_[eIdx];
         bool invadedAfterSwitch = invadedBeforeSwitch;
 
-        const auto wPhaseIdx = spatialParams.template wettingPhase<typename ElementVolumeVariables::VolumeVariables::FluidSystem>(element, elemVolVars);
+        // Result type, containing the local scv index of the pore from which the invasion/snap-off occurred
+        // Evaluates to 'false' if no invasion/snap-off occurred
+        struct Result
+        {
+            std::uint8_t localScvIdxWithCriticalPc;
+            Scalar criticalPc;
+            EventType event = EventType::none;
+
+            operator bool() const
+            { return event != EventType::none; }
+        };
 
         // Block non-wetting phase flux out of the outlet
-        static const bool blockOutlet = getParamFromGroup<bool>(problem_.paramGroup(), "InvasionState.BlockOutletForNonwettingPhase", true);
-        if (blockOutlet && gridGeometry.throatLabel(eIdx) == Labels::outlet)
+        static const auto blockNonwettingPhase = getParamFromGroup<std::vector<int>>(problem_.paramGroup(), "InvasionState.BlockNonwettingPhaseAtThroatLabel", std::vector<int>{Labels::outlet});
+        if (!blockNonwettingPhase.empty() && std::find(blockNonwettingPhase.begin(), blockNonwettingPhase.end(), gridGeometry.throatLabel(eIdx)) != blockNonwettingPhase.end())
         {
             invadedCurrentIteration_[eIdx] = false;
-            return false;
+            return Result{}; // nothing happened
         }
 
         //Determine whether throat gets invaded or snap-off occurs
-        using Scalar = typename ElementVolumeVariables::VolumeVariables::PrimaryVariables::value_type;
         const std::array<Scalar, 2> pc = { elemVolVars[0].capillaryPressure(), elemVolVars[1].capillaryPressure() };
         const auto pcMax = std::max_element(pc.begin(), pc.end());
         const Scalar pcEntry = fluxVarsCache.pcEntry();
         const Scalar pcSnapoff = fluxVarsCache.pcSnapoff();
 
         // check if there is a user-specified global capillary pressure which needs to be obeyed
-        if (maybeRestrictToGlobalCapillaryPressure_(pcEntry, decltype(isValid(Detail::hasGlobalCapillaryPressure())(problem_)){}))
+        if (maybeRestrictToGlobalCapillaryPressure_(pcEntry))
         {
             if (*pcMax > pcEntry)
             {
@@ -232,7 +240,7 @@ private:
             }
 
             invadedCurrentIteration_[eIdx] = false;
-            return false;
+            return Result{}; //nothing happened
         }
 
         if (*pcMax > pcEntry)
@@ -242,68 +250,51 @@ private:
 
         invadedCurrentIteration_[eIdx] = invadedAfterSwitch;
 
-        if (invadedAfterSwitch != invadedBeforeSwitch && verbose_)
+        if (invadedBeforeSwitch == invadedAfterSwitch)
+            return Result{}; // nothing happened
+        else
         {
-          const std::array<Scalar, 2> sw = { elemVolVars[0].saturation(wPhaseIdx), elemVolVars[1].saturation(wPhaseIdx) };
-          const auto scvIdx = pcMax - pc.begin();
-          const auto vIdx = gridGeometry.gridView().indexSet().subIndex(element, scvIdx, 1);
-          if (!invadedBeforeSwitch && invadedAfterSwitch)
-          {
-              std::cout << "Throat " << eIdx << " was invaded from pore "  << vIdx << " :";
-              std::cout << " pc: " << *pcMax;
-              std::cout << ", pcEntry: " << spatialParams.pcEntry(element, elemVolVars);
-              std::cout << ", sw: " << sw[scvIdx] << std::endl;
-          }
-          else if (invadedBeforeSwitch && !invadedAfterSwitch)
-          {
-              std::cout << "Snap-off occured at: " << eIdx << " from pore "  << vIdx << " :";
-              std::cout << " pc: " << *pcMax;
-              std::cout << ", pcSnapoff: " << spatialParams.pcSnapoff(element, elemVolVars);
-              std::cout << ", sw: " << sw[scvIdx] << std::endl;
-          }
-          else
-              DUNE_THROW(Dune::InvalidStateException, "Invalid Process ");
-        }
-        return invadedBeforeSwitch != invadedAfterSwitch;
-    }
+            Result result;
+            result.localScvIdxWithCriticalPc = std::distance(pc.begin(), pcMax);
+            result.criticalPc = *pcMax;
+            result.event = !invadedBeforeSwitch && invadedAfterSwitch ? EventType::invasion : EventType::snapOff;
 
-    //! Update the fluxVarsCache after an invasion/snap-off occured (only for caching enabled)
-    template<class Element, class FVElementGeometry, class GridFluxVariablesCache,
-             class ElementVolumeVariables, class SubControlVolumeFace>
-    void updateChangedFluxVarCache_(const Element& element,
-                                    const FVElementGeometry& fvGeometry,
-                                    GridFluxVariablesCache& gridFluxVarsCache,
-                                    const ElementVolumeVariables& elemVolVars,
-                                    const SubControlVolumeFace& scvf,
-                                    std::true_type)
-    {
-        const auto eIdx = problem_.gridGeometry().elementMapper().index(element);
-        gridFluxVarsCache.cache(eIdx, scvf.index()).update(problem_, element, fvGeometry, elemVolVars, scvf, invaded(element));
-    }
+            if (verbose_)
+            {
+                const auto wPhaseIdx = spatialParams.template wettingPhase<typename ElementVolumeVariables::VolumeVariables::FluidSystem>(element, elemVolVars);
+                const std::array sw = { elemVolVars[0].saturation(wPhaseIdx), elemVolVars[1].saturation(wPhaseIdx) };
+                const auto vIdx = gridGeometry.gridView().indexSet().subIndex(element, result.localScvIdxWithCriticalPc, 1);
+                if (result.event == EventType::invasion)
+                {
+                    std::cout << "Throat " << eIdx << " was invaded from pore "  << vIdx << " :";
+                    std::cout << " pc: " << *pcMax;
+                    std::cout << ", pcEntry: " << spatialParams.pcEntry(element, elemVolVars);
+                    std::cout << ", sw: " << sw[result.localScvIdxWithCriticalPc] << std::endl;
+                }
+                else
+                {
+                    std::cout << "Snap-off occured at throat " << eIdx << " from pore "  << vIdx << " :";
+                    std::cout << " pc: " << *pcMax;
+                    std::cout << ", pcSnapoff: " << spatialParams.pcSnapoff(element, elemVolVars);
+                    std::cout << ", sw: " << sw[result.localScvIdxWithCriticalPc] << std::endl;
+                }
+            }
 
-    //! Do nothing if the fluxVarCaches are not cached globally
-    template<class Element, class FVElementGeometry, class GridFluxVariablesCache,
-             class ElementVolumeVariables, class SubControlVolumeFace>
-    void updateChangedFluxVarCache_(const Element& element,
-                                    const FVElementGeometry& fvGeometry,
-                                    GridFluxVariablesCache& gridFluxVarsCache,
-                                    const ElementVolumeVariables& elemVolVars,
-                                    const SubControlVolumeFace& scvf,
-                                    std::false_type) {}
+            return result;
+        }
+    }
 
     //! If the user has specified a global capillary pressure, check if it is lower than the given entry capillary pressure.
     //! This may be needed to exactly reproduce pc-S curves given by static network models.
     template<class Scalar>
-    bool maybeRestrictToGlobalCapillaryPressure_(const Scalar pcEntry, std::true_type) const
+    bool maybeRestrictToGlobalCapillaryPressure_(const Scalar pcEntry) const
     {
-        return restrictToGlobalCapillaryPressure_ && (pcEntry > problem_.globalCapillaryPressure());
+        if constexpr (hasGlobalCapillaryPressure<Problem>())
+            return restrictToGlobalCapillaryPressure_ && (pcEntry > problem_.globalCapillaryPressure());
+        else
+            return false;
     }
 
-    //! Do nothing here.
-    template<class Scalar>
-    bool maybeRestrictToGlobalCapillaryPressure_(const Scalar pc, std::false_type) const
-    { return false; }
-
     std::vector<bool> invadedCurrentIteration_;
     std::vector<bool> invadedPreviousTimeStep_;
     bool hasChangedInCurrentIteration_ = false;
diff --git a/dumux/porenetwork/2p/model.hh b/dumux/porenetwork/2p/model.hh
index 8d676cf2f0e81b14cff8683c430b6961fd2bfcda..16591c003b4b0813a75e0586e7f5a3993b7dffeb 100644
--- a/dumux/porenetwork/2p/model.hh
+++ b/dumux/porenetwork/2p/model.hh
@@ -130,10 +130,8 @@ struct GridFluxVariablesCache<TypeTag, TTag::PNMTwoP>
 private:
     static constexpr bool enableCache = getPropValue<TypeTag, Properties::EnableGridFluxVariablesCache>();
     using Problem = GetPropType<TypeTag, Properties::Problem>;
-    using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
-    using Labels = GetPropType<TypeTag, Properties::Labels>;
     using FluxVariablesCache = GetPropType<TypeTag, Properties::FluxVariablesCache>;
-    using Traits = Dumux::PoreNetwork::PNMTwoPDefaultGridFVCTraits<Problem, FluxVariablesCache, Indices, Labels>;
+    using Traits = Dumux::PoreNetwork::PNMTwoPDefaultGridFVCTraits<Problem, FluxVariablesCache>;
 public:
     using type = Dumux::PoreNetwork::PNMTwoPGridFluxVariablesCache<Problem, FluxVariablesCache, enableCache, Traits>;
 };
diff --git a/dumux/porenetwork/2p/volumevariables.hh b/dumux/porenetwork/2p/volumevariables.hh
index dcb859bc171e433df525b08a19c4986b4a98e5f8..f05245028c7d1731a79f41ac72b9380d0c3b77cf 100644
--- a/dumux/porenetwork/2p/volumevariables.hh
+++ b/dumux/porenetwork/2p/volumevariables.hh
@@ -76,10 +76,7 @@ public:
         ParentType::update(elemSol, problem, element, scv);
         poreInscribedRadius_ = problem.spatialParams().poreInscribedRadius(element, scv, elemSol);
         poreVolume_ = problem.gridGeometry().poreVolume(scv.dofIndex()) * this->porosity();
-
-        // the value of water/air TODO make general in fluid system
-        static const Scalar gamma = getParamFromGroup<Scalar>(problem.paramGroup(), "Problem.SurfaceTension", 0.0725);
-        surfaceTension_ = gamma;
+        surfaceTension_ = problem.spatialParams().surfaceTension(element, scv, elemSol);
     }
 
     /*!
diff --git a/dumux/porenetwork/properties.hh b/dumux/porenetwork/properties.hh
index 628182f78bb93359ae9ecf54b2919fde000102a3..dec06d8a0a3f017e099cf77919a7cbaa78d946cb 100644
--- a/dumux/porenetwork/properties.hh
+++ b/dumux/porenetwork/properties.hh
@@ -68,7 +68,7 @@ public:
 };
 
 template<class TypeTag>
-struct HeatConductionType<TypeTag, TTag::PoreNetworkModel> { using type = Dumux::PoreNetwork::PNMFouriersLaw; };
+struct HeatConductionType<TypeTag, TTag::PoreNetworkModel> { using type = Dumux::PoreNetwork::PNMFouriersLaw<>; };
 
 //! The labels
 template<class TypeTag>