From a0adfa8b90bd102a38c7d7abaf15fefd3483a9aa Mon Sep 17 00:00:00 2001
From: Linus Seelinger <S.Linus@gmx.de>
Date: Fri, 1 Jul 2016 17:04:32 +0200
Subject: [PATCH] [lib][factory] Introduce ISTL library with preinstantiated
 solvers to speed up compile times

---
 cmake/modules/DuneIstlMacros.cmake | 103 +++++++++++++++++++++++++++++
 cmake/modules/solvertemplates.cc   |  55 +++++++++++++++
 cmake/modules/solvertemplates.hh   |  59 +++++++++++++++++
 config.h.cmake                     |   3 +
 4 files changed, 220 insertions(+)
 create mode 100644 cmake/modules/solvertemplates.cc
 create mode 100644 cmake/modules/solvertemplates.hh

diff --git a/cmake/modules/DuneIstlMacros.cmake b/cmake/modules/DuneIstlMacros.cmake
index 7744be063..176b332c0 100644
--- a/cmake/modules/DuneIstlMacros.cmake
+++ b/cmake/modules/DuneIstlMacros.cmake
@@ -2,6 +2,25 @@
 #
 #    This modules content is executed whenever a module required or suggests dune-istl!
 #
+# .. cmake_function:: dune_add_istl_library
+#
+#    .. cmake_brief::
+#
+#       Adds a library with precompiled preconditioners and solvers
+#
+#    .. cmake_param:: BLOCKSIZES
+#       :multi:
+#
+#       The block sizes of vectors/matrices used in your module
+#
+#
+#    This function adds a library to the user's dune module which contains precompiled
+#    preconditioners and solvers. This allows for faster compilation of the actual module.
+#    This pays off especially when using a factory to create preconditioners and solvers
+#    dynamically.
+#    The vector/matrix block sizes used in your module must be passed in order for the
+#    precompiled preconditioners and solvers to be used.
+
 
 find_package(METIS)
 find_package(ParMETIS)
@@ -16,3 +35,87 @@ include(AddSuiteSparseFlags)
 # enable / disable backwards compatibility w.r.t. category
 set(DUNE_ISTL_SUPPORT_OLD_CATEGORY_INTERFACE 1
   "Enable/Disable the backwards compatibility of the category enum/method in dune-istl solvers, preconditioner, etc. '1'")
