From 0a89a40f89eee607b047c68873964e01d2f6f8aa Mon Sep 17 00:00:00 2001
From: podlesny <podlesny@mi.fu-berlin.de>
Date: Thu, 11 Apr 2019 18:10:59 +0200
Subject: [PATCH] .

---
 src/CMakeLists.txt                |   1 +
 src/nodalweights.cc               |  75 +++++++
 src/nodalweights.hh               |  37 ++++
 src/tests/CMakeLists.txt          |   2 +
 src/tests/common.hh               |  62 ++++++
 src/tests/gridgluefrictiontest.cc | 327 ++++++++++++++++++++++++++++++
 src/tests/nodalweightstest.cc     | 170 ++++++++++++++++
 src/utils/debugutils.hh           |  98 ++++++++-
 8 files changed, 762 insertions(+), 10 deletions(-)
 create mode 100644 src/nodalweights.cc
 create mode 100644 src/nodalweights.hh
 create mode 100644 src/tests/common.hh
 create mode 100644 src/tests/gridgluefrictiontest.cc
 create mode 100644 src/tests/nodalweightstest.cc

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8a218775..32c35011 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -25,6 +25,7 @@ set(SW_SOURCE_FILES
 
 set(MSW_SOURCE_FILES
   assemblers.cc
+  nodalweights.cc
   data-structures/body.cc
   #data-structures/contactnetwork.cc
   data-structures/enumparser.cc
diff --git a/src/nodalweights.cc b/src/nodalweights.cc
new file mode 100644
index 00000000..910585f1
--- /dev/null
+++ b/src/nodalweights.cc
@@ -0,0 +1,75 @@
+#include "utils/almostequal.hh"
+
+#include "nodalweights.hh"
+
+template <class Basis0, class Basis1>
+NodalWeights<Basis0, Basis1>::NodalWeights(const Basis0& basis0, const Basis1& basis1)
+    : basis0_(basis0),
+      basis1_(basis1)
+    {}
+
+template <class Basis0, class Basis1>
+template <class Basis, class Element, class GlobalCoords>
+auto NodalWeights<Basis0, Basis1>::basisDof(const Basis& basis, const Element& elem, const GlobalCoords& vertex) const {
+    int dof = -1;
+
+    const typename Basis::LocalFiniteElement& lFE = basis.getLocalFiniteElement(elem);
+    const auto& geometry = elem.geometry();
+    const auto& localVertex = geometry.local(vertex);
+
+    const size_t localBasisSize = lFE.localBasis().size();
+    std::vector<Dune::FieldVector<double, 1>, std::allocator<Dune::FieldVector<double, 1> > > localBasisRep(localBasisSize);
+    lFE.localBasis().evaluateFunction(localVertex, localBasisRep);
+
+    for(size_t i=0; i<localBasisSize; i++) {
+        if (almost_equal(localBasisRep[i][0], 1.0, 2)) {
+            dof = basis.index(elem, i);
+            break;
+        }
+    }
+
+    return dof;
+}
+
+template <class Basis0, class Basis1>
+template <class GridGlue, class ScalarVector>
+void NodalWeights<Basis0, Basis1>::assemble(const GridGlue& glue, ScalarVector& weights0, ScalarVector& weights1, bool initializeVector) const {
+    using ctype = typename ScalarVector::field_type;
+
+    if (initializeVector==true) {
+        weights0.resize(basis0_.size());
+        weights1.resize(basis1_.size());
+    }
+
+    // loop over all intersections
+    for (const auto& rIs : intersections(glue)) {
+        const auto& inside = rIs.inside();
+        const auto& outside = rIs.outside();
+
+        /*if (!nmBoundary.contains(inside, rIs.indexInInside())) {
+            std::cout << "it happened" << std::endl;
+            continue;
+        }*/
+
+        const auto& geometry = rIs.geometry();
+        const ctype val = 1.0/(geometry.mydimension + 1)*geometry.volume();
+
+        std::cout << geometry.mydimension  << " " << geometry.volume() << " " << val << std::endl;
+
+        for (int i=0; i<geometry.corners(); i++) {
+            const auto& vertex = geometry.corner(i);
+
+            const int inIdx = basisDof(basis0_, inside, vertex);
+            if (inIdx >= 0) {
+                weights0[inIdx] += val;
+            }
+
+            const int outIdx = basisDof(basis1_, outside, vertex);
+            if (outIdx >= 0) {
+                weights1[outIdx] += val;
+            }
+
+            std::cout << inIdx << " " << outIdx << std::endl;
+        }
+    }
+}
diff --git a/src/nodalweights.hh b/src/nodalweights.hh
new file mode 100644
index 00000000..bafd4d96
--- /dev/null
+++ b/src/nodalweights.hh
@@ -0,0 +1,37 @@
+#ifndef SRC_NODALWEIGHTS_HH
+#define SRC_NODALWEIGHTS_HH
+
+
+/**
+ * let merged contact boundary Gamma be given by GridGlue object;
+ * computes
+ *                  int_Gamma lambda_i dx,
+ * where lambda_i is nodal basis of merged contact boundary whose
+ * dofs are given by nonmortar and mortar dofs;
+ *
+ *
+ * NOTE: works only for P1 nodal bases
+ **/
+
+template <class Basis0, class Basis1>
+class NodalWeights {
+private:
+    enum {dim = Basis0::GridView::Grid::dimension};
+
+    template <class Basis, class Element, class GlobalCoords>
+    auto basisDof(const Basis& basis, const Element& elem, const GlobalCoords& vertex) const;
+
+public:
+    NodalWeights(const Basis0& basis0, const Basis1& basis1);
+
+    template <class GridGlue, class ScalarVector>
+    void assemble(const GridGlue& glue, ScalarVector& weights0, ScalarVector& weights1, bool initializeVector = true) const;
+
+private:
+    const Basis0& basis0_;
+    const Basis1& basis1_;
+};
+
+#include "nodalweights.cc"
+
+#endif
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 4109f1b9..8ca00f64 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -1 +1,3 @@
 dune_add_test(SOURCES globalfrictioncontainertest.cc)
+dune_add_test(SOURCES gridgluefrictiontest.cc)
+dune_add_test(SOURCES nodalweightstest.cc)
diff --git a/src/tests/common.hh b/src/tests/common.hh
new file mode 100644
index 00000000..7e679834
--- /dev/null
+++ b/src/tests/common.hh
@@ -0,0 +1,62 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#ifndef DUNE_TECTONIC_SRC_TESTS_COMMON_HH
+#define DUNE_TECTONIC_SRC_TESTS_COMMON_HH
+
+#include <dune/grid/common/gridfactory.hh>
+#include <dune/grid/utility/structuredgridfactory.hh>
+
+#include <dune/fufem/referenceelementhelper.hh>
+
+// utility functions
+bool isClose(double a, double b) {
+  return std::abs(a - b) < 1e-14;
+}
+
+template <class Vector>
+bool xyCollinear(Vector const &a, Vector const &b, Vector const &c) {
+  return isClose((b[0] - a[0]) * (c[1] - a[1]), (b[1] - a[1]) * (c[0] - a[0]));
+}
+
+template <class Vector>
+bool xyBoxed(Vector const &v1, Vector const &v2, Vector const &x) {
+  auto const minmax0 = std::minmax(v1[0], v2[0]);
+  auto const minmax1 = std::minmax(v1[1], v2[1]);
+
+  if (minmax0.first - 1e-14 > x[0] or
+      x[0] > minmax0.second + 1e-14)
+    return false;
+  if (minmax1.first - 1e-14 > x[1] or
+      x[1] > minmax1.second + 1e-14)
+    return false;
+
+  return true;
+}
+
+template <class Vector>
+bool xyBetween(Vector const &v1, Vector const &v2, Vector const &x) {
+  return xyCollinear(v1, v2, x) && xyBoxed(v1, v2, x);
+}
+
+// build cube grid given by lowerLeft and upperRight point in global coordinates
+template <class GlobalCoords, class GridType>
+void buildGrid(const GlobalCoords& lowerLeft, const GlobalCoords& upperRight, const int n, std::shared_ptr<GridType>& grid, bool simplexGrid = true) {
+    std::array<unsigned int, GridType::dimension> elements;
+    std::fill(elements.begin(), elements.end(), n);
+
+    Dune::GridFactory<GridType> factory;
+    if (!simplexGrid) {
+        Dune::StructuredGridFactory<GridType>::createCubeGrid(factory, lowerLeft, upperRight, elements);
+        grid = std::move(factory.createGrid());
+    } else {
+        Dune::StructuredGridFactory<GridType>::createSimplexGrid(factory, lowerLeft, upperRight, elements);
+        grid = std::move(factory.createGrid());
+    }
+}
+
+template <class Intersection>
+bool containsInsideSubentity(const Intersection& nIt, int subEntity, int codim) {
+    return ReferenceElementHelper<double, Intersection::GridView::dim>::subEntityContainsSubEntity(nIt.inside().type(), nIt.indexInInside(), 1, subEntity, codim);
+}
+
+#endif
diff --git a/src/tests/gridgluefrictiontest.cc b/src/tests/gridgluefrictiontest.cc
new file mode 100644
index 00000000..e66fa3dd
--- /dev/null
+++ b/src/tests/gridgluefrictiontest.cc
@@ -0,0 +1,327 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <exception>
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/common/stdstreams.hh>
+#include <dune/common/fvector.hh>
+#include <dune/common/function.hh>
+
+//#include <dune/fufem/assemblers/assembler.hh>
+#include <dune/fufem/functiontools/basisinterpolator.hh>
+#include <dune/fufem/boundarypatch.hh>
+#include <dune/fufem/functionspacebases/p1nodalbasis.hh>
+
+#include <dune/fufem/functions/basisgridfunction.hh>
+
+#include <dune/grid/uggrid.hh>
+
+#include <dune/grid-glue/adapter/gridgluevtkwriter.hh>
+#include <dune/grid-glue/merging/merger.hh>
+
+#include <dune/contact/projections/normalprojection.hh>
+#include <dune/contact/common/couplingpair.hh>
+#include <dune/contact/assemblers/dualmortarcoupling.hh>
+#include <dune/contact/assemblers/nbodyassembler.hh>
+
+#include "../utils/debugutils.hh"
+
+#include "common.hh"
+
+const int dim = 2;
+const int n = 5;
+const bool simplexGrid = true;
+
+const std::string path = "";
+const std::string outputFile = "gridgluefrictiontest.log";
+
+#if HAVE_UG
+    using GridType = typename Dune::UGGrid<dim>;
+#else
+#error No UG!
+#endif
+    using LevelView = typename GridType::LevelGridView;
+    using LeafView = typename GridType::LeafGridView;
+    using LevelBoundaryPatch = BoundaryPatch<LevelView>;
+    using LeafBoundaryPatch = BoundaryPatch<LeafView>;
+
+    using c_type = double;
+    using GlobalCoords = Dune::FieldVector<c_type, dim>;
+    using Vector = Dune::FieldVector<c_type, 1>;
+    using BlockVector = Dune::BlockVector<Vector>;
+
+    using CouplingPair = Dune::Contact::CouplingPair<GridType, GridType, c_type>;
+    using CouplingType = Dune::Contact::DualMortarCoupling<c_type, GridType>;
+    using NBodyAssembler = Dune::Contact::NBodyAssembler<GridType, BlockVector>;
+
+
+
+// boundary function along y=1.0 line
+template <class VectorType>
+class BoundaryFunction0 : public Dune::VirtualFunction<VectorType, c_type> {
+public:
+    void evaluate(const VectorType& x, c_type& res) const override {
+        if (isClose(x[1], 1.0)) {
+            res = std::sin(x[0]);
+        } else {
+            res = 0.0;
+        }
+    }
+};
+
+// boundary function along y=1.0 line
+template <class VectorType>
+class BoundaryFunction1 : public Dune::VirtualFunction<VectorType, c_type> {
+public:
+    void evaluate(const VectorType& x, c_type& res) const override{
+        if (isClose(x[1], 1.0)) {
+            res = std::cos(x[0]);
+        } else {
+            res = 0.0;
+        }
+    }
+};
+
+
+int main(int argc, char *argv[]) { try {
+    Dune::MPIHelper::instance(argc, argv);
+
+    std::ofstream out(path + outputFile);
+    std::streambuf *coutbuf = std::cout.rdbuf(); //save old buffer
+    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to outputFile
+
+    std::cout << "------------------------------" << std::endl;
+    std::cout << "-- Grid-Glue Friction Test: --" << std::endl;
+    std::cout << "------------------------------" << std::endl << std::endl;
+
+    // building grids
+    std::vector<std::shared_ptr<GridType>> grids(2);
+
+    GlobalCoords lowerLeft0({0, 0});
+    GlobalCoords upperRight0({2, 1});
+    buildGrid(lowerLeft0, upperRight0, n, grids[0]);
+
+    GlobalCoords lowerLeft1({0.25, 1});
+    GlobalCoords upperRight1({1.75, 2});
+    buildGrid(lowerLeft1, upperRight1, n, grids[1]);
+
+    // writing grids
+    for (size_t i=0; i<grids.size(); i++) {
+        const auto& levelView = grids[i]->levelGridView(0);
+        writeToVTK(levelView, path, "body_" + std::to_string(i) + "_level0");
+    }
+
+    // compute coupling boundaries
+    LevelView gridView0 = grids[0]->levelGridView(0);
+    LevelView gridView1 = grids[1]->levelGridView(0);
+    LevelBoundaryPatch upper(gridView0);
+    LevelBoundaryPatch lower(gridView1);
+
+    lower.insertFacesByProperty([&](typename LevelView::Intersection const &in) {
+        return xyBetween(lowerLeft1, {upperRight1[0], lowerLeft1[1]}, in.geometry().center());
+    });
+
+    upper.insertFacesByProperty([&](typename LevelView::Intersection const &in) {
+        return xyBetween({lowerLeft0[0], upperRight0[1]}, upperRight0, in.geometry().center());
+    });
+
+    // set contact coupling
+    Dune::Contact::NormalProjection<LeafBoundaryPatch> contactProjection;
+
+    CouplingPair coupling;
+    coupling.set(0, 1, upper, lower, 0.1, CouplingPair::CouplingType::STICK_SLIP, contactProjection, nullptr);
+
+    double coveredArea_ = 0.8;
+    CouplingType contactCoupling;
+    contactCoupling.setGrids(*grids[0], *grids[1]);
+    contactCoupling.setupContactPatch(*coupling.patch0(),*coupling.patch1());
+    contactCoupling.gridGlueBackend_ = coupling.backend();
+    contactCoupling.setCoveredArea(coveredArea_);
+    contactCoupling.setup();
+
+    // set nBodyAssembler
+   /* std::vector<const GridType*> grids_ptr(grids.size());
+    for (size_t i=0; i<grids_ptr.size(); i++) {
+        grids_ptr[i] = grids[i].get();
+    }
+
+    NBodyAssembler nBodyAssembler(grids.size(), 1);
+    nBodyAssembler.setGrids(grids_ptr);
+
+    nBodyAssembler.setCoupling(coupling, 0);
+
+    nBodyAssembler.assembleTransferOperator();
+    nBodyAssembler.assembleObstacle(); */
+
+    // define basis
+    using Basis = P1NodalBasis<LevelView, double>;
+    Basis basis0(grids[0]->levelGridView(0));
+    Basis basis1(grids[1]->levelGridView(0));
+
+    std::cout << "--------------" << std::endl;
+    std::cout << "--- Basis0 ---" << std::endl;
+    std::cout << "--------------" << std::endl;
+    printBasisDofLocation(basis0);
+
+    std::cout << "--------------" << std::endl;
+    std::cout << "--- Basis1 ---" << std::endl;
+    std::cout << "--------------" << std::endl;
+    printBasisDofLocation(basis1);
+
+    // set grid functions on coupling boundary
+    BlockVector f0, f1;
+
+    BasisInterpolator<Basis, BlockVector, BoundaryFunction0<GlobalCoords>> interpolator0;
+    interpolator0.interpolate(basis0, f0, BoundaryFunction0<GlobalCoords>());
+
+    BasisInterpolator<Basis, BlockVector, BoundaryFunction1<GlobalCoords>> interpolator1;
+    interpolator1.interpolate(basis1, f1, BoundaryFunction1<GlobalCoords>());
+
+    printBoundary(upper, basis0, f0, "f0: ");
+    printBoundary(lower, basis1, f1, "f1: ");
+    writeToVTK(basis0, f0, path, "body_0_level0");
+    writeToVTK(basis1, f1, path, "body_1_level0");
+
+    // merged gridGlue coupling boundary
+    auto& gridGlue = *contactCoupling.getGlue();
+
+    // make basis grid functions
+    auto&& gridFunction0 = Functions::makeFunction(basis0, f0);
+    auto&& gridFunction1 = Functions::makeFunction(basis1, f1);
+
+    for (const auto& rIs : intersections(gridGlue)) {
+        const auto& inside = rIs.inside();
+        const auto& outside = rIs.outside();
+
+        const auto& rGeometry = rIs.geometry();
+        const auto& outGeometry = outside.geometry();
+
+        for (size_t i=0; i<rGeometry.corners(); i++) {
+            typename BasisGridFunction<Basis, BlockVector>::RangeType y;
+            gridFunction1.evaluateLocal(outside, outGeometry.local(rGeometry.corner(i)), y);
+            print(rGeometry.corner(i), "corner " + std::to_string(i));
+            std::cout << "f1(corner) = " << y << std::endl;
+
+            std::cout << std::endl;
+        }
+        std::cout << "---------"<< std::endl;
+       // auto basis.
+       // std::cout << containsInsideSubentity(rIs, 1, 1) << std::endl;
+    }
+
+    //Dune::GridGlue::GridGlueVtkWriter::writeIntersections<std::decltype(gridGlue), 0>(gridGlue, "");//, path + "gridglueintersections0.vtk"); //<std::decltype(gridGlue), 0>
+
+    /*LevelBoundaryPatch boundaryWithMapping(grids[0]->levelGridView(0));
+
+    const auto& indexSet0 = gridView0.indexSet();
+    const auto& indexSet1 = gridView1.indexSet();
+
+    // Get all fine grid boundary segments that are totally covered by the grid-glue segments
+    typedef std::pair<int,int> Pair;
+    std::map<Pair, c_type> coveredArea, fullArea;
+
+    // initialize with area of boundary faces
+    for (const auto& bIt : lower) {
+        const Pair p(indexSet0.index(bIt.inside()),bIt.indexInInside());
+        fullArea[p] = bIt.geometry().volume();
+        coveredArea[p] = 0;
+    }
+
+    // sum up the remote intersection areas to find out which are totally covered
+    for (const auto& rIs : intersections(gridGlue))
+        coveredArea[Pair(indexSet0.index(rIs.inside()),rIs.indexInInside())] += rIs.geometry().volume();
+
+    // add all fine grid faces that are totally covered by the contact mapping
+    for (const auto& bIt : lower) {
+        const auto& inside = bIt.inside();
+        if(coveredArea[Pair(indexSet0.index(inside),bIt.indexInInside())]/
+            fullArea[Pair(indexSet0.index(inside),bIt.indexInInside())] >= coveredArea_)
+            boundaryWithMapping.addFace(inside, bIt.indexInInside());
+    }*/
+
+    //writeBoundary(boundaryWithMapping, path + "relevantNonmortar");
+
+
+    /** \todo replace by all fine grid segments which are totally covered by the RemoteIntersections. */
+    //for (const auto& rIs : intersections(glue))
+    //    boundaryWithMapping.addFace(rIs.inside(),rIs.indexInInside());
+
+  /*  printf("contact mapping could be built for %d of %d boundary segments.\n",
+           boundaryWithMapping.numFaces(), lower.numFaces());
+
+    LevelBoundaryPatch nonmortarBoundary = boundaryWithMapping;
+    LevelBoundaryPatch mortarBoundary;
+    mortarBoundary.setup(gridView1);
+    for (const auto& rIs : intersections(gridGlue))
+        if (nonmortarBoundary.contains(rIs.inside(),rIs.indexInInside()))
+            mortarBoundary.addFace(rIs.outside(),rIs.indexInOutside());*/
+
+
+
+
+
+
+    /** \todo Also restrict mortar indices and don't use the whole grid level. */
+   /* Dune::MatrixIndexSet mortarIndices(nonmortarBoundary_.numVertices(), grid1_->size(dim));
+
+    // Create mapping from the global set of block dofs to the ones on the contact boundary
+    std::vector<int> globalToLocal;
+    nonmortarBoundary_.makeGlobalToLocal(globalToLocal);
+
+    // loop over all intersections
+    for (const auto& rIs : intersections(glue)) {
+
+        if (!nonmortarBoundary_.contains(rIs.inside(),rIs.indexInInside()))
+            continue;
+
+        const auto& inside = rIs.inside();
+        const auto& outside = rIs.outside();
+
+        const auto& domainRefElement = Dune::ReferenceElements<ctype, dim>::general(inside.type());
+        const auto& targetRefElement = Dune::ReferenceElements<ctype, dim>::general(outside.type());
+
+        int nDomainVertices = domainRefElement.size(dim);
+        int nTargetVertices = targetRefElement.size(dim);
+
+        for (int j=0; j<nDomainVertices; j++) {
+
+            int localDomainIdx = globalToLocal[indexSet0.subIndex(inside,j,dim)];
+
+            // if the vertex is not contained in the restricted contact boundary then dismiss it
+            if (localDomainIdx == -1)
+                continue;
+
+            for (int k=0; k<nTargetVertices; k++) {
+                int globalTargetIdx = indexSet1.subIndex(outside,k,dim);
+                if (!mortarBoundary_.containsVertex(globalTargetIdx))
+                    continue;
+
+                mortarIndices.add(localDomainIdx, globalTargetIdx);
+            }
+        }
+    }
+
+    mortarIndices.exportIdx(mortarLagrangeMatrix_);
+
+    // Clear it
+    mortarLagrangeMatrix_ = 0; */
+
+    bool passed = true;
+
+    std::cout << "Overall, the test " << (passed ? "was successful!" : "failed!") << std::endl;
+
+    std::cout.rdbuf(coutbuf); //reset to standard output again
+    return passed ? 0 : 1;
+
+} catch (Dune::Exception &e) {
+    Dune::derr << "Dune reported error: " << e << std::endl;
+} catch (std::exception &e) {
+    std::cerr << "Standard exception: " << e.what() << std::endl;
+} // end try
+} // end main
diff --git a/src/tests/nodalweightstest.cc b/src/tests/nodalweightstest.cc
new file mode 100644
index 00000000..78b3c7c2
--- /dev/null
+++ b/src/tests/nodalweightstest.cc
@@ -0,0 +1,170 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <iostream>
+#include <exception>
+#include <fstream>
+
+#include <dune/grid/uggrid.hh>
+
+#include <dune/fufem/assemblers/assembler.hh>
+#include <dune/fufem/assemblers/localassemblers/neumannboundaryassembler.hh>
+#include <dune/fufem/functions/constantfunction.hh>
+#include <dune/fufem/functionspacebases/p1nodalbasis.hh>
+
+#include <dune/contact/projections/normalprojection.hh>
+#include <dune/contact/common/couplingpair.hh>
+#include <dune/contact/assemblers/dualmortarcoupling.hh>
+
+#include "../utils/debugutils.hh"
+#include "common.hh"
+
+#include "../nodalweights.hh"
+
+const int dim = 2;
+const int n = 5;
+const bool simplexGrid = true;
+
+const std::string path = "";
+const std::string outputFile = "nodalweightstest.log";
+
+#if HAVE_UG
+    using GridType = typename Dune::UGGrid<dim>;
+#else
+#error No UG!
+#endif
+    using LevelView = typename GridType::LevelGridView;
+    using LeafView = typename GridType::LeafGridView;
+    using LevelBoundaryPatch = BoundaryPatch<LevelView>;
+    using LeafBoundaryPatch = BoundaryPatch<LeafView>;
+
+    using c_type = double;
+    using GlobalCoords = Dune::FieldVector<c_type, dim>;
+    using BlockVector = Dune::BlockVector<GlobalCoords>;
+
+    using ScalarVector = Dune::FieldVector<c_type, 1>;
+    using ScalarBlockVector = Dune::BlockVector<ScalarVector>;
+
+    using CouplingPair = Dune::Contact::CouplingPair<GridType, GridType, c_type>;
+    using CouplingType = Dune::Contact::DualMortarCoupling<c_type, GridType>;
+
+int main(int argc, char *argv[]) { try {
+    Dune::MPIHelper::instance(argc, argv);
+
+    std::ofstream out(path + outputFile);
+    std::streambuf *coutbuf = std::cout.rdbuf(); //save old buffer
+    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to outputFile
+
+    std::cout << "------------------------" << std::endl;
+    std::cout << "-- NodalWeights Test: --" << std::endl;
+    std::cout << "------------------------" << std::endl << std::endl;
+
+    // building grids
+    std::vector<std::shared_ptr<GridType>> grids(2);
+
+    GlobalCoords lowerLeft0({0, 0});
+    GlobalCoords upperRight0({2, 1});
+    buildGrid(lowerLeft0, upperRight0, n, grids[0]);
+
+    GlobalCoords lowerLeft1({0, 1});
+    GlobalCoords upperRight1({2, 2});
+    buildGrid(lowerLeft1, upperRight1, n, grids[1]);
+
+    // writing grids
+    for (size_t i=0; i<grids.size(); i++) {
+        const auto& levelView = grids[i]->levelGridView(0);
+        writeToVTK(levelView, path, "body_" + std::to_string(i) + "_level0");
+    }
+
+    // compute coupling boundaries
+    LevelView gridView0 = grids[0]->levelGridView(0);
+    LevelView gridView1 = grids[1]->levelGridView(0);
+    LevelBoundaryPatch upper(gridView0);
+    LevelBoundaryPatch lower(gridView1);
+
+    lower.insertFacesByProperty([&](typename LevelView::Intersection const &in) {
+        return xyBetween(lowerLeft1, {upperRight1[0], lowerLeft1[1]}, in.geometry().center());
+    });
+
+    upper.insertFacesByProperty([&](typename LevelView::Intersection const &in) {
+        return xyBetween({lowerLeft0[0], upperRight0[1]}, upperRight0, in.geometry().center());
+    });
+
+    // set contact coupling
+    Dune::Contact::NormalProjection<LeafBoundaryPatch> contactProjection;
+
+    CouplingPair coupling;
+    coupling.set(0, 1, upper, lower, 0.1, CouplingPair::CouplingType::STICK_SLIP, contactProjection, nullptr);
+
+    double coveredArea_ = 0.8;
+    CouplingType contactCoupling;
+    contactCoupling.setGrids(*grids[0], *grids[1]);
+    contactCoupling.setupContactPatch(*coupling.patch0(),*coupling.patch1());
+    contactCoupling.gridGlueBackend_ = coupling.backend();
+    contactCoupling.setCoveredArea(coveredArea_);
+    contactCoupling.setup();
+
+    using Basis = P1NodalBasis<LevelView, c_type>;
+    Basis basis0(grids[0]->levelGridView(0));
+    Basis basis1(grids[1]->levelGridView(0));
+
+    printBasisDofLocation(basis0);
+    printBasisDofLocation(basis1);
+
+    ScalarBlockVector nWeights0, nWeights1;
+    NodalWeights<Basis, Basis> nodalWeights(basis0, basis1);
+    nodalWeights.assemble(*contactCoupling.getGlue(), nWeights0, nWeights1, true);
+
+    ScalarBlockVector weights0;
+    {
+        Assembler<Basis, Basis> assembler(basis0, basis0);
+        NeumannBoundaryAssembler<GridType, typename ScalarBlockVector::block_type> boundaryAssembler(
+                     std::make_shared<ConstantFunction<
+                     GlobalCoords, typename ScalarBlockVector::block_type>>(1));
+             assembler.assembleBoundaryFunctional(boundaryAssembler, weights0, upper);
+    }
+
+    ScalarBlockVector weights1;
+    {
+        Assembler<Basis, Basis> assembler(basis1, basis1);
+        NeumannBoundaryAssembler<GridType, typename ScalarBlockVector::block_type> boundaryAssembler(
+                     std::make_shared<ConstantFunction<
+                     GlobalCoords, typename ScalarBlockVector::block_type>>(1));
+             assembler.assembleBoundaryFunctional(boundaryAssembler, weights1, lower);
+    }
+
+    print(weights0, "assembled weights0: ");
+    print(nWeights0, "nWeights0: ");
+
+    print(weights1, "assembled weights1: ");
+    print(nWeights1, "nWeights1: ");
+
+    bool sizePassed = true;
+    if (weights0.size() != nWeights0.size() | weights1.size() != nWeights1.size()) {
+        sizePassed = false;
+    }
+
+    bool entriesPassed0 = true;
+    for (size_t i=0; i<weights0.size(); i++) {
+        entriesPassed0 = entriesPassed0 & isClose(weights0[i], nWeights0[i]);
+    }
+
+    bool entriesPassed1 = true;
+    for (size_t i=0; i<weights1.size(); i++) {
+        entriesPassed1 = entriesPassed1 & isClose(weights1[i], nWeights1[i]);
+    }
+
+    bool passed = sizePassed & entriesPassed0 & entriesPassed1;
+
+    std::cout << "Overall, the test " << (passed ? "was successful!" : "failed!") << std::endl;
+
+    std::cout.rdbuf(coutbuf); //reset to standard output again
+    return passed ? 0 : 1;
+
+} catch (Dune::Exception &e) {
+    Dune::derr << "Dune reported error: " << e << std::endl;
+} catch (std::exception &e) {
+    std::cerr << "Standard exception: " << e.what() << std::endl;
+} // end try
+} // end main
diff --git a/src/utils/debugutils.hh b/src/utils/debugutils.hh
index 150aad1c..c81de410 100644
--- a/src/utils/debugutils.hh
+++ b/src/utils/debugutils.hh
@@ -12,7 +12,7 @@
 
 #include <dune/grid/io/file/vtk/vtkwriter.hh>
 
-using namespace std;
+//using namespace std;
 
 
     template <int s>
@@ -33,7 +33,7 @@ using namespace std;
         std::cout << message << std::endl;
 
        for (size_t i=0; i<x.size(); i++) {
-           std::cout << x[i] << ";" << std::endl;;
+           std::cout << x[i] << ";" << std::endl;
        }
 
    }
@@ -184,9 +184,45 @@ using namespace std;
        std::cout.rdbuf( lBufferOld );
    }
 
