diff --git a/dumux/porenetwork/2pnc/CMakeLists.txt b/dumux/porenetwork/2pnc/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3de09eeabc5386d3152c4e3b9a581734571246ad
--- /dev/null
+++ b/dumux/porenetwork/2pnc/CMakeLists.txt
@@ -0,0 +1,6 @@
+# SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+file(GLOB DUMUX_PORENETWORK_2P_NC_HEADERS *.hh *.inc)
+install(FILES ${DUMUX_PORENETWORK_2P_NC_HEADERS}
+        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/porenetwork/2pnc)
diff --git a/dumux/porenetwork/2pnc/iofields.hh b/dumux/porenetwork/2pnc/iofields.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f14cb1f9a15f02fb38d168ef290623aca983c480
--- /dev/null
+++ b/dumux/porenetwork/2pnc/iofields.hh
@@ -0,0 +1,67 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+//
+// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+/*!
+ * \file
+ * \ingroup PNMTwoPNCModel
+ * \copydoc Dumux::PoreNetwork::TwoPNCIOFields
+ */
+#ifndef DUMUX_PNM_2P_NC_IO_FIELDS_HH
+#define DUMUX_PNM_2P_NC_IO_FIELDS_HH
+
+#include <dumux/porousmediumflow/2pnc/iofields.hh>
+#include <dumux/porenetwork/common/iofields.hh>
+
+namespace Dumux::PoreNetwork {
+
+/*!
+ * \ingroup PNMTwoPNCModel
+ * \brief Adds output fields specific to the PNM 2pnc model
+ */
+class TwoPNCIOFields
+{
+public:
+    template <class OutputModule>
+    static void initOutputModule(OutputModule& out)
+    {
+         // use default fields from the 2pnc model
+        Dumux::TwoPNCIOFields::initOutputModule(out);
+
+        using VolumeVariables = typename OutputModule::VolumeVariables;
+        using FS = typename VolumeVariables::FluidSystem;
+
+        CommonIOFields::initOutputModule(out);
+
+        out.addFluxVariable([](const auto& fluxVars, const auto& fluxVarsCache)
+                              { return fluxVarsCache.pcEntry(); }, "pcEntry");
+
+        out.addFluxVariable([](const auto& fluxVars, const auto& fluxVarsCache)
+                              { return fluxVarsCache.transmissibility(FS::phase0Idx); }, "transmissibilityW");
+
+        out.addFluxVariable([](const auto& fluxVars, const auto& fluxVarsCache)
+                              { return fluxVarsCache.transmissibility(FS::phase1Idx); }, "transmissibilityN");
+
+        auto volumeFluxW = [](const auto& fluxVars, const auto& fluxVarsCache)
+        {
+            auto upwindTerm = [](const auto& volVars) { return volVars.mobility(FS::phase0Idx); };
+            using std::abs;
+            return abs(fluxVars.advectiveFlux(FS::phase0Idx, upwindTerm));
+        };
+        out.addFluxVariable(volumeFluxW, "volumeFluxW");
+
+        auto volumeFluxN = [](const auto& fluxVars, const auto& fluxVarsCache)
+        {
+            auto upwindTerm = [](const auto& volVars) { return volVars.mobility(FS::phase1Idx); };
+            using std::abs;
+            return abs(fluxVars.advectiveFlux(FS::phase1Idx, upwindTerm));
+        };
+        out.addFluxVariable(volumeFluxN, "volumeFluxN");
+    }
+};
+
+} // end namespace Dumux::PoreNetwork
+
+#endif
diff --git a/dumux/porenetwork/2pnc/model.hh b/dumux/porenetwork/2pnc/model.hh
new file mode 100644
index 0000000000000000000000000000000000000000..5a73becb375e6b865995eccbcc7665c1a4fbe6c1
--- /dev/null
+++ b/dumux/porenetwork/2pnc/model.hh
@@ -0,0 +1,259 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+//
+// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+/*!
+ * \file
+ * \ingroup PNMTwoPNCModel
+ * \brief A two-phase multi-compositional pore-network model using fully implicit scheme.
+ *
+ * A mass balance equation is formulated for each pore body \f$i\f$ and each component \f$\kappa\f$:
+ *
+ * \f[
+ *	V_i \frac{\partial (\sum_{\alpha} (x^\kappa_\alpha \varrho_\alpha S_\alpha)_i) }{\partial t} + \sum_\alpha \sum_j (x^\kappa_\alpha \varrho_\alpha  Q_\alpha)_{ij}
+ *  + \sum_\alpha \sum_j (A_\alpha j^\kappa_\alpha)_{ij}= (V q^\kappa)_i ~.
+ * \f]
+ *
+ * \f$V_i\f$ is the pore body volume, \f$x^\kappa_\alpha\f$ resepresents the mole fraction of component \f$\kappa\f$  in phase \f$\alpha\f$ , the advective mass flow \f$(\varrho_\alpha Q_\alpha)_{ij}\f$
+ * through throat \f$ij\f$ can be based on the fluid phase density \f$\varrho\f$ either of the upstream pore body \f$i\f$ or \f$j\f$ (upwinding) or on the respective averaged value.
+ * \f$j^\kappa_\alpha\f$ represents the diffuive flux vector and \f$A_\alpha\f$ the area of throat cross section occupied by phase \f$\alpha\f$. \f$q_\alpha\f$ is a mass sink or source term defined on pore body \f$i\f$.
+ *
+ * Per default, the volume flow rate \f$Q_{\alpha,ij}\f$ follows a linear Hagen-Poiseuille-type law (PoreNetworkModel::CreepingFlow) which is only valid for \f$Re < 1\f$:
+ *
+ * \f[
+ *	Q_{\alpha,ij} = g_{\alpha, ij} (p_{\alpha, i} - p_{\alpha, j} + \Psi_\alpha)  ~.
+ * \f]
+ *
+ * \f$g_{\alpha,ij}\f$ is a suitable throat conductance value that takes into account the presence/saturation of the individual phases while \f$p_{\alpha,i}\f$ and \f$p_{\alpha,j}\f$ are averaged pore body phase pressures.
+ *
+ * The (optional) influence of gravity is given by
+ *
+ * \f[
+ *	\Psi_\alpha = \varrho_\alpha \mathbf{g} \cdot (\mathbf{x}_i - \mathbf{x}_j),
+ * \f]
+ *
+ * where \f$\mathbf{x}_i - \mathbf{x}_j\f$  is the distance vector between the centers of pore bodies \f$i\f$ and \f$j\f$ and \f$\mathbf{g}\f$ is the gravity vector.
+ *
+ * The model is able to use either mole or mass fractions. The property useMoles can be set to either true or false in the
+ * problem file. Make sure that the according units are used in the problem setup. useMoles is set to true by default.
+ *
+ * The primary variables are the pressure \f$p_\alpha\f$ for phase \f$\alpha\f$ and the mole or mass fraction of dissolved components in phase \f$\alpha\f$ \f$x^\kappa_\alpha\f$ or \f$X^\kappa_\alpha\f$.
+ */
+
+#ifndef DUMUX_PNM_2P_NC_MODEL_HH
+#define DUMUX_PNM_2P_NC_MODEL_HH
+
+#include <dumux/common/properties.hh>
+#include <dumux/porenetwork/properties.hh>
+#include <dumux/flux/porenetwork/fickslaw.hh>
+
+#include <dumux/porousmediumflow/nonisothermal/model.hh>
+#include <dumux/porousmediumflow/nonisothermal/indices.hh>
+#include <dumux/porousmediumflow/nonisothermal/iofields.hh>
+
+#include <dumux/flux/porenetwork/advection.hh>
+#include <dumux/porousmediumflow/2pnc/model.hh>
+#include <dumux/porousmediumflow/compositional/switchableprimaryvariables.hh>
+#include <dumux/material/fluidmatrixinteractions/porenetwork/throat/transmissibility1p.hh>
+#include <dumux/material/fluidmatrixinteractions/porenetwork/throat/transmissibility2p.hh>
+#include <dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/multishapelocalrules.hh>
+
+#include <dumux/porenetwork/2p/fluxvariablescache.hh>
+#include <dumux/porenetwork/2p/gridfluxvariablescache.hh>
+#include <dumux/porenetwork/2p/spatialparams.hh>
+#include <dumux/porousmediumflow/compositional/localresidual.hh>
+
+
+#include "iofields.hh"
+#include "volumevariables.hh"
+
+namespace Dumux::Properties{
+// \{
+//////////////////////////////////////////////////////////////////
+// Type tags
+//////////////////////////////////////////////////////////////////
+
+//! The type tags for the implicit two-phase n-components problems
+// Create new type tags
+namespace TTag {
+struct PNMTwoPNC { using InheritsFrom = std::tuple<PoreNetworkModel, TwoPNC>; };
+
+//! The type tags for the corresponding non-isothermal problems
+struct PNMTwoPNCNI { using InheritsFrom = std::tuple<PNMTwoPNC>; };
+} // end namespace TTag
+
+//////////////////////////////////////////////////////////////////
+// Property tags
+//////////////////////////////////////////////////////////////////
+
+//! Set the volume variables property
+template<class TypeTag>
+struct VolumeVariables<TypeTag, TTag::PNMTwoPNC>
+{
+private:
+    using PV = GetPropType<TypeTag, Properties::PrimaryVariables>;
+    using FSY = GetPropType<TypeTag, Properties::FluidSystem>;
+    using FST = GetPropType<TypeTag, Properties::FluidState>;
+    using SSY = GetPropType<TypeTag, Properties::SolidSystem>;
+    using SST = GetPropType<TypeTag, Properties::SolidState>;
+    using PT = typename GetPropType<TypeTag, Properties::SpatialParams>::PermeabilityType;
+    using MT = GetPropType<TypeTag, Properties::ModelTraits>;
+    using DM = typename GetPropType<TypeTag, Properties::GridGeometry>::DiscretizationMethod;
+    static constexpr bool enableIS = getPropValue<TypeTag, Properties::EnableBoxInterfaceSolver>();
+    // class used for scv-wise reconstruction of nonwetting phase saturations
+    using SR = TwoPScvSaturationReconstruction<DM, enableIS>;
+    using BaseTraits = TwoPVolumeVariablesTraits<PV, FSY, FST, SSY, SST, PT, MT, SR>;
+
+    using DT = GetPropType<TypeTag, Properties::MolecularDiffusionType>;
+    using EDM = GetPropType<TypeTag, Properties::EffectiveDiffusivityModel>;
+
+    template<class BaseTraits, class DT, class EDM>
+    struct NCTraits : public BaseTraits
+    {
+        using DiffusionType = DT;
+        using EffectiveDiffusivityModel = EDM;
+    };
+public:
+    using type = PoreNetwork::TwoPNCVolumeVariables<NCTraits<BaseTraits, DT, EDM>>;
+};
+
+//! The primary variables vector for the 2pnc model
+template<class TypeTag>
+struct PrimaryVariables<TypeTag, TTag::PNMTwoPNC>
+{
+private:
+    using PrimaryVariablesVector = Dune::FieldVector<GetPropType<TypeTag, Properties::Scalar>,
+                                                     GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
+public:
+    using type = SwitchablePrimaryVariables<PrimaryVariablesVector, int>;
+};
+
+//! The spatial parameters to be employed.
+//! Use PNMTwoPSpatialParams by default.
+template<class TypeTag>
+struct SpatialParams<TypeTag, TTag::PNMTwoPNC>
+{
+private:
+    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using LocalRules = PoreNetwork::FluidMatrix::MultiShapeTwoPLocalRules<Scalar>;
+public:
+    using type = PoreNetwork::TwoPDefaultSpatialParams<GridGeometry, Scalar, LocalRules>;
+};
+
+//! The advection type
+template<class TypeTag>
+struct AdvectionType<TypeTag, TTag::PNMTwoPNC>
+{
+private:
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using S = PoreNetwork::TransmissibilityPatzekSilin<Scalar>;
+    using W = PoreNetwork::WettingLayerTransmissibility::RansohoffRadke<Scalar>;
+    using N = PoreNetwork::NonWettingPhaseTransmissibility::BakkeOren<Scalar>;
+
+public:
+    using type = PoreNetwork::CreepingFlow<Scalar, S, W, N>;
+};
+
+template<class TypeTag>
+struct IOFields<TypeTag, TTag::PNMTwoPNC> { using type = PoreNetwork::TwoPNCIOFields; };
+
+//! The grid flux variables cache vector class
+template<class TypeTag>
+struct GridFluxVariablesCache<TypeTag, TTag::PNMTwoPNC>
+{
+private:
+    static constexpr bool enableCache = getPropValue<TypeTag, Properties::EnableGridFluxVariablesCache>();
+    using Problem = GetPropType<TypeTag, Properties::Problem>;
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using FluxVariablesCache = GetPropTypeOr<TypeTag,
+        Properties::FluxVariablesCache, FluxVariablesCaching::EmptyCache<Scalar>
+    >;
+    using Traits = PoreNetwork::PNMTwoPDefaultGridFVCTraits<Problem, FluxVariablesCache>;
+public:
+    using type = PoreNetwork::PNMTwoPGridFluxVariablesCache<Problem, FluxVariablesCache, enableCache, Traits>;
+};
+
+//! The flux variables cache
+template<class TypeTag>
+struct FluxVariablesCache<TypeTag, TTag::PNMTwoPNC>
+{ using type = PoreNetwork::TwoPFluxVariablesCache<GetPropType<TypeTag, Properties::AdvectionType>>; };
+
+//! We use fick's law as the default for the diffusive fluxes
+template<class TypeTag>
+struct MolecularDiffusionType<TypeTag, TTag::PNMTwoPNC>
+{
+private:
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>;
+public:
+    using type = PoreNetwork::PNMFicksLaw<Scalar, ModelTraits::numFluidPhases(), ModelTraits::numFluidComponents()>;
+};
+
+//////////////////////////////////////////////////////////////////
+// Property values for isothermal model required for the general non-isothermal model
+//////////////////////////////////////////////////////////////////
+template<class TypeTag>
+struct ModelTraits<TypeTag, TTag::PNMTwoPNCNI>
+{
+private:
+    //! we use the number of components specified by the fluid system here
+    using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
+    static_assert(FluidSystem::numPhases == 2, "Only fluid systems with 2 fluid phases are supported by the 2p-nc model!");
+    using IsothermalTraits = TwoPNCModelTraits<FluidSystem::numComponents,
+                                               getPropValue<TypeTag, Properties::UseMoles>(),
+                                               getPropValue<TypeTag, Properties::SetMoleFractionsForFirstPhase>(),
+                                               getPropValue<TypeTag, Properties::Formulation>(), getPropValue<TypeTag, Properties::ReplaceCompEqIdx>()>;
+public:
+    using type = PorousMediumFlowNIModelTraits<IsothermalTraits>;
+}; //!< The model traits of the non-isothermal model
+
+//! Set the volume variables property
+template<class TypeTag>
+struct VolumeVariables<TypeTag, TTag::PNMTwoPNCNI>
+{
+private:
+    using PV = GetPropType<TypeTag, Properties::PrimaryVariables>;
+    using FSY = GetPropType<TypeTag, Properties::FluidSystem>;
+    using FST = GetPropType<TypeTag, Properties::FluidState>;
+    using SSY = GetPropType<TypeTag, Properties::SolidSystem>;
+    using SST = GetPropType<TypeTag, Properties::SolidState>;
+    using PT = typename GetPropType<TypeTag, Properties::SpatialParams>::PermeabilityType;
+    using MT = GetPropType<TypeTag, Properties::ModelTraits>;
+    using DM = typename GetPropType<TypeTag, Properties::GridGeometry>::DiscretizationMethod;
+    static constexpr bool enableIS = getPropValue<TypeTag, Properties::EnableBoxInterfaceSolver>();
+    // class used for scv-wise reconstruction of nonwetting phase saturations
+    using SR = TwoPScvSaturationReconstruction<DM, enableIS>;
+    using BaseTraits = TwoPVolumeVariablesTraits<PV, FSY, FST, SSY, SST, PT, MT, SR>;
+
+    using DT = GetPropType<TypeTag, Properties::MolecularDiffusionType>;
+    using EDM = GetPropType<TypeTag, Properties::EffectiveDiffusivityModel>;
+    using ETCM = GetPropType< TypeTag, Properties:: ThermalConductivityModel>;
+
+    template<class BaseTraits, class DT, class EDM, class ETCM>
+    struct NCNITraits : public BaseTraits
+    {
+        using DiffusionType = DT;
+        using EffectiveDiffusivityModel = EDM;
+        using EffectiveThermalConductivityModel = ETCM;
+    };
+public:
+    using type = PoreNetwork::TwoPNCVolumeVariables<NCNITraits<BaseTraits, DT, EDM, ETCM>>;
+};
+
+//! Set non-isothermal output fields
+template<class TypeTag>
+struct IOFields<TypeTag, TTag::PNMTwoPNCNI> { using type = EnergyIOFields<PoreNetwork::TwoPNCIOFields>; };
+
+// Somerton is used as default model to compute the effective thermal heat conductivity
+template<class TypeTag>
+struct ThermalConductivityModel<TypeTag, TTag::PNMTwoPNCNI>
+{
+    using type = ThermalConductivitySomertonTwoP<GetPropType<TypeTag, Properties::Scalar>>;
+};
+
+} // end namespace Dumux::Properties
+
+#endif
diff --git a/dumux/porenetwork/2pnc/volumevariables.hh b/dumux/porenetwork/2pnc/volumevariables.hh
new file mode 100644
index 0000000000000000000000000000000000000000..b6fd98bebd498e502a260cf3207a016b6b3da0c0
--- /dev/null
+++ b/dumux/porenetwork/2pnc/volumevariables.hh
@@ -0,0 +1,89 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+//
+// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+/*!
+ * \file
+ * \ingroup PNMTwoPNCModel
+ * \copydoc Dumux::PoreNetwork::TwoPNCVolumeVariables
+ */
+
+#ifndef DUMUX_PNM_2P_NC_VOLUME_VARIABLES_HH
+#define DUMUX_PNM_2P_NC_VOLUME_VARIABLES_HH
+
+#include <dumux/porousmediumflow/2pnc/volumevariables.hh>
+
+namespace Dumux::PoreNetwork {
+
+/*!
+ * \ingroup PNMTwoPNCModel
+ * \brief Contains the quantities which are constant within a
+ *        finite volume in the two-phase n-components model.
+ */
+template <class Traits>
+class TwoPNCVolumeVariables
+: public Dumux::TwoPNCVolumeVariables<Traits>
+{
+    using ParentType = Dumux::TwoPNCVolumeVariables<Traits>;
+    using Scalar = typename Traits::PrimaryVariables::value_type;
+
+public:
+    //! Export type of fluid system
+    using FluidSystem = typename Traits::FluidSystem;
+    //! Export type of fluid state
+    using FluidState = typename Traits::FluidState;
+    //! Export type of solid state
+    using SolidState = typename Traits::SolidState;
+    //! Export type of solid system
+    using SolidSystem = typename Traits::SolidSystem;
+
+    /*!
+     * \brief Updates all quantities for a given control volume.
+     *
+     * \param elemSol A vector containing all primary variables connected to the element
+     * \param problem The object specifying the problem which ought to
+     *                be simulated
+     * \param element An element which contains part of the control volume
+     * \param scv The sub control volume
+    */
+    template<class ElemSol, class Problem, class Element, class Scv>
+    void update(const ElemSol &elemSol,
+                const Problem &problem,
+                const Element &element,
+                const Scv& scv)
+    {
+        ParentType::update(elemSol, problem, element, scv);
+        poreInscribedRadius_ = problem.spatialParams().poreInscribedRadius(element, scv, elemSol);
+        poreVolume_ = problem.gridGeometry().poreVolume(scv.dofIndex()) * this->porosity();
+        surfaceTension_ = problem.spatialParams().surfaceTension(element, scv, elemSol);
+    }
+
+    /*!
+     * \brief Returns the pore's inscribed radius.
+     */
+    Scalar poreInscribedRadius() const
+    { return poreInscribedRadius_; }
+
+    /*!
+     * \brief Returns the pore volume. // TODO should this be a fraction only?
+     */
+    Scalar poreVolume() const
+    { return poreVolume_; }
+
+    /*!
+     * \brief Returns the surface tension.
+     */
+    Scalar surfaceTension() const
+    { return surfaceTension_; }
+
+protected:
+    Scalar poreInscribedRadius_;
+    Scalar poreVolume_;
+    Scalar surfaceTension_;
+};
+
+} // end namespace Dumux::PoreNetwork
+
+#endif
diff --git a/dumux/porenetwork/CMakeLists.txt b/dumux/porenetwork/CMakeLists.txt
index 6618be881349769efbb0e06c1075d1457dcb79b2..1b9434334cc1eaf70d856f0b82c1298ffd92dee7 100644
--- a/dumux/porenetwork/CMakeLists.txt
+++ b/dumux/porenetwork/CMakeLists.txt
@@ -4,6 +4,7 @@
 add_subdirectory(1p)
 add_subdirectory(1pnc)
 add_subdirectory(2p)
