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>