From 2b7a60430fbe64af7dc81c63d5710b6c5737b92b Mon Sep 17 00:00:00 2001
From: Robert K <robertk@posteo.org>
Date: Fri, 29 Jul 2016 12:03:41 +0200
Subject: [PATCH] [bugfix] This fixes an issue when UMFPack is found and AMG
 with field type float is selected. Since UMFPack does not support this, it
 cannot be used in this case.

---
 dune/istl/paamg/amg.hh | 99 +++++++++++++++++++++++++++++++++++-------
 dune/istl/umfpack.hh   |  8 +++-
 2 files changed, 90 insertions(+), 17 deletions(-)

diff --git a/dune/istl/paamg/amg.hh b/dune/istl/paamg/amg.hh
index 1d0683f27..2a987a147 100644
--- a/dune/istl/paamg/amg.hh
+++ b/dune/istl/paamg/amg.hh
@@ -370,6 +370,69 @@ namespace Dune
       rhs_=nullptr;
     }
 
+    template <class Matrix,
+              class Vector>
+    struct DirectSolverSelector
+    {
+      typedef typename Matrix :: field_type field_type;
+      enum SolverType { umfpack, superlu, none };
+
+      static constexpr SolverType solver =
+#if HAVE_SUITESPARSE_UMFPACK
+        UMFPackMethodChooser< field_type > :: valid ? umfpack : none ;
+#elif HAVE_SUPERLU
+        superlu ;
+#else
+        none;
+#endif
+
+      template <class M, SolverType>
+      struct Solver
+      {
+        typedef InverseOperator<Vector,Vector> type;
+        static type* create(const M& mat, bool verbose, bool reusevector )
+        {
+          DUNE_THROW(NotImplemented,"DirectSolver not selected");
+          return nullptr;
+        }
+        static std::string name () { return "None"; }
+      };
+#if HAVE_SUITESPARSE_UMFPACK
+      template <class M>
+      struct Solver< M, umfpack >
+      {
+        typedef UMFPack< M > type;
+        static type* create(const M& mat, bool verbose, bool reusevector )
+        {
+          return new type(mat, verbose, reusevector );
+        }
+        static std::string name () { return "UMFPack"; }
+      };
+#endif
+#if HAVE_SUPERLU
+      template <class M>
+      struct Solver< M, superlu >
+      {
+        typedef SuperLU< M > type;
+        static type* create(const M& mat, bool verbose, bool reusevector )
+        {
+          return new type(mat, verbose, reusevector );
+        }
+        static std::string name () { return "SuperLU"; }
+      };
+#endif
+
+      // define direct solver type to be used
+      typedef Solver< Matrix, solver > SelectedSolver ;
+      typedef typename SelectedSolver :: type   DirectSolver;
+      static constexpr bool isDirectSolver = solver != none;
+      static std::string name() { return SelectedSolver :: name (); }
+      static DirectSolver* create(const Matrix& mat, bool verbose, bool reusevector )
+      {
+        return SelectedSolver :: create( mat, verbose, reusevector );
+      }
+    };
+
     template<class M, class X, class S, class PI, class A>
     template<class C>
     void AMG<M,X,S,PI,A>::createHierarchies(C& criterion, Operator& matrix,
@@ -383,7 +446,8 @@ namespace Dune
       // build the necessary smoother hierarchies
       matrices_->coarsenSmoother(*smoothers_, smootherArgs_);
 
-            if(buildHierarchy_ && matrices_->levels()==matrices_->maxlevels()) {
+      if(buildHierarchy_ && matrices_->levels()==matrices_->maxlevels())
+      {
         // We have the carsest level. Create the coarse Solver
         SmootherArgs sargs(smootherArgs_);
         sargs.iterations = 1;
@@ -402,32 +466,35 @@ namespace Dune
         coarseSmoother_.reset(ConstructionTraits<Smoother>::construct(cargs));
         scalarProduct_.reset(ScalarProductChooser::construct(cargs.getComm()));
 
-#if HAVE_SUPERLU || HAVE_SUITESPARSE_UMFPACK
-#if HAVE_SUITESPARSE_UMFPACK
-#define DIRECTSOLVER UMFPack
-#else
-#define DIRECTSOLVER SuperLU
-#endif
+        typedef DirectSolverSelector< typename M::matrix_type, X > SolverSelector;
+
         // Use superlu if we are purely sequential or with only one processor on the coarsest level.
-        if(std::is_same<ParallelInformation,SequentialInformation>::value // sequential mode
+        if( SolverSelector::isDirectSolver &&
+            (std::is_same<ParallelInformation,SequentialInformation>::value // sequential mode
            || matrices_->parallelInformation().coarsest()->communicator().size()==1 //parallel mode and only one processor
            || (matrices_->parallelInformation().coarsest().isRedistributed()
                && matrices_->parallelInformation().coarsest().getRedistributed().communicator().size()==1
-               && matrices_->parallelInformation().coarsest().getRedistributed().communicator().size()>0)) { // redistribute and 1 proc
+               && matrices_->parallelInformation().coarsest().getRedistributed().communicator().size()>0) )
+          )
+        { // redistribute and 1 proc
           if(matrices_->parallelInformation().coarsest().isRedistributed())
           {
             if(matrices_->matrices().coarsest().getRedistributed().getmat().N()>0)
+            {
               // We are still participating on this level
-              solver_.reset(new DIRECTSOLVER<typename M::matrix_type>(matrices_->matrices().coarsest().getRedistributed().getmat(), false, false));
+              solver_.reset(SolverSelector::create(matrices_->matrices().coarsest().getRedistributed().getmat(), false, false));
+            }
             else
               solver_.reset();
-          }else
-            solver_.reset(new DIRECTSOLVER<typename M::matrix_type>(matrices_->matrices().coarsest()->getmat(), false, false));
+          }
+          else
+          {
+            solver_.reset(SolverSelector::create(matrices_->matrices().coarsest()->getmat(), false, false));
+          }
           if(verbosity_>0 && matrices_->parallelInformation().coarsest()->communicator().rank()==0)
-            std::cout<< "Using a direct coarse solver (" << static_cast< DIRECTSOLVER<typename M::matrix_type>* >(solver_.get())->name() << ")" << std::endl;
-        }else
-#undef DIRECTSOLVER
-#endif // HAVE_SUPERLU|| HAVE_SUITESPARSE_UMFPACK
+            std::cout<< "Using a direct coarse solver (" << SolverSelector::name() << ")" << std::endl;
+        }
+        else
         {
           if(matrices_->parallelInformation().coarsest().isRedistributed())
           {
diff --git a/dune/istl/umfpack.hh b/dune/istl/umfpack.hh
index ac69a44c5..e6e3c8d84 100644
--- a/dune/istl/umfpack.hh
+++ b/dune/istl/umfpack.hh
@@ -53,11 +53,15 @@ namespace Dune {
   // depending on the template parameter used.
   template<typename T>
   struct UMFPackMethodChooser
-  {};
+  {
+    static constexpr bool valid = false ;
+  };
 
   template<>
   struct UMFPackMethodChooser<double>
   {
+    static constexpr bool valid = true ;
+
     template<typename... A>
     static void defaults(A... args)
     {
@@ -113,6 +117,8 @@ namespace Dune {
   template<>
   struct UMFPackMethodChooser<std::complex<double> >
   {
+    static constexpr bool valid = true ;
+
     template<typename... A>
     static void defaults(A... args)
     {
-- 
GitLab