+add_subdirectory(2pnc)
 add_subdirectory(common)
 add_subdirectory(solidenergy)
 add_subdirectory(util)
diff --git a/test/porenetwork/2pnc/CMakeLists.txt b/test/porenetwork/2pnc/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..04791d2e1a4f6f0d88bc61073c238e6c1f4a385e
--- /dev/null
+++ b/test/porenetwork/2pnc/CMakeLists.txt
@@ -0,0 +1,27 @@
+# SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+add_input_file_links()
+dune_symlink_to_source_files(FILES grids)
+
+dumux_add_test(NAME test_pnm_2pnc
+               SOURCES main.cc
+               LABELS porenetwork
+               COMPILE_DEFINITIONS ISOTHERMAL=1
+               COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py
+               CMAKE_GUARD "( dune-foamgrid_FOUND AND HAVE_UMFPACK )"
+               CMD_ARGS      --script fuzzy
+                             --files ${CMAKE_SOURCE_DIR}/test/references/test_pnm_2pnc-reference.vtp
+                                     ${CMAKE_CURRENT_BINARY_DIR}/test_pnm_2pnc-00010.vtp
+                             --command "${CMAKE_CURRENT_BINARY_DIR}/test_pnm_2pnc")
+
+dumux_add_test(NAME test_pnm_2pnc_ni
+               SOURCES main.cc
+               LABELS porenetwork
+               COMPILE_DEFINITIONS ISOTHERMAL=0
+               COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py
+               CMAKE_GUARD "( dune-foamgrid_FOUND AND HAVE_UMFPACK )"
+               CMD_ARGS      --script fuzzy
+                             --files ${CMAKE_SOURCE_DIR}/test/references/test_pnm_2pnc_ni-reference.vtp
+                                     ${CMAKE_CURRENT_BINARY_DIR}/test_pnm_2pnc_ni-00004.vtp
+                             --command "${CMAKE_CURRENT_BINARY_DIR}/test_pnm_2pnc_ni params_ni.input -Problem.Name test_pnm_2pnc_ni")
diff --git a/test/porenetwork/2pnc/grids/1dGrid.dgf b/test/porenetwork/2pnc/grids/1dGrid.dgf
new file mode 100644
index 0000000000000000000000000000000000000000..e3aa06359ff65177b9b5b1a2f6e737d0d1a25ff0
--- /dev/null
+++ b/test/porenetwork/2pnc/grids/1dGrid.dgf
@@ -0,0 +1,20 @@
+DGF
+% SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+% SPDX-License-Identifier: CC-BY-4.0
+% Vertex parameters: PoreInscribedRadius PoreLabel
+% Element parameters: ThroatInscribedRadius ThroatLength ThroatLabel
+Vertex % Coordinates and volumes of the pore bodies
+parameters 2
+0 0 0 0.0002263 2.0
+1 0 0 0.0002263 -1.0
+2 0 0 0.0002263 -1.0
+3 0 0 0.0002263 -1.0
+4 0 0 0.0002263 3.0
+#
+SIMPLEX % Connections of the pore bodies (pore throats)
+parameters 3
+0 1 3.3304e-05 6.6609e-05 2
+1 2 3.3304e-05 6.6609e-05 -1
+2 3 3.3304e-05 6.6609e-05 -1
+3 4 3.3304e-05 6.6609e-05 3
+#
diff --git a/test/porenetwork/2pnc/main.cc b/test/porenetwork/2pnc/main.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b12fb47681e4c5c235706ff633fb9858ea8636f2
--- /dev/null
+++ b/test/porenetwork/2pnc/main.cc
@@ -0,0 +1,162 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+//
+// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+/*!
+ * \file
+ *
+ * \brief Test for the two-phase n-components pore-network model
+ */
+#include <config.h>
+
+#include <ctime>
+#include <iostream>
+
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/common/timer.hh>
+#include <dune/grid/io/file/dgfparser/dgfexception.hh>
+#include <dune/grid/io/file/vtk.hh>
+
+#include <dumux/assembly/fvassembler.hh>
+#include <dumux/common/initialize.hh>
+#include <dumux/common/properties.hh>
+#include <dumux/common/parameters.hh>
+#include <dumux/common/dumuxmessage.hh>
+#include <dumux/io/grid/porenetwork/gridmanager.hh>
+#include <dumux/linear/istlsolvers.hh>
+#include <dumux/linear/linearalgebratraits.hh>
+#include <dumux/linear/linearsolvertraits.hh>
+#include <dumux/porenetwork/common/pnmvtkoutputmodule.hh>
+#include <dumux/porenetwork/2p/newtonsolver.hh>
+
+#include "properties.hh"
+
+int main(int argc, char** argv)
+{
+    using namespace Dumux;
+
+    using TypeTag = Properties::TTag::DrainageProblem;
+
+    // maybe initialize MPI and/or multithreading backend
+    Dumux::initialize(argc, argv);
+    const auto& mpiHelper = Dune::MPIHelper::instance();
+
+    // print dumux start message
+    if (mpiHelper.rank() == 0)
+        DumuxMessage::print(/*firstCall=*/true);
+
+    ////////////////////////////////////////////////////////////
+    // parse the command line arguments and input file
+    ////////////////////////////////////////////////////////////
+
+    // parse command line arguments
+    Parameters::init(argc, argv);
+
+    //////////////////////////////////////////////////////////////////////
+    // try to create a grid (from the given grid file or the input file)
+    /////////////////////////////////////////////////////////////////////
+
+    using GridManager = Dumux::PoreNetwork::GridManager<3>;
+    GridManager gridManager;
+    gridManager.init();
+
+    // we compute on the leaf grid view
+    const auto& leafGridView = gridManager.grid().leafGridView();
+    auto gridData = gridManager.getGridData();
+
+    // create the finite volume grid geometry
+    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+    auto gridGeometry = std::make_shared<GridGeometry>(leafGridView, *gridData);
+
+    // the spatial parameters
+    using SpatialParams = GetPropType<TypeTag, Properties::SpatialParams>;
+    auto spatialParams = std::make_shared<SpatialParams>(gridGeometry);
+
+    // the problem (boundary conditions)
+    using Problem = GetPropType<TypeTag, Properties::Problem>;
+    auto problem = std::make_shared<Problem>(gridGeometry, spatialParams);
+
+    // the solution vector
+    using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
+    SolutionVector x(gridGeometry->numDofs());
+    problem->applyInitialSolution(x);
+    auto xOld = x;
+
+    // the grid variables
+    using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
+    auto gridVariables = std::make_shared<GridVariables>(problem, gridGeometry);
+    gridVariables->init(x);
+
+    // get some time loop parameters
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    const auto tEnd = getParam<Scalar>("TimeLoop.TEnd");
+    const auto maxDt = getParam<Scalar>("TimeLoop.MaxTimeStepSize");
+    auto dt = getParam<Scalar>("TimeLoop.DtInitial");
+
+    // check if we are about to restart a previously interrupted simulation
+    Scalar restartTime = getParam<Scalar>("TimeLoop.Restart", 0);
+
+    // initialize the vtk output module
+    using IOFields = GetPropType<TypeTag, Properties::IOFields>;
+    PoreNetwork::VtkOutputModule<GridVariables, GetPropType<TypeTag, Properties::FluxVariables>, SolutionVector> vtkWriter(*gridVariables, x, problem->name());
+    IOFields::initOutputModule(vtkWriter); //! Add model specific output fields
+
+    vtkWriter.write(0.0);
+
+    // instantiate time loop
+    auto timeLoop = std::make_shared<TimeLoop<Scalar>>(restartTime, dt, tEnd);
+    timeLoop->setMaxTimeStepSize(maxDt);
+
+    // the assembler with time loop for instationary problem
+    using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>;
+    auto assembler = std::make_shared<Assembler>(problem, gridGeometry, gridVariables, timeLoop, xOld);
+
+    // the linear solver
+    using LinearSolver = Dumux::UMFPackIstlSolver<SeqLinearSolverTraits, LinearAlgebraTraitsFromAssembler<Assembler>>;
+    auto linearSolver = std::make_shared<LinearSolver>();
+
+    // the non-linear solver
+    using NewtonSolver = PoreNetwork::TwoPNewtonSolver<Assembler, LinearSolver>;
+    NewtonSolver nonLinearSolver(assembler, linearSolver);
+
+    // time loop
+    timeLoop->start(); do
+    {
+        // try solving the non-linear system
+        nonLinearSolver.solve(x, *timeLoop);
+
+        // make the new solution the old solution
+        xOld = x;
+        gridVariables->advanceTimeStep();
+
+        // advance to the time loop to the next step
+        timeLoop->advanceTimeStep();
+
+        // write vtk output
+        if(problem->shouldWriteOutput(timeLoop->timeStepIndex(), *gridVariables))
+            vtkWriter.write(timeLoop->time());
+
+        // report statistics of this time step
+        timeLoop->reportTimeStep();
+
+        // set new dt as suggested by newton solver
+        timeLoop->setTimeStepSize(nonLinearSolver.suggestTimeStepSize(timeLoop->timeStepSize()));
+
+    } while (!timeLoop->finished());
+
+    ////////////////////////////////////////////////////////////
+    // finalize, print dumux message to say goodbye
+    ////////////////////////////////////////////////////////////
+    timeLoop->finalize(leafGridView.comm());
+
+    // print dumux end message
+    if (mpiHelper.rank() == 0)
+    {
+        Parameters::print();
+        DumuxMessage::print(/*firstCall=*/false);
+    }
+
+    return 0;
+}
diff --git a/test/porenetwork/2pnc/params.input b/test/porenetwork/2pnc/params.input
new file mode 100644
index 0000000000000000000000000000000000000000..42f13ccf19889cd6d57701686e9257347898b0fc
--- /dev/null
+++ b/test/porenetwork/2pnc/params.input
@@ -0,0 +1,31 @@
+[TimeLoop]
+DtInitial = 1e-5 # [s]
+TEnd = 0.01 # [s]
+
+[Grid]
+File = ./grids/1dGrid.dgf
+PoreGeometry = Cube
+ThroatCrossSectionShape = Square
+
+[Problem]
+Name = test_pnm_2pnc
+VtpOutputFrequency = 10 # Write every n-th time step. 0 only writes a file if an invasion / snap-off occurred. -1 writes every step
+EnableGravity = false
+CapillaryPressure = 5000
+UseFixedPressureAndSaturationBoundary = false
+Source = 1e-5
+
+[Vtk]
+AddVelocity = 1
+
+[Newton]
+MaxSteps = 10
+TargetSteps = 4
+MaxRelativeShift = 1e-5
+
+[InvasionState]
+Verbosity = true
+#AccuracyCriterion = 0.99
+
+[SpatialParams]
+HighSwRegularizationMethod = Spline
diff --git a/test/porenetwork/2pnc/params_ni.input b/test/porenetwork/2pnc/params_ni.input
new file mode 100644
index 0000000000000000000000000000000000000000..90c30695d6c7874b0b685f3078ca8932611cc0f8
--- /dev/null
+++ b/test/porenetwork/2pnc/params_ni.input
@@ -0,0 +1,31 @@
+[TimeLoop]
+DtInitial = 1e-5 # [s]
+TEnd = 0.01 # [s]
+
+[Grid]
+File = ./grids/1dGrid.dgf
+PoreGeometry = Cube
+ThroatCrossSectionShape = Square
+
+[Problem]
+Name = test_pnm2pnc_ni
+VtpOutputFrequency = 10 # Write every n-th time step. 0 only writes a file if an invasion / snap-off occurred
+CapillaryPressure = 5000
+EnableGravity = false
+UseFixedPressureAndSaturationBoundary = true
+InletTemperature = 288.15
+OutletTemperature = 283.15
+Source = 1e-5
+
+[Vtk]
+AddVelocity = 1
+
+[Newton]
+MaxSteps = 10
+TargetSteps = 4
+MaxRelativeShift = 1e-5
+
+[Component]
+SolidHeatCapacity = 1.0 # for compatibility
+SolidDensity = 1.0 # for compatibility
+SolidThermalConductivity = 1.0 # for compatibility
diff --git a/test/porenetwork/2pnc/problem.hh b/test/porenetwork/2pnc/problem.hh
new file mode 100644
index 0000000000000000000000000000000000000000..bf71e5a8ab85c43992e75e23db594c16a576c2f6
--- /dev/null
+++ b/test/porenetwork/2pnc/problem.hh
@@ -0,0 +1,224 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+//
+// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+/*!
+ * \file
+ *
+ * \brief A test problem for the two-phase n-components pore network model.
+ */
+#ifndef DUMUX_PNM_2P_NC_PROBLEM_HH
+#define DUMUX_PNM_2P_NC_PROBLEM_HH
+
+#include <dumux/common/boundarytypes.hh>
+#include <dumux/common/parameters.hh>
+#include <dumux/porousmediumflow/problem.hh>
+#include <dumux/material/components/air.hh>
+
+namespace Dumux {
+
+template <class TypeTag>
+class DrainageProblem : public PorousMediumFlowProblem<TypeTag>
+{
+    using ParentType = PorousMediumFlowProblem<TypeTag>;
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
+    using BoundaryTypes = Dumux::BoundaryTypes<GetPropType<TypeTag, Properties::ModelTraits>::numEq()>;
+    using ElementVolumeVariables = typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView;
+    using FVElementGeometry = typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView;
+    using SubControlVolume = typename FVElementGeometry::SubControlVolume;
+    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+    using GridView = typename GridGeometry::GridView;
+    using GridVariables = GetPropType<TypeTag, Properties::GridVariables>;
+
+    // copy some indices for convenience
+    using Indices = typename GetPropType<TypeTag, Properties::ModelTraits>::Indices;
+    using Labels = GetPropType<TypeTag, Properties::Labels>;
+    using Element = typename GridView::template Codim<0>::Entity;
+    using Vertex = typename GridView::template Codim<GridView::dimension>::Entity;
+
+public:
+    template<class SpatialParams>
+    DrainageProblem(std::shared_ptr<const GridGeometry> gridGeometry, std::shared_ptr<SpatialParams> spatialParams)
+    : ParentType(gridGeometry, spatialParams)
+    {
+        vtpOutputFrequency_ = getParam<int>("Problem.VtpOutputFrequency");
+        useFixedPressureAndSaturationBoundary_ = getParam<bool>("Problem.UseFixedPressureAndSaturationBoundary", false);
+        pc_ = getParam<Scalar>("Problem.CapillaryPressure");
+        source_ = getParam<Scalar>("Problem.Source");
+        inletPressure_ = getParam<Scalar>("Problem.InletPressure", 1e5);
+        outletPressure_ = getParam<Scalar>("Problem.OutletPressure", 1e5);
+#if !ISOTHERMAL
+        inletTemperature_ = getParam<Scalar>("Problem.InletTemperature", 288.15);
+        outletTemperature_ = getParam<Scalar>("Problem.OutletTemperature", 283.15);
+#endif
+    }
+
+    /*!
+     * \name Problem parameters
+     */
+    // \{
+
+    bool shouldWriteOutput(const int timeStepIndex, const GridVariables& gridVariables) const
+    {
+        if (vtpOutputFrequency_ < 0)
+            return true;
+
+        if (vtpOutputFrequency_ == 0)
+            return (timeStepIndex == 0 || gridVariables.gridFluxVarsCache().invasionState().hasChanged());
+        else
+            return (timeStepIndex % vtpOutputFrequency_ == 0 || gridVariables.gridFluxVarsCache().invasionState().hasChanged());
+    }
+
+    // \}
+
+     /*!
+     * \name Boundary conditions
+     */
+    // \{
+    //! Specifies which kind of boundary condition should be used for
+    //! which equation for a sub control volume on the boundary.
+    BoundaryTypes boundaryTypes(const Element& element, const SubControlVolume& scv) const
+    {
+        BoundaryTypes bcTypes;
+
+        // If a global phase pressure difference (pn,inlet - pw,outlet) with fixed saturations is specified, use a Dirichlet BC here
+        if (useFixedPressureAndSaturationBoundary_ && isInletPore_(scv))
+            bcTypes.setAllDirichlet();
+        else if (!useFixedPressureAndSaturationBoundary_ && isInletPore_(scv))
+            bcTypes.setAllNeumann();
+        else if (isOutletPore_(scv))
+            bcTypes.setAllDirichlet();
+
+        return bcTypes;
+    }
+
+
+    //! Evaluate the boundary conditions for a Dirichlet control volume.
+    PrimaryVariables dirichlet(const Element& element,
+                               const SubControlVolume& scv) const
+    {
+        PrimaryVariables values(0.0);
+        values[Indices::pressureIdx] = 1e5;
+        values[Indices::switchIdx] = 0.0;
+
+        // If a global phase pressure difference (pn,inlet - pw,outlet) is specified and the saturation shall also be fixed, apply:
+        // pw,inlet = pw,outlet = 1e5; pn,outlet = pw,outlet + pc(S=0) = pw,outlet; pn,inlet = pw,inlet + pc_
+        if (useFixedPressureAndSaturationBoundary_ && isInletPore_(scv))
+        {
+            values.setState(Indices::bothPhases);
+            values[Indices::pressureIdx] = inletPressure_;
+            values[Indices::switchIdx] = 1.0 - this->spatialParams().fluidMatrixInteraction(element, scv, int()/*dummyElemsol*/).sw(pc_);
+#if !ISOTHERMAL
+            values[Indices::temperatureIdx] = inletTemperature_;
+#endif
+        }
+        else if (isOutletPore_(scv))
+        {
+            values.setState(Indices::firstPhaseOnly);
+            values[Indices::pressureIdx] = outletPressure_;
+            values[Indices::switchIdx] = 0.0;
+#if !ISOTHERMAL
+            values[Indices::temperatureIdx] = outletTemperature_;
+#endif
+        }
+
+        return values;
+    }
+
+    // \}
+
+    /*!
+     * \name Volume terms
+     */
+    // \{
+
+    //! Evaluate the source term for all phases within a given sub-control-volume.
+    PrimaryVariables source(const Element& element,
+                            const FVElementGeometry& fvGeometry,
+                            const ElementVolumeVariables& elemVolVars,
+                            const SubControlVolume& scv) const
+    {
+        PrimaryVariables values(0.0);
+
+        // for isothermal case, we fix injection rate of non-wetting phase at inlet
+        // for non-isothermal case, we fix injection of air enthalpy at inlet
+        if (!useFixedPressureAndSaturationBoundary_ && isInletPore_(scv))
+        {
+            values[Indices::conti0EqIdx + 1] = source_/scv.volume();
+#if !ISOTHERMAL
+            const auto pressure = elemVolVars[scv].pressure(1);
+            const auto airEnthalpy = Components::Air<Scalar>::gasEnthalpy(inletTemperature_, pressure);
+            values[Indices::temperatureIdx] = airEnthalpy * source_ * Components::Air<Scalar>::molarMass()/scv.volume();
+#endif
+        }
+
+        return values;
+    }
+    // \}
+
+    //! Evaluate the initial value for a control volume.
+    PrimaryVariables initial(const Vertex& vertex) const
+    {
+        PrimaryVariables values(0.0);
+        values[Indices::pressureIdx] = outletPressure_;
+
+        // get global index of pore
+        const auto dofIdxGlobal = this->gridGeometry().vertexMapper().index(vertex);
+        if (isInletPore_(dofIdxGlobal))
+        {
+            values.setState(Indices::firstPhaseOnly);
+            values[Indices::switchIdx] = 0.0;
+        }
+        else
+        {
+            values.setState(Indices::firstPhaseOnly);
+            values[Indices::switchIdx] = 0.0;
+        }
+
+#if !ISOTHERMAL
+        values[Indices::temperatureIdx] = outletTemperature_;
+#endif
+
+        return values;
+    }
+
+    //!  Evaluate the initial invasion state of a pore throat
+    bool initialInvasionState(const Element& element) const
+    { return false; }
+
+    // \}
+
+private:
+
+    bool isInletPore_(const SubControlVolume& scv) const
+    {
+        return isInletPore_(scv.dofIndex());
+    }
+
+    bool isInletPore_(const std::size_t dofIdxGlobal) const
+    {
+        return this->gridGeometry().poreLabel(dofIdxGlobal) == Labels::inlet;
+    }
+
+    bool isOutletPore_(const SubControlVolume& scv) const
+    {
+        return this->gridGeometry().poreLabel(scv.dofIndex()) == Labels::outlet;
+    }
+
+    int vtpOutputFrequency_;
+    bool useFixedPressureAndSaturationBoundary_;
+    Scalar pc_;
+    Scalar source_;
+    Scalar inletPressure_;
+    Scalar outletPressure_;
+#if !ISOTHERMAL
+    Scalar inletTemperature_;
+    Scalar outletTemperature_;
+#endif
+};
+} //end namespace Dumux
+
+#endif
diff --git a/test/porenetwork/2pnc/properties.hh b/test/porenetwork/2pnc/properties.hh
new file mode 100644
index 0000000000000000000000000000000000000000..19c02ecff02a5af0e6be0634600e43224a9b2946
--- /dev/null
+++ b/test/porenetwork/2pnc/properties.hh
@@ -0,0 +1,77 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+//
+// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+/*!
+ * \file
+ *
+ * \brief The properties for the two-phase n-components pore network model.
+ */
+#ifndef DUMUX_PNM_2P_NC_PROPERTIES_HH
+#define DUMUX_PNM_2P_NC_PROPERTIES_HH
+
+#include <dune/foamgrid/foamgrid.hh>
+
+#include <dumux/porousmediumflow/problem.hh>
+#include <dumux/porenetwork/2pnc/model.hh>
+#include <dumux/porenetwork/2p/spatialparams.hh>
+#include <dumux/material/fluidmatrixinteractions/porenetwork/pore/2p/multishapelocalrules.hh>
+
+#include <dumux/common/properties.hh>
+
+#include <dumux/material/components/simpleh2o.hh>
+#include <dumux/material/components/tabulatedcomponent.hh>
+#include <dumux/material/fluidsystems/h2oair.hh>
+#include <dumux/porenetwork/common/utilities.hh>
+
+#include "problem.hh"
+#include "spatialparams.hh"
+
+//////////
+// Specify the properties
+//////////
+namespace Dumux::Properties {
+
+// Create new type tags
+namespace TTag {
+#if ISOTHERMAL
+struct DrainageProblem { using InheritsFrom = std::tuple<PNMTwoPNC>; };
+#else
+struct DrainageProblem { using InheritsFrom = std::tuple<PNMTwoPNCNI>; };
+#endif
+} // end namespace TTag
+
+// Set the problem property
+template<class TypeTag>
+struct Problem<TypeTag, TTag::DrainageProblem> { using type = DrainageProblem<TypeTag>; };
+
+template<class TypeTag>
+struct FluidSystem<TypeTag, TTag::DrainageProblem>
+{
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using H2OType = Components::TabulatedComponent<Components::H2O<Scalar> >;
+    using Policy = FluidSystems::H2OAirDefaultPolicy<false/*fastButSimplifiedRelations*/>;
+    using type = FluidSystems::H2OAir<Scalar, H2OType, Policy, true/*useKelvinVaporPressure*/>;
+
+};
+
+template<class TypeTag>
+struct SpatialParams<TypeTag, TTag::DrainageProblem>
+{
+private:
+    using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>;
+    using Scalar = GetPropType<TypeTag, Properties::Scalar>;
+    using LocalRules = PoreNetwork::FluidMatrix::MultiShapeTwoPLocalRules<Scalar>;
+public:
+    using type = PoreNetwork::TwoPNCDrainageSpatialParams<GridGeometry, Scalar, LocalRules>;
+};
+
+// Set the grid type
+template<class TypeTag>
+struct Grid<TypeTag, TTag::DrainageProblem> { using type = Dune::FoamGrid<1, 3>; };
+
+} //end namespace Dumux::Properties
+
+#endif
diff --git a/test/porenetwork/2pnc/spatialparams.hh b/test/porenetwork/2pnc/spatialparams.hh
new file mode 100644
index 0000000000000000000000000000000000000000..86dc93f5b4c9a1b18ebe1d41e6d035e7de5a053d
--- /dev/null
+++ b/test/porenetwork/2pnc/spatialparams.hh
@@ -0,0 +1,69 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+//
+// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+/*!
+ * \file
+ * \ingroup PoreNetworkModels
+ * \ingroup SpatialParameters
+ * \brief Spatial parameters for a 2pnc pore-network model
+ */
+
+#ifndef DUMUX_PNM_2P_NC_DRAINAGE_SPATIAL_PARAMS_HH
+#define DUMUX_PNM_2P_NC_DRAINAGE_SPATIAL_PARAMS_HH
+
+#include <dumux/porenetwork/2p/spatialparams.hh>
+
+namespace Dumux::PoreNetwork {
+
+template<class GridGeometry, class Scalar, class MaterialLawT>
+class TwoPNCDrainageSpatialParams
+: public TwoPSpatialParams<GridGeometry, Scalar, MaterialLawT, TwoPNCDrainageSpatialParams<GridGeometry, Scalar, MaterialLawT>>
+{
+    using ParentType = TwoPSpatialParams<GridGeometry, Scalar, MaterialLawT, TwoPNCDrainageSpatialParams<GridGeometry, Scalar, MaterialLawT>>;
+
+    using GridView = typename GridGeometry::GridView;
+    using Element = typename GridView::template Codim<0>::Entity;
+    using FVElementGeometry = typename GridGeometry::LocalView;
+    using SubControlVolume = typename GridGeometry::SubControlVolume;
+    using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
+public:
+    using PermeabilityType = Scalar;
+    using ParentType::ParentType;
+
+    TwoPNCDrainageSpatialParams(std::shared_ptr<const GridGeometry> gridGeometry)
+    : ParentType(gridGeometry)
+    {
+        temperature_ = getParam<Scalar>("SpatialParams.Temperature", 283.15);
+        gamma_ = getParam<Scalar>("SpatialParams.SurfaceTension", 0.0725); // default to surface tension of water/air
+        theta_ = getParam<Scalar>("SpatialParams.ContactAngle", 0.0);
+    }
+
+    //! \brief Function for defining the temperature
+    Scalar temperatureAtPos(const GlobalPosition& globalPos) const
+    { return temperature_; }
+
+    //! \brief Function for defining the wetting phase
+    template<class FluidSystem>
+    int wettingPhaseAtPos(const GlobalPosition& globalPos) const
+    { return FluidSystem::phase0Idx; }
+
+
+    //! \brief Function for defining the contact angle
+    int contactAngleAtPos(const GlobalPosition& globalPos) const
+    { return theta_; }
+
+    //! \brief Function for defining the surface tension
+    Scalar surfaceTensionAtPos(const GlobalPosition& globalPos) const
+    { return gamma_; }
+
+private:
+    Scalar temperature_;
+    Scalar gamma_;
+    Scalar theta_;
+};
+} // end namespace Dumux::PoreNetwork
+
+#endif
diff --git a/test/porenetwork/CMakeLists.txt b/test/porenetwork/CMakeLists.txt
index 4cb5469ebdb3bb3d4f3ba1ca00c9383c560f2ca5..73edd9468deca4edf5a6fe4d4f66e18ffff3c4fb 100644
--- a/test/porenetwork/CMakeLists.txt
+++ b/test/porenetwork/CMakeLists.txt
@@ -5,3 +5,4 @@ add_subdirectory(1p)
 add_subdirectory(1pnc)
 add_subdirectory(2p)
 add_subdirectory(solidenergy)
