From 4db9083a87a5f89efe46a042d46a375f10f8d4a1 Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon.praetorius@tu-dresden.de>
Date: Mon, 2 Jul 2018 16:06:12 +0200
Subject: [PATCH] Corrected errors in ConvectionDiffusionOperator and added
 example

---
 examples/CMakeLists.txt                       |  2 +-
 examples/convection_diffusion.cc              | 44 ++++++++++++++++
 .../assembler/ConvectionDiffusionOperator.hpp | 51 ++++++++++---------
 3 files changed, 73 insertions(+), 24 deletions(-)
 create mode 100644 examples/convection_diffusion.cc

diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 5a8d6233..ab96c269 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_custom_target(examples)
 
-set(projects2d "ellipt" "heat" "vecellipt" "stokes0" "stokes1" "stokes3" "navier_stokes")
+set(projects2d "ellipt" "heat" "vecellipt" "stokes0" "stokes1" "stokes3" "navier_stokes" "convection_diffusion")
 
 foreach(project ${projects2d})
     add_executable(${project}.2d ${project}.cc)
diff --git a/examples/convection_diffusion.cc b/examples/convection_diffusion.cc
new file mode 100644
index 00000000..40871822
--- /dev/null
+++ b/examples/convection_diffusion.cc
@@ -0,0 +1,44 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+
+#include <iostream>
+
+#include <amdis/AMDiS.hpp>
+#include <amdis/ProblemStat.hpp>
+#include <amdis/assembler/ConvectionDiffusionOperator.hpp>
+#include <amdis/common/Literals.hpp>
+
+using namespace AMDiS;
+
+// 1 component with polynomial degree 1
+//using Grid = Dune::AlbertaGrid<AMDIS_DIM, AMDIS_DOW>;
+using ElliptParam   = YaspGridBasis<AMDIS_DIM, 1>;
+using ElliptProblem = ProblemStat<ElliptParam>;
+
+int main(int argc, char** argv)
+{
+  AMDiS::init(argc, argv);
+
+  using namespace Dune::Indices;
+
+  ElliptProblem prob("ellipt");
+  prob.initialize(INIT_ALL);
+
+  // -div(A*grad(u)) + div(b*u) + c*u = f
+  auto opCD = convectionDiffusion(/*A=*/1.0, /*b=*/0.0, /*c=*/1.0, /*f=*/1.0);
+  prob.addMatrixOperator(opCD, _0, _0);
+  prob.addVectorOperator(opCD, _0);
+
+  // set boundary condition
+  auto predicate = [](auto const& x){ return x[0] < 1.e-8 || x[1] < 1.e-8; }; // define boundary
+  auto dbcValues = [](auto const& x){ return 0.0; }; // set value
+  prob.addDirichletBC(predicate, _0, _0, dbcValues);
+
+  AdaptInfo adaptInfo("adapt");
+  prob.buildAfterCoarsen(adaptInfo, Flag(0));
+  prob.solve(adaptInfo);
+  prob.writeFiles(adaptInfo, true);
+
+  AMDiS::finalize();
+  return 0;
+}
diff --git a/src/amdis/assembler/ConvectionDiffusionOperator.hpp b/src/amdis/assembler/ConvectionDiffusionOperator.hpp
index a2f938e7..388370ab 100644
--- a/src/amdis/assembler/ConvectionDiffusionOperator.hpp
+++ b/src/amdis/assembler/ConvectionDiffusionOperator.hpp
@@ -14,7 +14,7 @@ namespace AMDiS
    * @{
    **/
 
-  /// convection-diffusion operator
+  /// convection-diffusion operator, see \ref convectionDiffusion
   /// <A*grad(u),grad(v)> - <b*u, grad(v)> + <c*u, v> = <f, v> (conserving) or
   /// <A*grad(u),grad(v)> + <b*grad(u), v> + <c*u, v> = <f, v> (non conserving)
   template <class LocalContext, class GridFctA, class GridFctB, class GridFctC, class GridFctF, bool conserving = true>
@@ -71,7 +71,7 @@ namespace AMDiS
                               this->getDegree(1,coeffOrder(localFctB),rowNode,colNode),
                               this->getDegree(0,coeffOrder(localFctC),rowNode,colNode)});
 
