From aabace24fb1da36ac4db2a17b5750b492bc1773e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jakub=20Klinkovsk=C3=BD?= <klinkovsky@mmg.fjfi.cvut.cz>
Date: Tue, 28 Jan 2020 16:49:31 +0100
Subject: [PATCH] Refactoring getLinearSolver and getPreconditioner

---
 src/TNL/Solvers/LinearSolverTypeResolver.h    | 79 ++++++++++++++-----
 .../PDE/SemiImplicitTimeStepper_impl.h        |  6 +-
 src/TNL/Solvers/SolverConfig_impl.h           | 31 ++------
 3 files changed, 67 insertions(+), 49 deletions(-)

diff --git a/src/TNL/Solvers/LinearSolverTypeResolver.h b/src/TNL/Solvers/LinearSolverTypeResolver.h
index 18bf080399..5615ea7077 100644
--- a/src/TNL/Solvers/LinearSolverTypeResolver.h
+++ b/src/TNL/Solvers/LinearSolverTypeResolver.h
@@ -12,6 +12,8 @@
 
 #pragma once
 
+#include <vector>
+#include <string>
 #include <memory>
 
 #include <TNL/Solvers/Linear/SOR.h>
@@ -28,54 +30,89 @@
 namespace TNL {
 namespace Solvers {
 
+inline std::vector<std::string>
+getLinearSolverOptions()
+{
+   return {
+      "sor",
+      "cg",
+      "bicgstab",
+      "bicgstabl",
+      "gmres",
+      "tfqmr"
+#ifdef HAVE_UMFPACK
+      , "umfpack"
+#endif
+   };
+}
+
+inline std::vector<std::string>
+getPreconditionerOptions()
+{
+   return {
+      "none",
+      "diagonal",
+      "ilu0",
+      "ilut"
+   };
+}
+
 template< typename MatrixType >
 std::shared_ptr< Linear::LinearSolver< MatrixType > >
-getLinearSolver( const Config::ParameterContainer& parameters )
+getLinearSolver( std::string name )
 {
-   const String& discreteSolver = parameters.getParameter< String >( "discrete-solver" );
-
-   if( discreteSolver == "sor" )
+   if( name == "sor" )
       return std::make_shared< Linear::SOR< MatrixType > >();
-   if( discreteSolver == "cg" )
+   if( name == "cg" )
       return std::make_shared< Linear::CG< MatrixType > >();
-   if( discreteSolver == "bicgstab" )
+   if( name == "bicgstab" )
       return std::make_shared< Linear::BICGStab< MatrixType > >();
-   if( discreteSolver == "bicgstabl" )
+   if( name == "bicgstabl" )
       return std::make_shared< Linear::BICGStabL< MatrixType > >();
-   if( discreteSolver == "gmres" )
+   if( name == "gmres" )
       return std::make_shared< Linear::GMRES< MatrixType > >();
-   if( discreteSolver == "tfqmr" )
+   if( name == "tfqmr" )
       return std::make_shared< Linear::TFQMR< MatrixType > >();
 #ifdef HAVE_UMFPACK
    if( discreteSolver == "umfpack" )
       return std::make_shared< Linear::UmfpackWrapper< MatrixType > >();
 #endif
 
-   std::cerr << "Unknown semi-implicit discrete solver " << discreteSolver << ". It can be only: sor, cg, bicgstab, bicgstabl, gmres, tfqmr";
-#ifdef HAVE_UMFPACK
-   std::cerr << ", umfpack"
-#endif
-   std::cerr << "." << std::endl;
+   std::string options;
+   for( auto o : getLinearSolverOptions() )
+      if( options.empty() )
+         options += o;
+      else
+         options += ", " + o;
+
+   std::cerr << "Unknown semi-implicit discrete solver " << name << ". It can be only: " << options << "." << std::endl;
 
    return nullptr;
 }
 
 template< typename MatrixType >
 std::shared_ptr< Linear::Preconditioners::Preconditioner< MatrixType > >
-getPreconditioner( const Config::ParameterContainer& parameters )
+getPreconditioner( std::string name )
 {
-   const String& preconditioner = parameters.getParameter< String >( "preconditioner" );
 
-   if( preconditioner == "none" )
+   if( name == "none" )
       return nullptr;
-   if( preconditioner == "diagonal" )
+   if( name == "diagonal" )
       return std::make_shared< Linear::Preconditioners::Diagonal< MatrixType > >();
-   if( preconditioner == "ilu0" )
+   if( name == "ilu0" )
       return std::make_shared< Linear::Preconditioners::ILU0< MatrixType > >();
-   if( preconditioner == "ilut" )
+   if( name == "ilut" )
       return std::make_shared< Linear::Preconditioners::ILUT< MatrixType > >();
 
-   std::cerr << "Unknown preconditioner " << preconditioner << ". It can be only: none, diagonal, ilu0, ilut." << std::endl;
+   std::string options;
+   for( auto o : getPreconditionerOptions() )
+      if( options.empty() )
+         options += o;
+      else
+         options += ", " + o;
+
+   std::cerr << "Unknown preconditioner " << name << ". It can be only: " << options << "." << std::endl;
+
    return nullptr;
 }
 
diff --git a/src/TNL/Solvers/PDE/SemiImplicitTimeStepper_impl.h b/src/TNL/Solvers/PDE/SemiImplicitTimeStepper_impl.h
index 5faa7902e1..3e8d106b27 100644
--- a/src/TNL/Solvers/PDE/SemiImplicitTimeStepper_impl.h
+++ b/src/TNL/Solvers/PDE/SemiImplicitTimeStepper_impl.h
@@ -33,14 +33,16 @@ setup( const Config::ParameterContainer& parameters,
        const String& prefix )
 {
    // set up the linear solver
-   linearSystemSolver = getLinearSolver< MatrixType >( parameters );
+   const String& discreteSolver = parameters.getParameter< String >( prefix + "discrete-solver" );
+   linearSystemSolver = getLinearSolver< MatrixType >( discreteSolver );
    if( ! linearSystemSolver )
       return false;
    if( ! linearSystemSolver->setup( parameters ) )
       return false;
 
    // set up the preconditioner
-   preconditioner = getPreconditioner< MatrixType >( parameters );
+   const String& preconditionerName = parameters.getParameter< String >( prefix + "preconditioner" );
+   preconditioner = getPreconditioner< MatrixType >( preconditionerName );
    if( preconditioner ) {
       linearSystemSolver->setPreconditioner( preconditioner );
       if( ! preconditioner->setup( parameters ) )
diff --git a/src/TNL/Solvers/SolverConfig_impl.h b/src/TNL/Solvers/SolverConfig_impl.h
index e5673d5c1e..9d3515157f 100644
--- a/src/TNL/Solvers/SolverConfig_impl.h
+++ b/src/TNL/Solvers/SolverConfig_impl.h
@@ -15,16 +15,7 @@
 #include <TNL/Solvers/DummyProblem.h>
 #include <TNL/Solvers/PDE/ExplicitTimeStepper.h>
 #include <TNL/Solvers/PDE/TimeDependentPDESolver.h>
-#include <TNL/Solvers/Linear/SOR.h>
-#include <TNL/Solvers/Linear/CG.h>
-#include <TNL/Solvers/Linear/BICGStab.h>
-#include <TNL/Solvers/Linear/BICGStabL.h>
-#include <TNL/Solvers/Linear/GMRES.h>
-#include <TNL/Solvers/Linear/TFQMR.h>
-#include <TNL/Solvers/Linear/UmfpackWrapper.h>
-#include <TNL/Solvers/Linear/Preconditioners/Diagonal.h>
-#include <TNL/Solvers/Linear/Preconditioners/ILU0.h>
-#include <TNL/Solvers/Linear/Preconditioners/ILUT.h>
+#include <TNL/Solvers/LinearSolverTypeResolver.h>
 #include <TNL/Matrices/CSR.h>
 #include <TNL/Meshes/DistributedMeshes/DistributedGrid.h>
 
@@ -124,23 +115,11 @@ bool SolverConfig< ConfigTag, ProblemConfig >::configSetup( Config::ConfigDescri
    }
    if( ConfigTagTimeDiscretisation< ConfigTag, SemiImplicitTimeDiscretisationTag >::enabled )
    {
-      config.addEntryEnum( "cg" );
-      config.addEntryEnum( "bicgstab" );
-      config.addEntryEnum( "bicgstabl" );
-      config.addEntryEnum( "gmres" );
-      config.addEntryEnum( "tfqmr" );
-      config.addEntryEnum( "sor" );
-#ifdef HAVE_UMFPACK
-      config.addEntryEnum( "umfpack" );
-#endif
+      for( auto o : getLinearSolverOptions() )
+         config.addEntryEnum( String( o ) );
       config.addEntry< String >( "preconditioner", "The preconditioner for the discrete solver:", "none" );
-      config.addEntryEnum( "none" );
-      config.addEntryEnum( "diagonal" );
-   // TODO: implement parallel ILU or device-dependent build config tags for preconditioners
-#ifndef HAVE_CUDA
-      config.addEntryEnum( "ilu0" );
-      config.addEntryEnum( "ilut" );
-#endif
+      for( auto o : getPreconditionerOptions() )
+         config.addEntryEnum( String( o ) );
    }
    if( ConfigTagTimeDiscretisation< ConfigTag, ExplicitTimeDiscretisationTag >::enabled ||
        ConfigTagTimeDiscretisation< ConfigTag, SemiImplicitTimeDiscretisationTag >::enabled )
-- 
GitLab