getfem-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Getfem-commits] (no subject)


From: Konstantinos Poulios
Subject: [Getfem-commits] (no subject)
Date: Tue, 23 Jan 2024 05:31:40 -0500 (EST)

branch: add-umfpack-interface
commit a3afc92c2b6a10b138da320b28e06baa75746e94
Author: Konstantinos Poulios <logari81@gmail.com>
AuthorDate: Tue Jan 23 11:30:21 2024 +0100

    Add experimental UMFPACK support
    
      - compiles but does not work properly yet
---
 CMakeLists.txt                        |   1 +
 cmake/gmm_arch_config.h.in            |   3 +
 configure.ac                          | 107 ++++++++++++++++++-
 src/Makefile.am                       |   1 +
 src/getfem/getfem_model_solvers.h     |  21 ++++
 src/gmm/gmm_UMFPACK_interface.h       | 188 ++++++++++++++++++++++++++++++++++
 src/gmm/gmm_arch_config.h.in          |   3 +
 src/gmm/gmm_solver_Schwarz_additive.h |   8 +-
 tests/test_condensation.cc            |   4 +-
 9 files changed, 329 insertions(+), 7 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7ff2cdd8..be062820 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -322,6 +322,7 @@ set(HEADERS
     src/gmm/gmm_superlu_interface.h
     src/gmm/gmm_transposed.h
     src/gmm/gmm_tri_solve.h
+    src/gmm/gmm_UMFPACK_interface.h
     src/gmm/gmm_vector.h
     src/gmm/gmm_vector_to_matrix.h
     src/getfem/bgeot_comma_init.h
diff --git a/cmake/gmm_arch_config.h.in b/cmake/gmm_arch_config.h.in
index 50f47daa..4b4b029a 100644
--- a/cmake/gmm_arch_config.h.in
+++ b/cmake/gmm_arch_config.h.in
@@ -19,6 +19,9 @@
 /* defined if GMM is linked to the superlu library */
 #cmakedefine GMM_USES_SUPERLU
 
+/* defined if GMM is linked to the umfpack library */
+#cmakedefine GMM_USES_UMFPACK
+
 /* Use blas with 64 bits integers */
 #cmakedefine GMM_USE_BLAS64_INTERFACE
 
diff --git a/configure.ac b/configure.ac
index cd519ed5..65e505ce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -958,9 +958,98 @@ fi
 dnl ---------------------------END OF MUMPS TEST--------------------------
 
 
+dnl ------------------------------UMFPACK TEST----------------------------
+require_umfpack="auto"
+AC_ARG_ENABLE(umfpack,
+  [AS_HELP_STRING([--enable-umfpack], [Enable UMFPACK support])],
+  [require_umfpack=$enableval],
+  [require_umfpack="auto"])
+
+UMFPACK_LIBS="-lumfpack"
+# the user can override these defaults using --with-umfpack=
+AC_ARG_WITH(umfpack,
+ [AS_HELP_STRING([--with-umfpack=<lib>],[use UMFPACK library <lib>])],
+ [case $with_umfpack in
+   yes | "")
+     if test "x$require_umfpack" = "xno"; then
+       AC_MSG_ERROR([Contradicting arguments between --enable-umfpack and 
--with-umfpack.])
+     elif test "x$require_umfpack" = "xauto"; then
+       require_umfpack="yes"
+     fi;;
+   no)
+     if test "x$require_umfpack" = "xyes"; then
+       AC_MSG_ERROR([Contradicting arguments between --enable-umfpack and 
--with-umfpack.])
+     elif test "x$require_umfpack" = "xauto"; then
+       require_umfpack="no"
+     fi;;
+   -* | */* | *.a | *.so | *.so.* | *.o| builtin) 
UMFPACK_LIBS="$with_umfpack";;
+   *) UMFPACK_LIBS=`echo $with_umfpack | sed -e 's/^/-l/g;s/ \+/ -l/g'`;;
+  esac]
+)
+
+UMFPACKINC=""
+AC_ARG_WITH(umfpack-include-dir,
+ [AS_HELP_STRING([--with-umfpack-include-dir],[directory in which the 
umfpack.h headers can be found])],
+ [ if test x$require_umfpack = xno; then
+     AC_MSG_ERROR([Inconsistent options for --enable-umfpack, --with-umfpack 
and --with-umfpack-include-dir.]);
+   else
+     require_umfpack="yes"
+     case $withval in
+       -I* ) UMFPACKINC="$withval";;
+       * ) UMFPACKINC="-I$withval";;
+     esac
+   fi;],
+)
+CPPFLAGS="$CPPFLAGS $UMFPACKINC"
 
-if test "x$found_superlu" = "xno" -a "x$found_mumps" = "xno"; then
-  AC_MSG_ERROR([Neither MUMPS nor SuperLU was enabled. At least one linear 
solver is required.])
+if test "x$require_umfpack" = "xno"; then
+  UMFPACK_LIBS=""
+  found_umfpack="no"
+  echo "Building with UMFPACK explicitly disabled";
+else
+  AC_CHECK_HEADERS(
+    [umfpack.h],
+    [found_umfpack="yes"],
+    [ if test "x$require_umfpack" = "xyes"; then
+        AC_MSG_ERROR([Header files of UMFPACK not found.]);
+      else
+        found_umfpack="no"
+      fi;
+    ])
+  if test x$found_umfpack = xyes; then
+    save_LIBS="$LIBS";
+    AC_CHECK_LIB([umfpack], [umfpack_di_solve],
+                 [AC_DEFINE(GMM_USES_UMFPACK,,[defined if GMM is linked to the 
umfpack library])],
+                 [if test "x$require_umfpack" = "xyes"; then
+                    AC_MSG_ERROR([UMFPACK library not found]);
+                  else
+                    found_umfpack="no"
+                  fi;])
+    if test "x$found_umfpack" = "xyes"; then
+      echo "Building with UMFPACK (use --enable-umfpack=no to disable it)"
+      LIBS="$UMFPACK_LIBS $save_LIBS"
+    else
+      UMFPACK_LIBS=""
+      LIBS="$save_LIBS"
+    fi
+  elif test "x$require_umfpack" = "xyes"; then
+    AC_MSG_ERROR([UMFPACK header files not found but required by the user. 
Aborting configure...]);
+  else
+    echo "UMFPACK header files not found, building without UMFPACK"
+    UMPFPACK_LIBS=""
+  fi
+fi
+
+AM_CONDITIONAL(UMFPACK, test x$found_umfpack = xyes)
+AC_SUBST([UMFPACK_LIBS])
+if test "x$found_umfpack" = "xyes"; then
+  echo "Configuration of UMFPACK done"
+fi
+dnl ---------------------------END OF UMFPACK TEST------------------------
+
+
+if test "x$found_superlu" = "xno" -a "x$found_mumps" = "xno" -a 
"x$found_umfpack" = "xno"; then
+  AC_MSG_ERROR([Neither MUMPS, SuperLU, nor UMFPACK was enabled. At least one 
external direct linear solver is required.])
   exit 1
 fi
 
@@ -1273,12 +1362,22 @@ else
 fi;
 
 if test "x$found_mumps" = "xyes"; then
-  echo "- Mumps found. A direct solver for large sparse linear systems."
+  echo "- MUMPS found. A direct solver for large sparse linear systems."
 else
   if test "x$require_mumps" = "xno"; then
     echo "- Not using the MUMPS library for large sparse linear systems."
   else
-    echo "- Mumps not found. Not using the MUMPS library for large sparse 
linear systems."
+    echo "- MUMPS not found. Not using the MUMPS library for large sparse 
linear systems."
+  fi
+fi;
+
+if test "x$found_umfpack" = "xyes"; then
+  echo "- UMFPACK found. A direct solver for large sparse linear systems."
+else
+  if test "x$require_umfpack" = "xno"; then
+    echo "- Not using the UMFPACK library for large sparse linear systems."
+  else
+    echo "- UMFPACK not found. Not using the UMFPACK library for large sparse 
linear systems."
   fi
 fi;
 
diff --git a/src/Makefile.am b/src/Makefile.am
index c002f042..61b3da0c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -73,6 +73,7 @@ nobase_include_HEADERS =                              \
        gmm/gmm_except.h                                \
        gmm/gmm_feedback_management.h                   \
        gmm/gmm_MUMPS_interface.h                       \
+       gmm/gmm_UMFPACK_interface.h                     \
        getfem/dal_config.h                             \
        getfem/dal_singleton.h                          \
        getfem/dal_basic.h                              \
diff --git a/src/getfem/getfem_model_solvers.h 
b/src/getfem/getfem_model_solvers.h
index da570c01..01112a6c 100644
--- a/src/getfem/getfem_model_solvers.h
+++ b/src/getfem/getfem_model_solvers.h
@@ -42,6 +42,7 @@
 #include "getfem_models.h"
 #include "gmm/gmm_superlu_interface.h"
 #include "gmm/gmm_MUMPS_interface.h"
+#include "gmm/gmm_UMFPACK_interface.h"
 #include "gmm/gmm_iter.h"
 #include "gmm/gmm_iter_solvers.h"
 #include "gmm/gmm_dense_qr.h"
@@ -190,6 +191,17 @@ namespace getfem {
   };
 #endif
 
+#if defined(GMM_USES_UMFPACK)
+  template <typename MAT, typename VECT>
+  struct linear_solver_umfpack : public abstract_linear_solver<MAT, VECT> {
+    void operator ()(const MAT &M, VECT &x, const VECT &b,
+                     gmm::iteration &iter) const {
+      bool ok = gmm::UMFPACK_solve(M, x, b);
+      iter.enforce_converged(ok);
+    }
+  };
+#endif
+
 #if GETFEM_PARA_LEVEL > 1 && GETFEM_PARA_SOLVER == MUMPS_PARA_SOLVER
   template <typename MAT, typename VECT>
   struct linear_solver_distributed_mumps
@@ -645,6 +657,8 @@ namespace getfem {
         return std::make_shared<linear_solver_mumps<MATRIX, VECTOR>>();
 # elif defined(GMM_USES_SUPERLU)
       return std::make_shared<linear_solver_superlu<MATRIX, VECTOR>>();
+# elif defined(GMM_USES_UMFPACK)
+      return std::make_shared<linear_solver_umfpack<MATRIX, VECTOR>>();
 # else
       static_assert(false,
                     "At least one direct solver (MUMPS or SuperLU) is 
required");
@@ -690,6 +704,13 @@ namespace getfem {
 # endif
 #else
       GMM_ASSERT1(false, "Mumps is not interfaced");
+#endif
+    }
+    else if (bgeot::casecmp(name, "umfpack") == 0) {
+#if defined(GMM_USES_UMFPACK)
+      return std::make_shared<linear_solver_umfpack<MATRIX, VECTOR>>();
+#else
+      GMM_ASSERT1(false, "UMFPACK is not interfaced");
 #endif
     }
     else if (bgeot::casecmp(name, "cg/ildlt") == 0)
diff --git a/src/gmm/gmm_UMFPACK_interface.h b/src/gmm/gmm_UMFPACK_interface.h
new file mode 100644
index 00000000..1efe2602
--- /dev/null
+++ b/src/gmm/gmm_UMFPACK_interface.h
@@ -0,0 +1,188 @@
+/* -*- c++ -*- (enables emacs c++ mode) */
+/*===========================================================================
+
+ Copyright (C) 2024-2024 Konstantinos Poulios
+
+ This file is a part of GetFEM
+
+ GetFEM  is  free software;  you  can  redistribute  it  and/or modify it
+ under  the  terms  of the  GNU  Lesser General Public License as published
+ by  the  Free Software Foundation;  either version 3 of the License,  or
+ (at your option) any later version along with the GCC Runtime Library
+ Exception either version 3.1 or (at your option) any later version.
+ This program  is  distributed  in  the  hope  that it will be useful,  but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or  FITNESS  FOR  A PARTICULAR PURPOSE.  See the GNU Lesser General Public
+ License and GCC Runtime Library Exception for more details.
+ You  should  have received a copy of the GNU Lesser General Public License
+ along  with  this program;  if not, write to the Free Software Foundation,
+ Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ As a special exception, you  may use  this file  as it is a part of a free
+ software  library  without  restriction.  Specifically,  if   other  files
+ instantiate  templates  or  use macros or inline functions from this file,
+ or  you compile this  file  and  link  it  with other files  to produce an
+ executable, this file  does  not  by itself cause the resulting executable
+ to be covered  by the GNU Lesser General Public License.  This   exception
+ does not  however  invalidate  any  other  reasons why the executable file
+ might be covered by the GNU Lesser General Public License.
+
+===========================================================================*/
+
+/**@file gmm_UMFPACK_interface.h
+   @author Konstantinos Poulios <logari81@gmail.com>,
+   @date January 11, 2024.
+   @brief Interface with UMFPACK (direct solver for sparse matrices).
+*/
+#if defined(GMM_USES_UMFPACK)
+
+#ifndef GMM_UMFPACK_INTERFACE_H
+#define GMM_UMFPACK_INTERFACE_H
+
+#include "gmm_kernel.h"
+
+
+extern "C" {
+#include <umfpack.h>
+}
+
+namespace gmm {
+
+  /* ********************************************************************* */
+  /*   UMFPACK solve interface                                             */
+  /* ********************************************************************* */
+
+  //
+  template <typename T>
+  struct umfpack_interf {
+    int n;
+    std::vector<int> c;
+    std::vector<int> i;
+    std::vector<double> ar;
+    std::vector<double> xr;
+    std::vector<double> br;
+
+    inline int
+    umfpack_symbolic(void **output) {
+      return umfpack_di_symbolic(n, n, &(c[0]), &(i[0]), &(ar[0]),
+                                 output, NULL, NULL);
+    }
+    inline int
+    umfpack_numeric(void *symbolic, void **output) {
+      return umfpack_di_numeric(&(c[0]), &(i[0]), &(ar[0]),
+                                symbolic, output, NULL, NULL);
+    }
+    static inline void
+    umfpack_free_symbolic(void **symbolic) {
+      umfpack_di_free_symbolic(symbolic);
+    }
+    inline int
+    umfpack_solve(void *numeric) {
+      return umfpack_di_solve(UMFPACK_A, &(c[0]), &(i[0]), &(ar[0]),
+                              &(xr[0]), &(br[0]), numeric, NULL, NULL);
+    }
+    static inline void
+    umfpack_free_numeric(void **numeric) {
+      umfpack_di_free_numeric(numeric);
+    }
+    template<typename MAT, typename VECTX, typename VECTB>
+    umfpack_interf(MAT &A, VECTX &X, VECTB &B)
+    {
+      n = int(gmm::vect_size(B));
+      GMM_ASSERT2(gmm::mat_nrows(A) == size_type(n), "Incompatible 
matrix-vector sizes");
+      GMM_ASSERT2(gmm::mat_ncols(A) == size_type(n), "System matrix needs to 
be square");
+      xr.resize(n);
+      br.resize(n);
+      gmm::copy(X, xr);
+      gmm::copy(B, br);
+      csc_matrix<double> csc_A(n, n);
+      gmm::copy(A, csc_A);
+      c.resize(csc_A.jc.size());
+      i.resize(csc_A.ir.size());
+      ar.resize(csc_A.pr.size());
+      gmm::copy(csc_A.jc, c);
+      gmm::copy(csc_A.ir, i);
+      gmm::copy(csc_A.pr, ar);
+    }
+  };
+
+  template <typename T>
+  struct umfpack_interf<std::complex<T>> {
+    int n;
+    std::vector<int> c;
+    std::vector<int> i;
+    std::vector<double> ar, ai;
+    std::vector<double> xr, xi;
+    std::vector<double> br, bi;
+  
+    inline int
+    umfpack_symbolic(void **output) {
+      return umfpack_zi_symbolic(n, n, &(c[0]), &(i[0]), &(ar[0]), &(ai[0]),
+                                 output, NULL, NULL);
+    }
+    inline int
+    umfpack_numeric(void *symbolic, void **output) {
+      return umfpack_zi_numeric(&(c[0]), &(i[0]), &(ar[0]), &(ai[0]),
+                                symbolic, output, NULL, NULL);
+    }
+    static inline void
+    umfpack_free_symbolic(void **symbolic) {
+      umfpack_zi_free_symbolic(symbolic);
+    }
+    inline int
+    umfpack_solve(void *numeric) {
+      return umfpack_zi_solve(UMFPACK_A, &(c[0]), &(i[0]), &(ar[0]), &(ai[0]),
+                              &(xr[0]), &(xi[0]), &(br[0]), &(bi[0]), numeric, 
NULL, NULL);
+    }
+    static inline void
+    umfpack_free_numeric(void **numeric) {
+      umfpack_zi_free_numeric(numeric);
+    }
+    template<typename MAT, typename VECTX, typename VECTB>
+    umfpack_interf(MAT &A, VECTX &X, VECTB &B)
+    {
+      n = int(gmm::vect_size(B));
+      GMM_ASSERT2(gmm::mat_nrows(A) == size_type(n), "Incompatible 
matrix-vector sizes");
+      GMM_ASSERT2(gmm::mat_ncols(A) == size_type(n), "System matrix needs to 
be square");
+      xr.resize(n);
+      xi.resize(n);
+      br.resize(n);
+      bi.resize(n);
+      gmm::copy(gmm::real_part(X), xr);
+      gmm::copy(gmm::imag_part(X), xi);
+      gmm::copy(gmm::real_part(B), br);
+      gmm::copy(gmm::imag_part(B), bi);
+      csc_matrix<std::complex<double>> csc_A(n, n);
+      gmm::copy(A, csc_A);
+      c.resize(csc_A.jc.size());
+      i.resize(csc_A.ir.size());
+      ar.resize(csc_A.pr.size());
+      ai.resize(csc_A.pr.size());
+      gmm::copy(csc_A.jc, c);
+      gmm::copy(csc_A.ir, i);
+      gmm::copy(gmm::real_part(csc_A.pr), ar);
+      gmm::copy(gmm::imag_part(csc_A.pr), ai);
+    }
+  };
+
+  // UMFPACK solve interface, returns "true" if successful
+  template <typename MAT, typename VECTX, typename VECTB>
+  bool UMFPACK_solve(const MAT &A, VECTX &X, const VECTB &B) {
+    typedef typename linalg_traits<MAT>::value_type T;
+    umfpack_interf<T> intrf(A, B, X); // possibly convert float to double
+                                      // umfpack supports only double precision
+    int status;
+    void *symbolic, *numeric;
+    status = intrf.umfpack_symbolic(&symbolic);
+    status = intrf.umfpack_numeric(symbolic, &numeric);
+    intrf.umfpack_free_symbolic(&symbolic);
+    status = intrf.umfpack_solve(numeric);
+    intrf.umfpack_free_numeric(&numeric);
+    return (status == UMFPACK_OK);
+  }
+
+}
+  
+#endif // GMM_UMFPACK_INTERFACE_H
+
+#endif // GMM_USES_UMFPACK
diff --git a/src/gmm/gmm_arch_config.h.in b/src/gmm/gmm_arch_config.h.in
index 0d46b9ab..2c7dc709 100644
--- a/src/gmm/gmm_arch_config.h.in
+++ b/src/gmm/gmm_arch_config.h.in
@@ -18,6 +18,9 @@
 /* defined if GMM is linked to the superlu library */
 #undef GMM_USES_SUPERLU
 
+/* defined if GMM is linked to the umfpack library */
+#undef GMM_USES_UMFPACK
+
 /* Use blas with 64 bits integers */
 #undef GMM_USE_BLAS64_INTERFACE
 
diff --git a/src/gmm/gmm_solver_Schwarz_additive.h 
b/src/gmm/gmm_solver_Schwarz_additive.h
index 378534e1..5a2c9cbc 100644
--- a/src/gmm/gmm_solver_Schwarz_additive.h
+++ b/src/gmm/gmm_solver_Schwarz_additive.h
@@ -41,8 +41,10 @@
 #include "gmm_kernel.h"
 #if defined(GMM_USES_SUPERLU)
 #include "gmm_superlu_interface.h"
-#else
+#elif defined(GMM_USES_MUMPS)
 #include "gmm_MUMPS_interface.h"
+#else //defined(GMM_USES_UMFPACK)
+#include "gmm_UMFPACK_interface.h"
 #endif
 #include "gmm_solver_cg.h"
 #include "gmm_solver_gmres.h"
@@ -575,8 +577,10 @@ namespace gmm {
 #if defined(GMM_USES_SUPERLU)
       double rcond;
       gmm::SuperLU_solve(M.vMloc[i], x, w, rcond);
-#else
+#elif defined(GMM_USES_MUMPS)
       gmm::MUMPS_solve(M.vMloc[i], x, w);
+#else // defined(GMM_USES_UMFPACK)
+      gmm::UMFPACK_solve(M.vMloc[i], x, w);
 #endif
       // gmm::iteration iter(1E-10, 0, 100000);
       //gmm::gmres(M.vMloc[i], x, w, gmm::identity_matrix(), 50, iter);
diff --git a/tests/test_condensation.cc b/tests/test_condensation.cc
index d62c3ed2..9509f53d 100644
--- a/tests/test_condensation.cc
+++ b/tests/test_condensation.cc
@@ -35,8 +35,10 @@ int main(int argc, char *argv[]) {
 
 #if defined(GMM_USES_MUMPS)
   std::string lsolver("mumps");
-#else
+#elif defined(GMM_USES_SUPERLU)
   std::string lsolver("superlu");
+#else
+  std::string lsolver("umfpack");
 #endif
 
   gmm::set_traces_level(1);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]