+   template <class Intersection, class Basis>
+   void printIntersection(const Intersection& it, const Basis& basis, std::string message = "") {
+       if (message != "") {
+           std::cout << message << std::endl;
+       }
+
+       const auto& inside = it.inside();
+       const auto& localCoefficients = basis.getLocalFiniteElement(inside).localCoefficients();
+
+       std::cout << "dofs: ";
+       for (size_t i=0; i<localCoefficients.size(); i++) {
+           unsigned int entity = localCoefficients.localKey(i).subEntity();
+           unsigned int codim  = localCoefficients.localKey(i).codim();
+
+           if (it.containsInsideSubentity(entity, codim)) {
+               int dofIndex = basis.index(it.inside(), i);
+               std::cout << dofIndex << " ";
+               break;
+           }
+       }
+       std::cout << std::endl;
+   }
+
+   template <class BoundaryPatch, class Basis>
+   void printBoundary(const BoundaryPatch& patch, const Basis& basis, std::string message = "") {
+       if (message != "") {
+           std::cout << message << std::endl;
+       }
+
+       for (auto bIt = patch.begin(); bIt != patch.end(); ++bIt) {
+            printIntersection(*bIt, basis, "");
+       }
+
+       std::cout << std::endl;
+   }
+
    template <class BasisType, typename ctype=double>
    void printBasisDofLocation(const BasisType& basis) {
-       typedef typename BasisType::GridView GridView;
+     /*  typedef typename BasisType::GridView GridView;
 
        const int dim = GridView::dimension;
 
@@ -197,12 +233,9 @@ using namespace std;
        const GridView& gridView = basis.getGridView();
        const int gridN = std::pow(gridView.indexSet().size(dim), 1.0/dim)-1;
 
-       typedef typename GridView::template Codim<0>::Iterator ElementIterator;
-       ElementIterator it = gridView.template begin<0>();
-       ElementIterator end = gridView.template end<0>();
-       for (; it != end; ++it) {
-           const typename BasisType::LocalFiniteElement& tFE = basis.getLocalFiniteElement(*it);
-           const auto& geometry = (*it).geometry();
+       for (auto& it : elements(gridView)) {
+           const typename BasisType::LocalFiniteElement& tFE = basis.getLocalFiniteElement(it);
+           const auto& geometry = it.geometry();
 
            for(int i=0; i<geometry.corners(); ++i) {
                const auto& vertex = geometry.corner(i);
@@ -219,7 +252,7 @@ using namespace std;
 
                for(int k=0; k<localBasisSize; ++k) {
                    if (localBasisRep[k]==1) {
-                       int dofIndex = basis.index((*it), k);
+                       int dofIndex = basis.index(it, k);
 
                        if (indexTransformation.count(dofIndex)==0) {
                            indexTransformation[dofIndex] = vertexIndex;
@@ -245,5 +278,50 @@ using namespace std;
            }
            std::cout << std::endl;
        }
+       std::cout << std::endl;*/
+
+       const int dim = BasisType::GridView::dimension;
+
+       std::map<int, Dune::FieldVector<ctype, dim>> indexCoords;
+
+
+       const auto& gridView = basis.getGridView();
+
+       for (auto& it : elements(gridView)) {
+            const typename BasisType::LocalFiniteElement& tFE = basis.getLocalFiniteElement(it);
+            const auto& geometry = it.geometry();
+
+            for(int i=0; i<geometry.corners(); ++i) {
+                const auto& vertex = geometry.corner(i);
+                const auto& local = geometry.local(vertex);
+
+                const int localBasisSize = tFE.localBasis().size();
+                std::vector<Dune::FieldVector<double, 1>, std::allocator<Dune::FieldVector<double, 1> > > localBasisRep(localBasisSize);
+                tFE.localBasis().evaluateFunction(local, localBasisRep);
+
+                for(int k=0; k<localBasisSize; ++k) {
+                    if (1.0 - localBasisRep[k]< 1e-14) {
+                        int dofIndex = basis.index(it, k);
+                        indexCoords[dofIndex] = vertex;
+                        break;
+                    }
+                }
+              }
+       }
+
+       std::cout << "Coords of basis dofs: " << indexCoords.size() << std::endl;
+       auto&& mapIt = indexCoords.begin();
+       const auto& mapEndIt = indexCoords.end();
+       for (; mapIt!=mapEndIt; ++mapIt) {
+            std::cout << mapIt->first << " Coords: ";
+
+            const auto& coords = mapIt->second;
+            for (size_t i=0; i<coords.size(); i++) {
+                std::cout << coords[i] << " ";
+            }
+            std::cout << std::endl;
+       }
+
+       std::cout << std::endl;
    }
 #endif
-- 
GitLab