+
+# We always have to write the header because it will always be included
+file(WRITE ${CMAKE_BINARY_DIR}/solvertemplates.hh "// Placeholder for istl library includes\n")
+
+set (DUNE_ADD_ISTL_LIBRARY_CALLED 0 CACHE INTERNAL "")
+
+
+# Allow including a library for precompiled preconditioners / solvers
+function(dune_add_istl_library)
+
+  cmake_minimum_required(VERSION 3.1)
+
+  # Only allow this to be called once
+  if (DUNE_ADD_ISTL_LIBRARY_CALLED)
+    message(FATAL_ERROR "You may only call dune_add_istl_library once per module!")
+  endif()
+  set (DUNE_ADD_ISTL_LIBRARY_CALLED 1 CACHE INTERNAL "")
+
+  # Set library name from current module name
+  string(REGEX REPLACE "[^a-zA-Z0-9-]" "_" safe_proj_name ${CMAKE_PROJECT_NAME})
+  set(libname ${safe_proj_name}-istl)
+
+  # Check if listed in dune_enable_all_packages
+  set (found -1)
+  if (DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES)
+    foreach(module_lib ${DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES})
+      if (${module_lib} STREQUAL ${libname})
+        set (found 1)
+        break()
+      endif()
+    endforeach()
+  endif()
+  if (${found} EQUAL -1)
+    message(FATAL_ERROR "You have to register ${libname} as a module library in dune_enable_all_packages before calling dune_add_istl_library!")
+  endif()
+
+
+
+  # Parse input
+  include(CMakeParseArguments)
+  set(MULTIARGS BLOCKSIZES)
+  cmake_parse_arguments(ADDLIB "" "" "${MULTIARGS}" ${ARGN})
+
+  # Check whether the parser produced any errors
+  if(ADDLIB_UNPARSED_ARGUMENTS)
+    message(WARNING "Unrecognized arguments ('${ADDLIB_UNPARSED_ARGUMENTS}') for dune_add_istl_library!")
+  endif()
+
+  # Check BLOCKSIZES for correctness
+  if(NOT ADDLIB_BLOCKSIZES)
+    message(FATAL_ERROR "BLOCKSIZES has to be specified!")
+  endif()
+  foreach(bs ${ADDLIB_BLOCKSIZES})
+    if(NOT "${bs}" MATCHES "[1-9][0-9]*")
+      message(FATAL_ERROR "${bs} was given to the BLOCKSIZES arugment of dune_add_istl_library, but it does not seem like a correct block size number")
+    endif()
+  endforeach()
+
+
+
+  # Get module path of istl
+  dune_module_path(MODULE dune-istl RESULT moddir CMAKE_MODULES)
+
+  # Generate template instantiation headers and cc's
+  file(WRITE ${CMAKE_BINARY_DIR}/solvertemplates.cc "// Auto-generated template stuff\n")
+  file(WRITE ${CMAKE_BINARY_DIR}/solvertemplates.hh "// Auto-generated template stuff\n")
+  foreach(bs ${ADDLIB_BLOCKSIZES})
+    set(BLOCKSIZE ${bs})
+    configure_file("${moddir}/solvertemplates.hh" ${CMAKE_BINARY_DIR}/solvertemplates${bs}.hh)
+    configure_file("${moddir}/solvertemplates.cc" ${CMAKE_BINARY_DIR}/solvertemplates${bs}.cc)
+
+    file(APPEND ${CMAKE_BINARY_DIR}/solvertemplates.cc "#include \"solvertemplates${bs}.cc\"\n")
+    file(APPEND ${CMAKE_BINARY_DIR}/solvertemplates.hh "#include \"solvertemplates${bs}.hh\"\n")
+
+  endforeach()
+  include_directories(${CMAKE_BINARY_DIR})
+
+
+
+  # Build library
+  dune_library_add_sources(${libname} SOURCES ${CMAKE_BINARY_DIR}/solvertemplates.cc)
+
+
+endfunction()
diff --git a/cmake/modules/solvertemplates.cc b/cmake/modules/solvertemplates.cc
new file mode 100644
index 000000000..3c763c2db
--- /dev/null
+++ b/cmake/modules/solvertemplates.cc
@@ -0,0 +1,55 @@
+#include <config.h>
+#include <dune/istl/bvector.hh>
+#include <dune/istl/bcrsmatrix.hh>
+#include <dune/common/parallel/indexset.hh>
+#include <dune/istl/paamg/pinfo.hh>
+#include <dune/istl/paamg/amg.hh>
+#include <dune/istl/owneroverlapcopy.hh> // For instantiation of parallel factories
+#include <dune/istl/factory.hh>
+
+namespace Dune {
+
+#if HAVE_MPI
+
+  namespace Precomp${BLOCKSIZE} {
+
+    typedef Dune::BlockVector<Dune::FieldVector<double,${BLOCKSIZE}> > V;
+    typedef Dune::BCRSMatrix<Dune::FieldMatrix<double,${BLOCKSIZE},${BLOCKSIZE}> > M;
+    typedef OwnerOverlapCopyCommunication<int> COMM;
+
+    typedef Dune::OverlappingSchwarzOperator<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::COMM> Operator1;
+    typedef Dune::SeqSSOR<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> Smoother1;
+    typedef Dune::BlockPreconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::COMM,Smoother1> ParSmoother1;
+
+  }
+  template class Amg::AMG<Precomp${BLOCKSIZE}::Operator1,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::ParSmoother1,Precomp${BLOCKSIZE}::COMM>;
+
+  template std::shared_ptr<InverseOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::SolverPrecondFactory::create<Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::COMM, Precomp${BLOCKSIZE}::M>(const Precomp${BLOCKSIZE}::M& A, const Precomp${BLOCKSIZE}::COMM& comm, ParameterTree& configuration, std::string group);
+  template std::shared_ptr<Preconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::PreconditionerFactory::create<Precomp${BLOCKSIZE}::COMM, Precomp${BLOCKSIZE}::M, Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::V>(std::string id, const Precomp${BLOCKSIZE}::M& A, const ParameterTree& configuration, const Precomp${BLOCKSIZE}::COMM& comm, std::shared_ptr<LinearOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> >& out_linearoperator);
+  template std::shared_ptr<InverseOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::SolverFactory::create<Precomp${BLOCKSIZE}::V>(std::shared_ptr<LinearOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > linearoperator, std::shared_ptr<Preconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > preconditioner, std::string id, const ParameterTree& configuration, const Precomp${BLOCKSIZE}::COMM& comm);
+
+#endif
+
+  template std::shared_ptr<Dune::InverseOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::SolverPrecondFactory::create<Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::M>(const Precomp${BLOCKSIZE}::M& A, ParameterTree& configuration, std::string group);
+  template std::shared_ptr<Dune::Preconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::PreconditionerFactory::create<Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::M>(std::string id, const Precomp${BLOCKSIZE}::M& A, const ParameterTree& configuration);
+  template std::shared_ptr<Dune::InverseOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::SolverFactory::create<Precomp${BLOCKSIZE}::V>(std::shared_ptr<LinearOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > linearoperator, std::shared_ptr<Preconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > preconditioner, std::string id, const ParameterTree& configuration);
+
+
+  template class Dune::BiCGSTABSolver<Precomp${BLOCKSIZE}::V>;
+  template class Dune::CGSolver<Precomp${BLOCKSIZE}::V>;
+  template class Dune::GeneralizedPCGSolver<Precomp${BLOCKSIZE}::V>;
+  template class Dune::GradientSolver<Precomp${BLOCKSIZE}::V>;
+  template class Dune::LoopSolver<Precomp${BLOCKSIZE}::V>;
+  template class Dune::MINRESSolver<Precomp${BLOCKSIZE}::V>;
+  template class Dune::RestartedGMResSolver<Precomp${BLOCKSIZE}::V>;
+
+  template class Amg::AMG<MatrixOperator<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>,Precomp${BLOCKSIZE}::V,SeqSSOR<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> >;
+  template class Dune::Richardson<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  template class Dune::SeqGS<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  template class Dune::SeqILU0<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  template class Dune::SeqILUn<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  template class Dune::SeqJac<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  template class Dune::SeqSSOR<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  template class Dune::SeqSOR<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+
+}
diff --git a/cmake/modules/solvertemplates.hh b/cmake/modules/solvertemplates.hh
new file mode 100644
index 000000000..a771680c4
--- /dev/null
+++ b/cmake/modules/solvertemplates.hh
@@ -0,0 +1,59 @@
+#include <dune/istl/bvector.hh>
+#include <dune/istl/bcrsmatrix.hh>
+#include <dune/common/parallel/indexset.hh>
+#include <dune/istl/paamg/pinfo.hh>
+#include <dune/istl/paamg/amg.hh>
+#include <dune/istl/owneroverlapcopy.hh> // For instantiation of parallel factories
+#include <dune/istl/factory.hh>
+
+#ifndef DUNE_ISTL_SOLVERTEMPLATES${BLOCKSIZE}_HH
+#define DUNE_ISTL_SOLVERTEMPLATES${BLOCKSIZE}_HH
+
+namespace Dune {
+
+#if HAVE_MPI
+
+  namespace Precomp${BLOCKSIZE} {
+
+    typedef Dune::BlockVector<Dune::FieldVector<double,${BLOCKSIZE}> > V;
+    typedef Dune::BCRSMatrix<Dune::FieldMatrix<double,${BLOCKSIZE},${BLOCKSIZE}> > M;
+    typedef OwnerOverlapCopyCommunication<int> COMM;
+
+    typedef Dune::OverlappingSchwarzOperator<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::COMM> Operator1;
+    typedef Dune::SeqSSOR<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> Smoother1;
+    typedef Dune::BlockPreconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::COMM,Smoother1> ParSmoother1;
+
+  }
+  extern template class Amg::AMG<Precomp${BLOCKSIZE}::Operator1,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::ParSmoother1,Precomp${BLOCKSIZE}::COMM>;
+
+  extern template std::shared_ptr<InverseOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::SolverPrecondFactory::create<Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::COMM, Precomp${BLOCKSIZE}::M>(const Precomp${BLOCKSIZE}::M& A, const Precomp${BLOCKSIZE}::COMM& comm, ParameterTree& configuration, std::string group);
+  extern template std::shared_ptr<Preconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::PreconditionerFactory::create<Precomp${BLOCKSIZE}::COMM, Precomp${BLOCKSIZE}::M, Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::V>(std::string id, const Precomp${BLOCKSIZE}::M& A, const ParameterTree& configuration, const Precomp${BLOCKSIZE}::COMM& comm, std::shared_ptr<LinearOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> >& out_linearoperator);
+  extern template std::shared_ptr<InverseOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::SolverFactory::create<Precomp${BLOCKSIZE}::V>(std::shared_ptr<LinearOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > linearoperator, std::shared_ptr<Preconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > preconditioner, std::string id, const ParameterTree& configuration, const Precomp${BLOCKSIZE}::COMM& comm);
+
+#endif
+
+  extern template std::shared_ptr<Dune::InverseOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::SolverPrecondFactory::create<Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::M>(const Precomp${BLOCKSIZE}::M& A, ParameterTree& configuration, std::string group);
+  extern template std::shared_ptr<Dune::Preconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::PreconditionerFactory::create<Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::V, Precomp${BLOCKSIZE}::M>(std::string id, const Precomp${BLOCKSIZE}::M& A, const ParameterTree& configuration);
+  extern template std::shared_ptr<Dune::InverseOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > Dune::SolverFactory::create<Precomp${BLOCKSIZE}::V>(std::shared_ptr<LinearOperator<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > linearoperator, std::shared_ptr<Preconditioner<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> > preconditioner, std::string id, const ParameterTree& configuration);
+
+
+  extern template class Dune::BiCGSTABSolver<Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::CGSolver<Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::GeneralizedPCGSolver<Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::GradientSolver<Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::LoopSolver<Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::MINRESSolver<Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::RestartedGMResSolver<Precomp${BLOCKSIZE}::V>;
+
+  extern template class Amg::AMG<MatrixOperator<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>,Precomp${BLOCKSIZE}::V,SeqSSOR<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V> >;
+  extern template class Dune::Richardson<Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::SeqGS<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::SeqILU0<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::SeqILUn<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::SeqJac<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::SeqSSOR<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+  extern template class Dune::SeqSOR<Precomp${BLOCKSIZE}::M,Precomp${BLOCKSIZE}::V,Precomp${BLOCKSIZE}::V>;
+
+}
+
+#endif
diff --git a/config.h.cmake b/config.h.cmake
index 3c488a94a..6845e4e5e 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -71,6 +71,9 @@
 /* Define to the revision of dune-istl */
 #define DUNE_ISTL_VERSION_REVISION ${DUNE_ISTL_VERSION_REVISION}
 
+/* Includes for istl library */
+#include "solvertemplates.hh"
+
 /* end dune-istl
    Everything below here will be overwritten
 */
-- 
GitLab