+add_subdirectory(2pnc)
diff --git a/test/references/test_pnm_2pnc-reference.vtp b/test/references/test_pnm_2pnc-reference.vtp
new file mode 100644
index 0000000000000000000000000000000000000000..5ad168b997c1c8647e8139f31177ac71791ac7b2
--- /dev/null
+++ b/test/references/test_pnm_2pnc-reference.vtp
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+<VTKFile type="PolyData" version="0.1" byte_order="LittleEndian">
+  <PolyData>
+    <Piece NumberOfLines="4" NumberOfPoints="5">
+      <PointData Scalars="S_liq">
+        <DataArray type="Float32" Name="S_liq" NumberOfComponents="1" format="ascii">
+          0.0374111 0.0474591 0.0343665 0.0391619 1
+        </DataArray>
+        <DataArray type="Float32" Name="p_liq" NumberOfComponents="1" format="ascii">
+          99081.6 99126.6 97908.1 97768.2 100000
+        </DataArray>
+        <DataArray type="Float32" Name="rho_liq" NumberOfComponents="1" format="ascii">
+          999.712 999.712 999.711 999.711 999.701
+        </DataArray>
+        <DataArray type="Float32" Name="mob_liq" NumberOfComponents="1" format="ascii">
+          765.754 765.754 765.753 765.753 765.754
+        </DataArray>
+        <DataArray type="Float32" Name="S_gas" NumberOfComponents="1" format="ascii">
+          0.962589 0.952541 0.965634 0.960838 0
+        </DataArray>
+        <DataArray type="Float32" Name="p_gas" NumberOfComponents="1" format="ascii">
+          101923 101441 100971 100498 100000
+        </DataArray>
+        <DataArray type="Float32" Name="rho_gas" NumberOfComponents="1" format="ascii">
+          1.24808 1.24214 1.23636 1.23055 0.00940657
+        </DataArray>
+        <DataArray type="Float32" Name="mob_gas" NumberOfComponents="1" format="ascii">
+          56885.7 56887.5 56889.3 56891.1 103741
+        </DataArray>
+        <DataArray type="Float32" Name="pc" NumberOfComponents="1" format="ascii">
+          2841.63 2314.36 3062.68 2730.15 0
+        </DataArray>
+        <DataArray type="Float32" Name="porosity" NumberOfComponents="1" format="ascii">
+          1 1 1 1 1
+        </DataArray>
+        <DataArray type="Float32" Name="x^H2O_liq" NumberOfComponents="1" format="ascii">
+          0.999981 0.999982 0.999982 0.999982 1
+        </DataArray>
+        <DataArray type="Float32" Name="X^H2O_liq" NumberOfComponents="1" format="ascii">
+          0.99997 0.99997 0.99997 0.999971 1
+        </DataArray>
+        <DataArray type="Float32" Name="x^Air_liq" NumberOfComponents="1" format="ascii">
+          1.8543e-05 1.84542e-05 1.83676e-05 1.82806e-05 0
+        </DataArray>
+        <DataArray type="Float32" Name="X^Air_liq" NumberOfComponents="1" format="ascii">
+          2.98082e-05 2.96654e-05 2.95262e-05 2.93864e-05 0
+        </DataArray>
+        <DataArray type="Float32" Name="rhoMolar_liq" NumberOfComponents="1" format="ascii">
+          55492.1 55492.1 55492.1 55492.1 55492.2
+        </DataArray>
+        <DataArray type="Float32" Name="x^H2O_gas" NumberOfComponents="1" format="ascii">
+          0.0120499 0.0121072 0.0121635 0.0122207 0.0122818
+        </DataArray>
+        <DataArray type="Float32" Name="X^H2O_gas" NumberOfComponents="1" format="ascii">
+          0.00753016 0.00756613 0.00760153 0.00763743 0.0122818
+        </DataArray>
+        <DataArray type="Float32" Name="x^Air_gas" NumberOfComponents="1" format="ascii">
+          0.98795 0.987893 0.987836 0.987779 0
+        </DataArray>
+        <DataArray type="Float32" Name="X^Air_gas" NumberOfComponents="1" format="ascii">
+          0.99247 0.992434 0.992399 0.992363 0
+        </DataArray>
+        <DataArray type="Float32" Name="rhoMolar_gas" NumberOfComponents="1" format="ascii">
+          43.2939 43.089 42.8893 42.6886 0.522147
+        </DataArray>
+        <DataArray type="Float32" Name="phase presence" NumberOfComponents="1" format="ascii">
+          3 3 3 3 1
+        </DataArray>
+        <DataArray type="Float32" Name="poreInscribedRadius" NumberOfComponents="1" format="ascii">
+          0.0002263 0.0002263 0.0002263 0.0002263 0.0002263
+        </DataArray>
+        <DataArray type="Float32" Name="coordinationNumber" NumberOfComponents="1" format="ascii">
+          1 2 2 2 1
+        </DataArray>
+        <DataArray type="Float32" Name="poreLabel" NumberOfComponents="1" format="ascii">
+          2 -1 -1 -1 3
+        </DataArray>
+      </PointData>
+      <CellData Scalars="process rank" Vectors="velocity_liq (m/s)">
+        <DataArray type="Float32" Name="velocity_liq (m/s)" NumberOfComponents="3" format="ascii">
+          -0.00296711 -0 -0 0.0692308 0 0 0.00794862 0 0 -0.159574 -0 -0
+        </DataArray>
+        <DataArray type="Float32" Name="velocity_gas (m/s)" NumberOfComponents="3" format="ascii">
+          60.2882 0 0 59.377 0 0 59.6628 0 0 61.9152 0 0
+        </DataArray>
+        <DataArray type="Float32" Name="process rank" NumberOfComponents="1" format="ascii">
+          0 0 0 0
+        </DataArray>
+        <DataArray type="Float32" Name="throatLabel" NumberOfComponents="1" format="ascii">
+          2 -1 -1 3
+        </DataArray>
+        <DataArray type="Float32" Name="throatInscribedRadius" NumberOfComponents="1" format="ascii">
+          3.3304e-05 3.3304e-05 3.3304e-05 3.3304e-05
+        </DataArray>
+        <DataArray type="Float32" Name="throatLength" NumberOfComponents="1" format="ascii">
+          6.6609e-05 6.6609e-05 6.6609e-05 6.6609e-05
+        </DataArray>
+        <DataArray type="Float32" Name="pcEntry" NumberOfComponents="1" format="ascii">
+          4106.16 4106.16 4106.16 4106.16
+        </DataArray>
+        <DataArray type="Float32" Name="transmissibilityW" NumberOfComponents="1" format="ascii">
+          4.81607e-17 3.56908e-17 3.56908e-17 5.65214e-17
+        </DataArray>
+        <DataArray type="Float32" Name="transmissibilityN" NumberOfComponents="1" format="ascii">
+          8.5211e-15 8.78119e-15 8.78119e-15 8.36682e-15
+        </DataArray>
+        <DataArray type="Float32" Name="volumeFluxW" NumberOfComponents="1" format="ascii">
+          1.65794e-12 3.33017e-11 3.82348e-12 9.65956e-11
+        </DataArray>
+        <DataArray type="Float32" Name="volumeFluxN" NumberOfComponents="1" format="ascii">
+          2.33789e-07 2.34872e-07 2.36002e-07 2.37215e-07
+        </DataArray>
+      </CellData>
+      <Points>
+        <DataArray type="Float32" Name="Coordinates" NumberOfComponents="3" format="ascii">
+          0 0 0 1 0 0 2 0 0 3 0 0
+          4 0 0
+        </DataArray>
+      </Points>
+      <Lines>
+        <DataArray type="Int32" Name="connectivity" NumberOfComponents="1" format="ascii">
+          0 1 1 2 2 3 3 4
+        </DataArray>
+        <DataArray type="Int32" Name="offsets" NumberOfComponents="1" format="ascii">
+          2 4 6 8
+        </DataArray>
+      </Lines>
+    </Piece>
+  </PolyData>
+</VTKFile>
diff --git a/test/references/test_pnm_2pnc_ni-reference.vtp b/test/references/test_pnm_2pnc_ni-reference.vtp
new file mode 100644
index 0000000000000000000000000000000000000000..be60712cea5a4e52236baa9770af90938e5835ed
--- /dev/null
+++ b/test/references/test_pnm_2pnc_ni-reference.vtp
@@ -0,0 +1,133 @@
+<?xml version="1.0"?>
+<VTKFile type="PolyData" version="0.1" byte_order="LittleEndian">
+  <PolyData>
+    <Piece NumberOfLines="4" NumberOfPoints="5">
+      <PointData Scalars="S_liq">
+        <DataArray type="Float32" Name="S_liq" NumberOfComponents="1" format="ascii">
+          0.0200785 0.0261951 0.948722 1 1
+        </DataArray>
+        <DataArray type="Float32" Name="p_liq" NumberOfComponents="1" format="ascii">
+          100000 101052 104283 102142 100000
+        </DataArray>
+        <DataArray type="Float32" Name="rho_liq" NumberOfComponents="1" format="ascii">
+          999.111 999.711 999.715 999.705 999.701
+        </DataArray>
+        <DataArray type="Float32" Name="mob_liq" NumberOfComponents="1" format="ascii">
+          879.067 766.229 765.823 765.781 765.754
+        </DataArray>
+        <DataArray type="Float32" Name="S_gas" NumberOfComponents="1" format="ascii">
+          0.979922 0.973805 0.0512775 0 0
+        </DataArray>
+        <DataArray type="Float32" Name="p_gas" NumberOfComponents="1" format="ascii">
+          105000 104963 104925 102142 100000
+        </DataArray>
+        <DataArray type="Float32" Name="rho_gas" NumberOfComponents="1" format="ascii">
+          1.26143 1.28536 1.28499 0.379949 0.00940657
+        </DataArray>
+        <DataArray type="Float32" Name="mob_gas" NumberOfComponents="1" format="ascii">
+          56207.5 56871.4 56874.1 57633.3 103741
+        </DataArray>
+        <DataArray type="Float32" Name="pc" NumberOfComponents="1" format="ascii">
+          5000 3911.23 641.727 0 -0
+        </DataArray>
+        <DataArray type="Float32" Name="porosity" NumberOfComponents="1" format="ascii">
+          1 1 1 1 1
+        </DataArray>
+        <DataArray type="Float32" Name="x^H2O_liq" NumberOfComponents="1" format="ascii">
+          0.999983 0.999981 0.999981 0.999994 1
+        </DataArray>
+        <DataArray type="Float32" Name="X^H2O_liq" NumberOfComponents="1" format="ascii">
+          0.999973 0.999969 0.999969 0.999991 1
+        </DataArray>
+        <DataArray type="Float32" Name="x^Air_liq" NumberOfComponents="1" format="ascii">
+          1.70916e-05 1.90931e-05 1.90944e-05 5.54692e-06 0
+        </DataArray>
+        <DataArray type="Float32" Name="X^Air_liq" NumberOfComponents="1" format="ascii">
+          2.74751e-05 3.06925e-05 3.06946e-05 8.91683e-06 0
+        </DataArray>
+        <DataArray type="Float32" Name="rhoMolar_liq" NumberOfComponents="1" format="ascii">
+          55458.8 55492.1 55492.3 55492.2 55492.2
+        </DataArray>
+        <DataArray type="Float32" Name="x^H2O_gas" NumberOfComponents="1" format="ascii">
+          0.0162449 0.0117178 0.0117075 0.0120252 0.0122818
+        </DataArray>
+        <DataArray type="Float32" Name="X^H2O_gas" NumberOfComponents="1" format="ascii">
+          0.0101679 0.00732173 0.00731526 0.00759294 0.0122818
+        </DataArray>
+        <DataArray type="Float32" Name="x^Air_gas" NumberOfComponents="1" format="ascii">
+          0.983755 0.988282 0.988293 0.294909 0
+        </DataArray>
+        <DataArray type="Float32" Name="X^Air_gas" NumberOfComponents="1" format="ascii">
+          0.989832 0.992678 0.992685 0.299341 0
+        </DataArray>
+        <DataArray type="Float32" Name="rhoMolar_gas" NumberOfComponents="1" format="ascii">
+          43.8272 44.5816 44.5685 13.3171 0.522147
+        </DataArray>
+        <DataArray type="Float32" Name="phase presence" NumberOfComponents="1" format="ascii">
+          3 3 3 1 1
+        </DataArray>
+        <DataArray type="Float32" Name="poreInscribedRadius" NumberOfComponents="1" format="ascii">
+          0.0002263 0.0002263 0.0002263 0.0002263 0.0002263
+        </DataArray>
+        <DataArray type="Float32" Name="T" NumberOfComponents="1" format="ascii">
+          288.15 283.172 283.153 283.151 283.15
+        </DataArray>
+        <DataArray type="Float32" Name="coordinationNumber" NumberOfComponents="1" format="ascii">
+          1 2 2 2 1
+        </DataArray>
+        <DataArray type="Float32" Name="poreLabel" NumberOfComponents="1" format="ascii">
+          2 -1 -1 -1 3
+        </DataArray>
+      </PointData>
+      <CellData Scalars="process rank" Vectors="velocity_liq (m/s)">
+        <DataArray type="Float32" Name="velocity_liq (m/s)" NumberOfComponents="3" format="ascii">
+          -0.0224304 -0 -0 -0.112597 -0 -0 3.83914 0 0 3.83908 0 0
+        </DataArray>
+        <DataArray type="Float32" Name="velocity_gas (m/s)" NumberOfComponents="3" format="ascii">
+          4.82473 0 0 4.88488 0 0 0 0 0 0 0 0
+        </DataArray>
+        <DataArray type="Float32" Name="process rank" NumberOfComponents="1" format="ascii">
+          0 0 0 0
+        </DataArray>
+        <DataArray type="Float32" Name="throatLabel" NumberOfComponents="1" format="ascii">
+          2 -1 -1 3
+        </DataArray>
+        <DataArray type="Float32" Name="throatInscribedRadius" NumberOfComponents="1" format="ascii">
+          3.3304e-05 3.3304e-05 3.3304e-05 3.3304e-05
+        </DataArray>
+        <DataArray type="Float32" Name="throatLength" NumberOfComponents="1" format="ascii">
+          6.6609e-05 6.6609e-05 6.6609e-05 6.6609e-05
+        </DataArray>
+        <DataArray type="Float32" Name="pcEntry" NumberOfComponents="1" format="ascii">
+          4106.16 4106.16 4106.16 4106.16
+        </DataArray>
+        <DataArray type="Float32" Name="transmissibilityW" NumberOfComponents="1" format="ascii">
+          5.02435e-18 1.34185e-17 1.03853e-14 1.03853e-14
+        </DataArray>
+        <DataArray type="Float32" Name="transmissibilityN" NumberOfComponents="1" format="ascii">
+          9.81542e-15 9.41615e-15 0 0
+        </DataArray>
+        <DataArray type="Float32" Name="volumeFluxW" NumberOfComponents="1" format="ascii">
+          4.04824e-12 3.32099e-11 1.70328e-08 1.70325e-08
+        </DataArray>
+        <DataArray type="Float32" Name="volumeFluxN" NumberOfComponents="1" format="ascii">
+          2.05347e-08 2.02316e-08 0 0
+        </DataArray>
+      </CellData>
+      <Points>
+        <DataArray type="Float32" Name="Coordinates" NumberOfComponents="3" format="ascii">
+          0 0 0 1 0 0 2 0 0 3 0 0
+          4 0 0
+        </DataArray>
+      </Points>
+      <Lines>
+        <DataArray type="Int32" Name="connectivity" NumberOfComponents="1" format="ascii">
+          0 1 1 2 2 3 3 4
+        </DataArray>
+        <DataArray type="Int32" Name="offsets" NumberOfComponents="1" format="ascii">
+          2 4 6 8
+        </DataArray>
+      </Lines>
+    </Piece>
+  </PolyData>
+</VTKFile>