diff --git a/dune/mmdg/dg.hh b/dune/mmdg/dg.hh
index 014257a2d65ddcffbe86c1f178539fdc4d200348..76def0c56c7a80f6859bd7fe7d646f450560de85 100644
--- a/dune/mmdg/dg.hh
+++ b/dune/mmdg/dg.hh
@@ -27,6 +27,12 @@ public:
   using VTKFunction = Dune::VTKFunction<GridView>;
   using P1Function = Dune::NonconformingP1VTKFunction<GridView,
     Dune::DynamicVector<Scalar>>;
+  using QRuleElem = Dune::QuadratureRule<Scalar, dim>;
+  using QRulesElem = Dune::QuadratureRules<Scalar, dim>;
+  using QRuleEdge = Dune::QuadratureRule<Scalar, dim-1>;
+  using QRulesEdge = Dune::QuadratureRules<Scalar, dim-1>;
+  static constexpr auto simplex = Dune::GeometryTypes::simplex(dim);
+  static constexpr auto edge = Dune::GeometryTypes::simplex(dim-1);
 
   //constructor
   DG (const GridView& gridView, const Mapper& mapper,
@@ -40,10 +46,10 @@ public:
       d = Vector(dof);
     }
 
-  const void operator() (const Scalar K, const Scalar mu)
+  const void operator() (const Scalar mu)
   {
     //assemble stiffness matrix A and load vector b
-    assembleSLE(K, mu);
+    assembleSLE(mu);
 
     Dune::InverseOperatorResult result;
     Dune::UMFPack<Matrix> solver(*A);
@@ -61,12 +67,17 @@ public:
 
 private:
   //assemble stiffness matrix A and load vector b
-  void assembleSLE (const Scalar K, const Scalar mu)
+  void assembleSLE (const Scalar mu)
   {
-    //quadrature rule
-    const Dune::QuadratureRule<Scalar, dim>& rule =
-      Dune::QuadratureRules<Scalar, dim>::rule(
-        Dune::GeometryTypes::simplex(dim), problem_.quadratureOrder());
+    //quadrature rules
+    const QRuleElem& rule_q =
+      QRulesElem::rule(simplex, problem_.quadratureOrder_q());
+    const QRuleElem& rule_K_Elem =
+      QRulesElem::rule(simplex, problem_.quadratureOrder_K());
+    const QRuleEdge& rule_K_Edge =
+      QRulesEdge::rule(edge, problem_.quadratureOrder_K());
+    const QRuleEdge& rule_Kplus1_Edge =
+      QRulesEdge::rule(edge, problem_.quadratureOrder_K() + 1);
 
     //we use the basis
     // phi_elem,0 (x) = indicator(elem);
@@ -76,7 +87,6 @@ private:
     {
       const int elemIdx = mapper_.index(elem);
       const auto& geo = elem.geometry();
-      const double elemVol = geo.volume();
 
       //in the system of linear equations (SLE) Ad = b,
       //the index elemIdxSLE refers to the basis function phi_elem,0
@@ -85,7 +95,7 @@ private:
       const int elemIdxSLE = (dim + 1)*elemIdx;
 
       //fill load vector b using a quadrature rule
-      for (const auto& ip : rule)
+      for (const auto& ip : rule_q)
       {
         //quadrature point in local and global coordinates
         const auto& qpLocal = ip.position();
@@ -96,21 +106,37 @@ private:
         const Scalar qEvalution(problem_.q(qpGlobal));
 
         //quadrature for int_elem q*phi_elem,0 dV
-        b[elemIdxSLE] += weight * qEvalution * integrationElem;
+        b[elemIdxSLE] += weight * integrationElem * qEvalution;
 
         //quadrature for int_elem q*phi_elem,i dV
         for (int i = 0; i < dim; i++)
         {
           b[elemIdxSLE + i + 1] +=
-            weight * qpGlobal[i] * qEvalution * integrationElem;
+            weight * integrationElem * qpGlobal[i] * qEvalution;
         }
       }
 
-      for (int i = 0; i < dim; i++)
+      //evaluate
+      // int_elem K*grad(phi_elem,i)*grad(phi_elem,j) dV
+      // = int_elem K[j][i] dV
+      //using a quadrature rule
+      for (const auto& ip : rule_K_Elem)
       {
-        //exact evaluation of
-        // int_elem K*grad(phi_elem,i)*grad(phi_elem,i) dV
-        A->entry(elemIdxSLE + i + 1, elemIdxSLE + i + 1) += K * elemVol;
+        //quadrature point in local and global coordinates
+        const auto& qpLocal = ip.position();
+        const auto& qpGlobal = geo.global(qpLocal);
+
+        const Scalar weight(ip.weight());
+        const Scalar integrationElem(geo.integrationElement(qpLocal));
+
+        for (int i = 0; i < dim; i++)
+        {
+          for (int j = 0; j <= i; j++)
+          {
+            A->entry(elemIdxSLE + i + 1, elemIdxSLE + j + 1) +=
+              weight * integrationElem * problem_.K(qpGlobal)[j][i];
+          }
+        }
       }
 
       //iterate over all intersection with the boundary of elem
@@ -126,17 +152,27 @@ private:
   //          Dune::QuadratureRules<double,dim-1>::rule(
   //          intersct.type(), 2);
 
-        //storage for multiply used integral values,
+        //create storage for multiply used integral values
+        //linearIntegrals[i] = int_intersct x[i] ds
+        Dune::FieldVector<Scalar, dim> linearIntegrals(0.0);
+
+        //quadraticIntregrals[i][j] = int_intersct x[i]*x[j] ds
+        //NOTE: is there a better type for a symmetric matrix?
         //note that only the lower diagonal and diagonal entries of
         //quadraticIntregrals are used
-        Dune::FieldVector<Scalar, dim> linearIntegrals(0.0);
         Dune::FieldMatrix<Scalar, dim, dim> quadraticIntregrals(0.0);
-        //NOTE: is there a better type for a symmetric matrix?
 
+        //KIntegrals[i] = int_intersct K[:,i]*normal ds
+        Dune::FieldVector<Scalar, dim> KIntegrals(0.0);
+
+        //KIntegralsX[i][j] = int_intersct x[j]*(K[:,i]*normal) ds
+        Dune::FieldMatrix<Scalar, dim, dim> KIntegralsX(0.0);
+
+        //fill vector linearIntegrals and matrix quadraticIntregrals //NOTE
         for (int i = 0; i < dim; i++)
         {
           //use midpoint rule for exact evaluation of
-          // int_intersct x_i ds
+          // int_intersct x[i] ds
           linearIntegrals[i] = intersctVol * intersctCenter[i];
 
           for (int j = 0; j <= i; j++)
@@ -164,6 +200,47 @@ private:
           }
         }
 
+        //fill vector KIntegrals using a quadrature rule
+        for (const auto& ip : rule_K_Edge)
+        {
+          //quadrature point in local and global coordinates
+          const auto& qpLocal = ip.position();
+          const auto& qpGlobal = intersctGeo.global(qpLocal);
+
+          const Scalar weight(ip.weight());
+          const Scalar integrationElem(intersctGeo.integrationElement(qpLocal));
+          const Dune::FieldMatrix<Scalar, dim, dim> KEvalution =
+            problem_.K(qpGlobal);
+
+          for (int i = 0; i < dim; i++)
+          {
+            KIntegrals[i] +=
+              weight * integrationElem * (KEvalution[i] * normal);
+          }
+        }
+
+        //fill vector KIntegralsX using a quadrature rule
+        for (const auto& ip : rule_Kplus1_Edge)
+        {
+          //quadrature point in local and global coordinates
+          const auto& qpLocal = ip.position();
+          const auto& qpGlobal = intersctGeo.global(qpLocal);
+
+          const Scalar weight(ip.weight());
+          const Scalar integrationElem(intersctGeo.integrationElement(qpLocal));
+          const Dune::FieldMatrix<Scalar, dim, dim> KEvalution =
+            problem_.K(qpGlobal);
+
+          for (int i = 0; i < dim; i++)
+          {
+            for (int j = 0; j < dim; j++)
+            {
+              KIntegralsX[i][j] += weight * integrationElem *
+                qpGlobal[j] * (KEvalution[i] * normal);
+            }
+          }
+        }
+
         //exact evaluation of
         // int_intersct mu*jump(phi_elem,0)*jump(phi_elem,0) ds
         A->entry(elemIdxSLE, elemIdxSLE) += mu * intersctVol;
@@ -177,25 +254,24 @@ private:
           for (int i = 0; i < dim; i++)
           { //we use the relations
             // int_intersct mu*jump(phi_elem,0)*jump(phi_elem,i) ds
-            // = mu * int_intersct x_i ds
+            // = mu * int_intersct x[i] ds
             //and
             // int_intersct avg(K*grad(phi_elem,i))*jump(phi_elem,0) ds
-            // = 0.5 * K * normal[i] * vol(intersct)
+            // = 0.5 * int_intersct K[:,i] * normal ds
             A->entry(elemIdxSLE + i + 1, elemIdxSLE) +=
-              mu * linearIntegrals[i] - 0.5 * K * normal[i] * intersctVol;
+              mu * linearIntegrals[i] - 0.5 * KIntegrals[i];
 
             for (int j = 0; j <= i; j++)
             {
               //we use the relations
               // int_intersct mu*jump(phi_elem,i)*jump(phi_elem,j) ds
-              // = mu * int_intersct x_i*x_j ds
+              // = mu * int_intersct x[i] * x[j] ds
               //and
               // int_intersct avg(K*grad(phi_elem,i))*jump(phi_elem,j) ds
-              // = 0.5 * K * normal[i] * int_intersct x_j ds
+              // = 0.5 * int_intersct x[j] * ( K[:,i] * normal ) ds
               A->entry(elemIdxSLE + i + 1, elemIdxSLE + j + 1)
                 += mu * quadraticIntregrals[i][j]
-                  - 0.5 * K * (normal[i] * linearIntegrals[j]
-                    + normal[j] * linearIntegrals[i]);
+                  - 0.5 * ( KIntegralsX[i][j] + KIntegralsX[j][i] );
             }
           }
 
@@ -205,7 +281,7 @@ private:
           }
 
           //exact evaluation of
-          // int_intersct mu*jump(phi_elem,0)*jump(phi_neighbor,0) ds
+          // int_intersct mu * jump(phi_elem,0) * jump(phi_neighbor,0) ds
           A->entry(elemIdxSLE, neighborIdxSLE) += -mu * intersctVol;
 
           //stiffness matrix A is symmetric
@@ -215,26 +291,22 @@ private:
           for (int i = 0; i < dim; i++)
           {
             //we use the relations
-            // int_intersct mu*jump(phi_elem,i)
-            //  *jump(phi_neighbor,0) ds
-            // = -mu*int_intersct x_i ds
+            // int_intersct mu * jump(phi_elem,i) * jump(phi_neighbor,0) ds
+            // = -mu * int_intersct x[i] ds
             //and
-            // int_intersct avg(K*grad(phi_neighbor,i))
-            //  *jump(phi_elem,0) ds
-            // = 0.5 * K * normal[i] * vol(intersct)
+            // int_intersct avg(K*grad(phi_neighbor,i)) * jump(phi_elem,0) ds
+            // = -0.5 * int_intersct K[:,i] * normal ds
             A->entry(elemIdxSLE + i + 1, neighborIdxSLE) +=
-              -mu * linearIntegrals[i] + 0.5 * K * normal[i] * intersctVol;
+              -mu * linearIntegrals[i] + 0.5 * KIntegrals[i];
 
             //we use the relations
-            // int_intersct mu*jump(phi_elem,0)
-            //  *jump(phi_neighbor,i) ds
-            // = -mu*int_intersct x_i ds
+            // int_intersct mu * jump(phi_elem,0) * jump(phi_neighbor,i) ds
+            // = -mu * int_intersct x[i] ds
             //and
-            // int_intersct avg(K*grad(phi_neighbor,i))
-            //  *jump(phi_elem,0) ds
-            // = 0.5 * K * normal[i] * vol(intersct)
+            // int_intersct avg(K*grad(phi_neighbor,i)) * jump(phi_elem,0) ds
+            // = 0.5 * int_intersct K[:,i] * normal ds
             A->entry(elemIdxSLE, neighborIdxSLE + i + 1) +=
-              -mu * linearIntegrals[i] - 0.5 * K * normal[i] * intersctVol;
+              -mu * linearIntegrals[i] - 0.5 * KIntegrals[i];
 
             //stiffness matrix A is symmetric
             A->entry(neighborIdxSLE, elemIdxSLE + i + 1) +=
@@ -245,21 +317,17 @@ private:
             for (int j = 0; j <= i; j++)
             {
               //we use the relations
-              // int_intersct mu*jump(phi_elem,i)
-              //  *jump(phi_neighbor,j) ds
-              // = -mu*int_intersct x_i*x_j ds
+              // int_intersct mu * jump(phi_elem,i) * jump(phi_neighbor,j) ds
+              // = -mu * int_intersct x[i] * x[j] ds
               //and
-              // int_intersct avg(K*grad(phi_neighbor,j))
-              //  *jump(phi_elem,i) ds
-              // = 0.5 * K * normal[j] * int_intersct x_i ds
+              // int_intersct avg(K*grad(phi_neighbor,j)) * jump(phi_elem,i) ds
+              // = 0.5 * int_intersct x[i] * ( K[:,j] * normal ) ds
               //as well as
-              // int_intersct avg(K*grad(phi_elem,i))
-              //  *jump(phi_neighbor,j) ds
-              // = -0.5 * K * normal[i] * int_intersct x_j ds
+              // int_intersct avg(K*grad(phi_elem,i)) * jump(phi_neighbor,j) ds
+              // = -0.5 * int_intersct x[j] * ( K[:,i] * normal ) ds
               A->entry(elemIdxSLE + i + 1, neighborIdxSLE + j + 1) +=
                 -mu * quadraticIntregrals[i][j]
-                - 0.5 * K * (normal[j] * linearIntegrals[i]
-                  - normal[i] * linearIntegrals[j]);
+                - 0.5 * ( KIntegralsX[j][i] - KIntegralsX[i][j] );
 
               //stiffness matrix A is symmetric
               A->entry(neighborIdxSLE + j + 1, elemIdxSLE + i + 1) +=
@@ -267,21 +335,18 @@ private:
 
               if (i != j)
               {
-                // int_intersct mu*jump(phi_elem,j)
-                //  *jump(phi_neighbor,i) ds
-                // = -mu*int_intersct x_i*x_j ds
+                //we use the relations
+                // int_intersct mu * jump(phi_elem,j) * jump(phi_neighbor,i) ds
+                // = -mu * int_intersct x[i] * x[j] ds
                 //and
-                // int_intersct avg(K*grad(phi_neighbor,i))
-                //  *jump(phi_elem,j) ds
-                // = 0.5 * K * normal[i] * int_intersct x_j ds
+                // int_intersct avg(K*grad(phi_neighbor,i))*jump(phi_elem,j) ds
+                // = 0.5 * int_intersct x[j] * ( K[:,i] * normal ) ds
                 //as well as
-                // int_intersct avg(K*grad(phi_elem,j))
-                //  *jump(phi_neighbor,i) ds
-                // = -0.5 * K * normal[j] * int_intersct x_i ds
+                // int_intersct avg(K*grad(phi_elem,j))*jump(phi_neighbor,i) ds
+                // = -0.5 * int_intersct x[i] * ( K[:,j] * normal ) ds
                 A->entry(elemIdxSLE + j + 1, neighborIdxSLE + i + 1) +=
                   -mu * quadraticIntregrals[i][j]
-                  - 0.5 * K * (normal[i] * linearIntegrals[j]
-                    - normal[j] * linearIntegrals[i]);
+                  - 0.5 * ( KIntegralsX[i][j] - KIntegralsX[j][i] );
 
                 //stiffness matrix A is symmetric
                 A->entry(neighborIdxSLE + i + 1, elemIdxSLE + j + 1) +=
@@ -294,28 +359,25 @@ private:
         {
           for (int i = 0; i < dim; i++)
           { //we use the relations
-            // int_intersct mu*jump(phi_elem,0)*jump(phi_elem,i) ds
-            // = mu * int_intersct x_i ds
+            // int_intersct mu * jump(phi_elem,0) * jump(phi_elem,i) ds
+            // = mu * int_intersct x[i] ds
             //and for boundary facets
-            // int_intersct avg(K*grad(phi_elem,i))
-            //  *jump(phi_elem,0) ds
-            // = K * normal[i] * vol(intersct)
+            // int_intersct avg(K*grad(phi_elem,i)) * jump(phi_elem,0) ds
+            // = 0.5 * int_intersct K[:,i] * normal ds
             A->entry(elemIdxSLE + i + 1, elemIdxSLE) +=
-              mu * linearIntegrals[i] - 0.5 * K * normal[i] * intersctVol;
+              mu * linearIntegrals[i] - 0.5 * KIntegrals[i];
 
             for (int j = 0; j <= i; j++)
             {
               //we use the relations
-              // int_intersct mu*jump(phi_elem,i)*jump(phi_elem,j) ds
-              // = mu * int_intersct x_i*x_j ds
+              // int_intersct mu * jump(phi_elem,i) * jump(phi_elem,j) ds
+              // = mu * int_intersct x[i] * x[j] ds
               //and for boundary facets
-              // int_intersct avg(K*grad(phi_elem,i))
-              //  *jump(phi_elem,j) ds
-              // = 0.5 * K * normal[i] * int_intersct x_j ds
+              // int_intersct avg(K*grad(phi_elem,i)) * jump(phi_elem,j) ds
+              // = 0.5 * int_intersct x[j] * ( K[:,i] * normal ) ds
               A->entry(elemIdxSLE + i + 1, elemIdxSLE + j + 1) +=
                 mu * quadraticIntregrals[i][j]
-                - 0.5 * K * (normal[i] * linearIntegrals[j]
-                  + normal[j] * linearIntegrals[i]);
+                - 0.5 * ( KIntegralsX[i][j] + KIntegralsX[j][i] );
             }
           }
         }
diff --git a/dune/mmdg/problems/dgproblem.hh b/dune/mmdg/problems/dgproblem.hh
index f8d22f3f88daa7fbf2c1dc2b222e37a26e335017..942c4338083017f5eebbd2c91adcc00e5749db3b 100644
--- a/dune/mmdg/problems/dgproblem.hh
+++ b/dune/mmdg/problems/dgproblem.hh
@@ -36,13 +36,6 @@ class DGProblem
       return Scalar(0.0);
     }
 
-    //returns the recommended quadrature order to compute an integral
-    //over x * q(x)
-    virtual int quadratureOrder () const
-    {
-      return 1;
-    }
-
     //permeability tensor at position pos
     virtual Matrix K (const Vector& pos) const
     {
@@ -56,6 +49,21 @@ class DGProblem
       //return identity matrix
       return permeability;
     }
+
+    //returns the recommended quadrature order to compute an integral
+    //over x * q(x)
+    virtual int quadratureOrder_q () const
+    {
+      return 1;
+    }
+
+    //returns the recommended quadrature order to compute an integral
+    //over an entry K[i][j] of the permeability tensor
+    virtual int quadratureOrder_K () const
+    {
+      return 0;
+    }
+
 };
 
 #endif
diff --git a/src/dg.cc b/src/dg.cc
index 540ab9c2c19875f40ffa13a335fdbc7703adcf27..8b160fec3ca62e53607e1a442eb1fd2c8e92d804 100644
--- a/src/dg.cc
+++ b/src/dg.cc
@@ -23,8 +23,6 @@
 #include <dune/mmdg/problems/poisson.hh>
 
 
-//TODO: specify K in problem? exact solution depends on K!
-
 int main(int argc, char** argv)
 {
   try
@@ -48,9 +46,6 @@ int main(int argc, char** argv)
     Dune::ParameterTree pt;
     Dune::ParameterTreeParser::readINITree("parameterDG.ini", pt);
 
-    //assume isotropic medium such that permeability tensor reduces to a scalar
-    const double K = std::stod(pt["K"]);
-
     //assume constant penalty parameter
     const double mu = std::stod(pt["mu"]);
 
@@ -63,8 +58,6 @@ int main(int argc, char** argv)
     //element mapper for the leaf grid view
     const Mapper mapper(gridView, Dune::mcmgElementLayout());
 
-//    const DGProblem<Dune::FieldVector<double, dim>, double> dummyProblem;
-
     DGProblem<Coordinate>* problem; //problem to be solved
 
     //determine problem type
@@ -81,7 +74,7 @@ int main(int argc, char** argv)
 
     const DG dg(gridView, mapper, *problem);
 
-    dg(K, mu);
+    dg(mu);
 
     //print total run time
     const double timeTotal = ClockHelper::elapsedRuntime(timeInitial);