-      using QuadratureRules = Dune::QuadratureRules<typename Context::Geometry::ctype, Context::dimension>;
+      using QuadratureRules = Dune::QuadratureRules<typename Context::Geometry::ctype, Context::LocalContext::mydimension>;
       auto const& quad = QuadratureRules::rule(context.type(), quadDeg);
 
       for (auto const& qp : quad) {
@@ -93,30 +93,33 @@ namespace AMDiS
         localFE.localBasis().evaluateJacobian(local, shapeGradients);
 
         // Compute the shape function gradients on the real element
-        thread_local std::vector<Dune::FieldVector<RangeFieldType,Context::dow> > gradients(shapeGradients.size());
+        using WorldVector = FieldVector<RangeFieldType,Context::dow>;
+        thread_local std::vector<WorldVector> gradients(shapeGradients.size());
 
         for (std::size_t i = 0; i < gradients.size(); ++i)
           jacobian.mv(shapeGradients[i][0], gradients[i]);
 
         const auto A = localFctA(local);
-        const auto b = localFctB(local);
+        WorldVector b; b = localFctB(local);
         const auto c = localFctC(local);
 
         IF_CONSTEXPR(conserving) {
+          WorldVector gradAi, gradBi;
           for (std::size_t i = 0; i < localFE.size(); ++i) {
             const int local_i = rowNode.localIndex(i);
-            const auto gradAi = A * gradients[i];
-            const auto gradBi = b * gradients[i];
+            gradAi = A * gradients[i];
+            gradBi = b * gradients[i];
             for (std::size_t j = 0; j < localFE.size(); ++j) {
               const int local_j = colNode.localIndex(j);
               elementMatrix[local_i][local_j] += (dot(gradAi, gradients[j]) + (c * shapeValues[i] - gradBi) * shapeValues[j]) * factor;
             }
           }
         } else {
+          WorldVector grad_i;
           for (std::size_t i = 0; i < localFE.size(); ++i) {
             const int local_i = rowNode.localIndex(i);
-            const auto grad_i = A * gradients[i];
-            grad_i += b * shapeValues[i];
+            grad_i = A * gradients[i];
+            grad_i+= b * shapeValues[i];
             for (std::size_t j = 0; j < localFE.size(); ++j) {
               const int local_j = colNode.localIndex(j);
               elementMatrix[local_i][local_j] += (dot(grad_i, gradients[j]) + c * shapeValues[i] * shapeValues[j]) * factor;
@@ -136,10 +139,10 @@ namespace AMDiS
                           Node const& node,
                           ElementVector& elementVector)
     {
-      static_assert(Node::isLeaf
+      static_assert(Node::isLeaf,
         "Operator can be applied to Leaf-Nodes only." );
 
-      using RangeType = typename FiniteElementType_t<RowNode>::Traits::LocalBasisType::Traits::RangeType;
+      using RangeType = typename FiniteElementType_t<Node>::Traits::LocalBasisType::Traits::RangeType;
 
       auto localFctF = localFunction(gridFctF_); localFctF.bind(context.element());
 
@@ -147,7 +150,7 @@ namespace AMDiS
 
       int quad_order = this->getDegree(0,coeffOrder(localFctF),node);
 
-      using QuadratureRules = Dune::QuadratureRules<typename Context::Geometry::ctype, Context::dimension>;
+      using QuadratureRules = Dune::QuadratureRules<typename Context::Geometry::ctype, Context::LocalContext::dimension>;
       auto const& quad = QuadratureRules::rule(context.type(), quad_order);
 
       for (auto const& qp : quad) {
@@ -164,8 +167,8 @@ namespace AMDiS
         const auto f = localFctF(local);
 
         for (std::size_t i = 0; i < localFE.size(); ++i) {
-          const int local_i = rowNode.localIndex(i);
-          elementVector[local_i][local_j] += f * shapeValues[i] * factor;
+          const int local_i = node.localIndex(i);
+          elementVector[local_i] += f * shapeValues[i] * factor;
         }
       }
 
@@ -180,22 +183,23 @@ namespace AMDiS
     template <class LocalFct>
     int coeffOrder(LocalFct const& localFct)
     {
-      using Concept = Dune::Std::is_detected<HasLocalFunctionOrder, LocalFunction>;
+      using Concept = Dune::Std::is_detected<HasLocalFunctionOrder, LocalFct>;
       return Dune::Hybrid::ifElse(Concept{},
         [&](auto id) { return order(id(localFct)); },
         [] (auto)    { return 0; });
     }
 
   private:
-    GridFctA gridFctA;
-    GridFctB gridFctB;
-    GridFctC gridFctC;
-    GridFctF gridFctF;
+    GridFctA gridFctA_;
+    GridFctB gridFctB_;
+    GridFctC gridFctC_;
+    GridFctF gridFctF_;
   };
 
-  template <class PreGridFctA, class PreGridFctB, class PreGridFctC, class PreGridFctF, bool conserving>
+  template <class PreGridFctA, class PreGridFctB, class PreGridFctC, class PreGridFctF, class c>
   struct PreConvectionDiffusionOperator
   {
+    static constexpr bool conserving = c::value;
     PreGridFctA gridFctA;
     PreGridFctB gridFctB;
     PreGridFctC gridFctC;
@@ -207,20 +211,21 @@ namespace AMDiS
                            PreGridFctC const& gridFctC, PreGridFctF const& gridFctF,
                            bool_t<conserving> = {})
   {
-    using Pre = PreConvectionDiffusionOperator<PreGridFctA, PreGridFctB, PreGridFctC, PreGridFctF, conserving>;
+    using Pre = PreConvectionDiffusionOperator<PreGridFctA, PreGridFctB, PreGridFctC, PreGridFctF, bool_t<conserving>>;
     return Pre{gridFctA, gridFctB, gridFctC, gridFctF};
   }
 
-  template <class LocalContext, class... GrdFcts, bool conserving, class GridView>
-  auto makeLocalOperator(PreConvectionDiffusionOperator<GridFcts..., conserving> const& pre, GridView const& gridView)
+  template <class LocalContext, class... T, class GridView>
+  auto makeLocalOperator(PreConvectionDiffusionOperator<T...> const& pre, GridView const& gridView)
   {
+    using Pre = PreConvectionDiffusionOperator<T...>;
     auto gridFctA = makeGridFunction(pre.gridFctA, gridView);
     auto gridFctB = makeGridFunction(pre.gridFctB, gridView);
     auto gridFctC = makeGridFunction(pre.gridFctC, gridView);
     auto gridFctF = makeGridFunction(pre.gridFctF, gridView);
 
     using GridFctOp = ConvectionDiffusionOperator<LocalContext,
-      decltype(gridFctA), decltype(gridFctB), decltype(gridFctC), decltype(gridFctF), conserving>;
+      decltype(gridFctA), decltype(gridFctB), decltype(gridFctC), decltype(gridFctF), Pre::conserving>;
 
     GridFctOp localOperator{gridFctA, gridFctB, gridFctC, gridFctF};
     return localOperator;
-- 
GitLab