]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Detect and use METIS to partition triangulations.
authorWolfgang Bangerth <bangerth@math.tamu.edu>
Mon, 8 Mar 2004 22:24:59 +0000 (22:24 +0000)
committerWolfgang Bangerth <bangerth@math.tamu.edu>
Mon, 8 Mar 2004 22:24:59 +0000 (22:24 +0000)
git-svn-id: https://svn.dealii.org/trunk@8681 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/aclocal.m4
deal.II/base/include/base/config.h.in
deal.II/configure
deal.II/configure.in
deal.II/deal.II/include/grid/grid_tools.h
deal.II/deal.II/source/grid/grid_tools.cc
deal.II/doc/development/Makefile
deal.II/doc/development/makefiles.1.html
deal.II/lac/include/lac/sparsity_pattern.h
deal.II/lac/source/sparsity_pattern.cc
tests/bits/metis_01.cc [new file with mode: 0644]

index e63ca75f0f7dd39dcc6da7c6391b846bf4a5dff5..44813481a5614f06f9d997a084bbabd4265a2776 100644 (file)
@@ -3717,3 +3717,60 @@ AC_DEFUN(DEAL_II_CONFIGURE_PETSC, dnl
        ])
   fi
 ])
+
+
+
+dnl ------------------------------------------------------------
+dnl Check whether Metis is installed, and if so store the 
+dnl respective links
+dnl
+dnl Usage: DEAL_II_CONFIGURE_METIS
+dnl
+dnl ------------------------------------------------------------
+AC_DEFUN(DEAL_II_CONFIGURE_METIS, dnl
+[
+  dnl First check for the Metis directory
+  AC_MSG_CHECKING(for Metis library directory)
+
+  AC_ARG_WITH(metis,
+  [  --with-metis=/path/to/metis   Specify the path to the Metis installation,
+                                   of which the include and library directories
+                                   are subdirs; use this if you want to
+                                   override the METIS_DIR environment variable],
+     [
+       USE_CONTRIB_METIS=yes
+        DEAL_II_METIS_DIR=$withval
+       AC_MSG_RESULT($DEAL_II_METIS_DIR)
+
+        dnl Make sure that what was specified is actually correct
+        if test ! -d $DEAL_II_METIS_DIR/Lib ; then
+          AC_MSG_ERROR([Path to Metis specified with --with-metis does not
+                       point to a complete Metis installation])
+       fi
+     ],
+     [
+        dnl Take something from the environment variables, if it is there
+        if test "x$METIS_DIR" != "x" ; then
+         USE_CONTRIB_METIS=yes
+          DEAL_II_METIS_DIR="$METIS_DIR"
+         AC_MSG_RESULT($DEAL_II_METIS_DIR)
+
+          dnl Make sure that what this is actually correct
+          if test ! -d $DEAL_II_METIS_DIR/include \
+               -o ! -d $DEAL_II_METIS_DIR/lib ; then
+            AC_MSG_ERROR([The path to Metis specified in the METIS_DIR
+                         environment variable does not
+                         point to a complete Metis installation])
+         fi
+        else
+         USE_CONTRIB_METIS=no
+          DEAL_II_METIS_DIR=""
+          AC_MSG_RESULT(not found)
+        fi
+     ])
+  if test "$USE_CONTRIB_METIS" = "yes" ; then
+    AC_DEFINE(DEAL_II_USE_METIS, 1,
+              [Defined if a Metis installation was found and is going
+               to be used])
+  fi
+])
index 865c05391f0be466561204ca9d2f590cad3164f3..cfcbb62c4d8a9a107cc5f9de45abb4d5db38ed08 100644 (file)
    provided by the compiler. */
 #undef DEAL_II_USE_DIRECT_ERRNO_H
 
+/* Defined if a Metis installation was found and is going to be used */
+#undef DEAL_II_USE_METIS
+
 /* Flag indicating whether the library shall be compiled for multithreaded
    applications. If so, then it is set to one, otherwise to zero. */
 #undef DEAL_II_USE_MT
index cd87a4a653518f94b313ea7ed956b5f78c0e77e7..0e4f390e0faecf9acf5993b2657b895591f16539 100755 (executable)
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 1.163 .
+# From configure.in Revision.
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.57.
 #
@@ -273,7 +273,7 @@ PACKAGE_BUGREPORT=
 
 ac_unique_file="deal.II"
 ac_subdirs_all="$ac_subdirs_all contrib tests"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS DEAL_II_VERSION DEAL_II_MAJOR DEAL_II_MINOR DEAL_II_PATH DEAL2_DIR build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX GXX_VERSION CXXFLAGSG CXXFLAGSO CXXFLAGSPIC SHLIBLD LDFLAGSPIC enablemultithreading withmultithreading F77 F77_VERSION F77FLAGSO F77FLAGSG F77FLAGSPIC F77LIBS enableshared lib_suffix AR RANLIB ac_ct_RANLIB enablemultigrid TECPLOT_LIBRARY_PATH TECPLOT_INCLUDE_PATH USE_CONTRIB_HSL USE_CONTRIB_PETSC DEAL_II_PETSC_DIR DEAL_II_PETSC_ARCH kdocdir kdocversion DOXYGEN PERL subdirs LIBOBJS LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS DEAL_II_VERSION DEAL_II_MAJOR DEAL_II_MINOR DEAL_II_PATH DEAL2_DIR build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CXX CXXFLAGS ac_ct_CXX GXX_VERSION CXXFLAGSG CXXFLAGSO CXXFLAGSPIC SHLIBLD LDFLAGSPIC enablemultithreading withmultithreading F77 F77_VERSION F77FLAGSO F77FLAGSG F77FLAGSPIC F77LIBS enableshared lib_suffix AR RANLIB ac_ct_RANLIB enablemultigrid TECPLOT_LIBRARY_PATH TECPLOT_INCLUDE_PATH USE_CONTRIB_HSL USE_CONTRIB_PETSC DEAL_II_PETSC_DIR DEAL_II_PETSC_ARCH USE_CONTRIB_METIS DEAL_II_METIS_DIR kdocdir kdocversion DOXYGEN PERL subdirs LIBOBJS LTLIBOBJS'
 ac_subst_files=''
 
 # Initialize some variables set by options.
@@ -833,6 +833,10 @@ Optional Packages:
                                      installation; use this if you want to
                                      override the PETSC_ARCH environment
                                      variable
+  --with-metis=/path/to/metis   Specify the path to the Metis installation,
+                                   of which the include and library directories
+                                   are subdirs; use this if you want to
+                                   override the METIS_DIR environment variable
   --with-cpu=cpu          Optimize specifically for the given CPU type,
                           rather than just generating code for this
                          processor family
@@ -7811,6 +7815,65 @@ fi;
 
 
 
+    echo "$as_me:$LINENO: checking for Metis library directory" >&5
+echo $ECHO_N "checking for Metis library directory... $ECHO_C" >&6
+
+
+# Check whether --with-metis or --without-metis was given.
+if test "${with_metis+set}" = set; then
+  withval="$with_metis"
+
+       USE_CONTRIB_METIS=yes
+        DEAL_II_METIS_DIR=$withval
+       echo "$as_me:$LINENO: result: $DEAL_II_METIS_DIR" >&5
+echo "${ECHO_T}$DEAL_II_METIS_DIR" >&6
+
+                if test ! -d $DEAL_II_METIS_DIR/Lib ; then
+          { { echo "$as_me:$LINENO: error: Path to Metis specified with --with-metis does not
+                       point to a complete Metis installation" >&5
+echo "$as_me: error: Path to Metis specified with --with-metis does not
+                       point to a complete Metis installation" >&2;}
+   { (exit 1); exit 1; }; }
+       fi
+
+else
+
+                if test "x$METIS_DIR" != "x" ; then
+         USE_CONTRIB_METIS=yes
+          DEAL_II_METIS_DIR="$METIS_DIR"
+         echo "$as_me:$LINENO: result: $DEAL_II_METIS_DIR" >&5
+echo "${ECHO_T}$DEAL_II_METIS_DIR" >&6
+
+                    if test ! -d $DEAL_II_METIS_DIR/include \
+               -o ! -d $DEAL_II_METIS_DIR/lib ; then
+            { { echo "$as_me:$LINENO: error: The path to Metis specified in the METIS_DIR
+                         environment variable does not
+                         point to a complete Metis installation" >&5
+echo "$as_me: error: The path to Metis specified in the METIS_DIR
+                         environment variable does not
+                         point to a complete Metis installation" >&2;}
+   { (exit 1); exit 1; }; }
+         fi
+        else
+         USE_CONTRIB_METIS=no
+          DEAL_II_METIS_DIR=""
+          echo "$as_me:$LINENO: result: not found" >&5
+echo "${ECHO_T}not found" >&6
+        fi
+
+fi;
+  if test "$USE_CONTRIB_METIS" = "yes" ; then
+
+cat >>confdefs.h <<\_ACEOF
+#define DEAL_II_USE_METIS 1
+_ACEOF
+
+  fi
+
+
+
+
+
 
 
 echo "$as_me:$LINENO: result: " >&5
@@ -8765,6 +8828,8 @@ s,@USE_CONTRIB_HSL@,$USE_CONTRIB_HSL,;t t
 s,@USE_CONTRIB_PETSC@,$USE_CONTRIB_PETSC,;t t
 s,@DEAL_II_PETSC_DIR@,$DEAL_II_PETSC_DIR,;t t
 s,@DEAL_II_PETSC_ARCH@,$DEAL_II_PETSC_ARCH,;t t
+s,@USE_CONTRIB_METIS@,$USE_CONTRIB_METIS,;t t
+s,@DEAL_II_METIS_DIR@,$DEAL_II_METIS_DIR,;t t
 s,@kdocdir@,$kdocdir,;t t
 s,@kdocversion@,$kdocversion,;t t
 s,@DOXYGEN@,$DOXYGEN,;t t
index 3ae1b2bb3b9a0881fde494b7f50849d1150f45c9..6c479d0387350d5db98276a12a34bb60d78d9d1f 100644 (file)
@@ -342,6 +342,10 @@ AC_SUBST(USE_CONTRIB_PETSC)
 AC_SUBST(DEAL_II_PETSC_DIR)
 AC_SUBST(DEAL_II_PETSC_ARCH)
 
+DEAL_II_CONFIGURE_METIS
+AC_SUBST(USE_CONTRIB_METIS)
+AC_SUBST(DEAL_II_METIS_DIR)
+
 
 
 dnl -------------------------------------------------------------
index 6623d7ae3fb038b9a9cd1d01840225335a01c5b2..8ffa04747cafd6d25aca5f7f0553a5a6801c9bd9 100644 (file)
@@ -2,7 +2,7 @@
 //    $Id$
 //    Version: $Name$
 //
-//    Copyright (C) 2001, 2002, 2003 by the deal.II authors
+//    Copyright (C) 2001, 2002, 2003, 2004 by the deal.II authors
 //
 //    This file is subject to QPL and may not be  distributed
 //    without copyright and license information. Please refer
@@ -28,7 +28,7 @@
  * cell that contains a given point. See the descriptions of the
  * individual functions for more information.
  *
- * @author Wolfgang Bangerth, 2001, 2003
+ * @author Wolfgang Bangerth, 2001, 2003, 2004
  */
 class GridTools
 {
@@ -233,7 +233,38 @@ class GridTools
     typename Container::active_cell_iterator
     find_active_cell_around_point (const Container  &container,
                                    const Point<dim> &p);
-    
+
+                                     /**
+                                      * Use the METIS partitioner to generate
+                                      * a partitioning of the active cells
+                                      * making up the entire domain. After
+                                      * calling this function, the subdomain
+                                      * ids of all active cells will have
+                                      * values between zero and
+                                      * @p{n_partitions-1}. You can access the
+                                      * subdomain id of a cell by using
+                                      * @p{cell->subdomain_id()}.
+                                      *
+                                      * This function will generate an error
+                                      * if METIS is not installed unless
+                                      * @p{n_partitions} is one. I.e., you can
+                                      * write a program so that it runs in the
+                                      * single-processor single-partition case
+                                      * without METIS installed, and only
+                                      * requires METIS when multiple
+                                      * partitions are required.
+                                      */
+    template <int dim>
+    static
+    void partition_triangulation (Triangulation<dim> &triangulation,
+                                  const unsigned int  n_partitions);
+                                     /**
+                                      * Exception
+                                      */
+    DeclException1 (ExcInvalidNumberOfPartitions,
+                    int,
+                    << "The number of partitions you gave is " << arg1
+                    << ", but must be greater than zero.");
                                     /**
                                      * Exception
                                      */
index 874b4453763cfedc8e66d0a516100dff8b37a8b0..66b0ef18dbe4be347985b89ec039422b93e0ba6f 100644 (file)
@@ -2,7 +2,7 @@
 //    $Id$
 //    Version: $Name$
 //
-//    Copyright (C) 2001, 2002, 2003 by the deal.II authors
+//    Copyright (C) 2001, 2002, 2003, 2004 by the deal.II authors
 //
 //    This file is subject to QPL and may not be  distributed
 //    without copyright and license information. Please refer
 #include <grid/tria.h>
 #include <grid/tria_accessor.h>
 #include <grid/tria_iterator.h>
+#include <lac/sparsity_pattern.h>
+#include <lac/compressed_sparsity_pattern.h>
 #include <dofs/dof_handler.h>
 #include <dofs/dof_accessor.h>
+#include <dofs/dof_tools.h>
+#include <fe/fe_dgq.h>
 #include <multigrid/mg_dof_handler.h>
 #include <multigrid/mg_dof_accessor.h>
 
@@ -238,6 +242,85 @@ GridTools::find_active_cell_around_point (const Container  &container,
 
 
 
+template <int dim>
+void
+GridTools::
+partition_triangulation (Triangulation<dim> &triangulation,
+                         const unsigned int  n_partitions)
+{
+  Assert (n_partitions > 0, ExcInvalidNumberOfPartitions(n_partitions));
+
+                                   // check for an easy return
+  if (n_partitions == 1)
+    {
+      for (typename Triangulation<dim>::active_cell_iterator
+             cell = triangulation.begin_active();
+           cell != triangulation.end(); ++cell)
+        cell->set_subdomain_id (0);
+      return;
+    }
+
+                                   // we decompose the domain by first
+                                   // generating the connection graph of all
+                                   // cells with their neighbors, and then
+                                   // passing this graph off to METIS. To make
+                                   // things a little simpler and more
+                                   // general, we let the function
+                                   // DoFTools:make_flux_sparsity_pattern
+                                   // function generate the connection graph
+                                   // for us and reuse the SparsityPattern
+                                   // data structure for the connection
+                                   // graph. The connection structure of the
+                                   // mesh is obtained by using a fake
+                                   // piecewise constant finite element
+                                   //
+                                   // Since in 3d the generation of a
+                                   // sparsity pattern can be expensive, we
+                                   // take the detour of the compressed
+                                   // sparsity pattern, which is a little
+                                   // slower but more efficient in terms of
+                                   // memory
+  FE_DGQ<dim> fake_q0(0);
+  DoFHandler<dim> dof_handler (triangulation);
+  dof_handler.distribute_dofs (fake_q0);
+  Assert (dof_handler.n_dofs() == triangulation.n_active_cells(),
+          ExcInternalError());
+  
+  CompressedSparsityPattern csp (dof_handler.n_dofs(),
+                                 dof_handler.n_dofs());
+  DoFTools::make_flux_sparsity_pattern (dof_handler, csp);
+  
+  SparsityPattern sparsity_pattern;
+  sparsity_pattern.copy_from (csp);
+
+                                   // partition this connection graph and get
+                                   // back a vector of indices, one per degree
+                                   // of freedom (which is associated with a
+                                   // cell)
+  std::vector<unsigned int> partition_indices (triangulation.n_active_cells());
+  sparsity_pattern.partition (n_partitions,  partition_indices);
+
+                                   // finally loop over all cells and set the
+                                   // subdomain ids. for this, get the DoF
+                                   // index of each cell and extract the
+                                   // subdomain id from the vector obtained
+                                   // above
+  std::vector<unsigned int> dof_indices(1);
+  for (typename DoFHandler<dim>::active_cell_iterator
+         cell = dof_handler.begin_active();
+       cell != dof_handler.end(); ++cell)
+    {
+      cell->get_dof_indices(dof_indices);
+      Assert (dof_indices[0] < triangulation.n_active_cells(),
+              ExcInternalError());
+      Assert (partition_indices[dof_indices[0]] < n_partitions,
+              ExcInternalError());
+      
+      cell->set_subdomain_id (partition_indices[dof_indices[0]]);
+    }
+}
+
+
 
 #if deal_II_dimension != 1
 template
@@ -267,3 +350,8 @@ template
 MGDoFHandler<deal_II_dimension>::active_cell_iterator
 GridTools::find_active_cell_around_point (const MGDoFHandler<deal_II_dimension> &,
                                           const Point<deal_II_dimension> &p);
+
+template
+void
+GridTools::partition_triangulation (Triangulation<deal_II_dimension> &,
+                                    const unsigned int);
index ff279d1f6add3260be44ad85e9ae60c10dbba939..1b86652764393c9bf35005eec039a920775231cd 100644 (file)
@@ -27,6 +27,8 @@ makefiles.html: Makefile makefiles.1.html $D/common/Make.global_options makefile
        @echo '<li><code>USE_CONTRIB_PETSC=$(USE_CONTRIB_PETSC)</code>' >> $@
        @echo '<li><code>DEAL_II_PETSC_DIR=$(DEAL_II_PETSC_DIR)</code>' >> $@
        @echo '<li><code>DEAL_II_PETSC_ARCH=$(DEAL_II_PETSC_ARCH)</code>' >> $@
+       @echo '<li><code>USE_CONTRIB_METIS=$(USE_CONTRIB_METIS)</code>' >> $@
+       @echo '<li><code>DEAL_II_METIS_DIR=$(DEAL_II_METIS_DIR)</code>' >> $@
        @echo '<li><code>lib-path-base=$(lib-path-base)</code>' >> $@
        @echo '<li><code>lib-path-lac=$(lib-path-lac)</code>' >> $@
        @echo '<li><code>lib-path-deal2=$(lib-path-deal2)</code>' >> $@
@@ -45,6 +47,7 @@ makefiles.html: Makefile makefiles.1.html $D/common/Make.global_options makefile
        @echo '<li><code>lib-contrib-hsl=$(lib-contrib-hsl)</code>' >> $@
        @echo '<li><code>lib-contrib-petsc.g=$(lib-contrib-petsc.g)</code>' >> $@
        @echo '<li><code>lib-contrib-petsc.o=$(lib-contrib-petsc.o)</code>' >> $@
+       @echo '<li><code>lib-contrib-metis=$(lib-contrib-metis)</code>' >> $@
        @echo '<li><code>include-path-base=$(include-path-base)</code>' >> $@
        @echo '<li><code>include-path-lac=$(include-path-lac)</code>' >> $@
        @echo '<li><code>include-path-deal2=$(include-path-deal2)</code>' >> $@
@@ -52,6 +55,7 @@ makefiles.html: Makefile makefiles.1.html $D/common/Make.global_options makefile
        @echo '<li><code>include-path-contrib-petsc=$(include-path-contrib-petsc)</code>' >> $@
        @echo '<li><code>include-path-contrib-petsc-bmake=$(include-path-contrib-petsc-bmake)</code>' >> $@
        @echo '<li><code>include-path-contrib-petsc-mpi=$(include-path-contrib-petsc-mpi)</code>' >> $@
+       @echo '<li><code>include-path-contrib-metis=$(include-path-contrib-metis)</code>' >> $@
        @echo '<li><code>INCLUDE=$(INCLUDE)</code>' >> $@
        @echo '<li><code>CXXFLAGS.g=$(CXXFLAGS.g)</code>' >> $@
        @echo '<li><code>CXXFLAGS.o=$(CXXFLAGS.o)</code>' >> $@
index 1dcb6c2b715c3c62f3a49780baf30b85549f5375..149b4f983f68fe7c572fb02b7b7583582a000bb5 100644 (file)
            upon configuration of the deal.II library.
            </p>
       </dd>    
+
+
+      <dt> <code>USE_CONTRIB_METIS</code> </dt>
+      <dd> <p>
+           <code>yes</code> indicates whether the METIS library has been
+           detected upon configuration, and whether we shall interface with
+           it. <code>no</code> otherwise. (See the
+          <a href="../readme.html#external-libs" target="body">ReadMe</a>
+          file for more information on installation of METIS.)
+           </p>
+      </dd>    
+
+
+      <dt> <code>DEAL_II_METIS_DIR</code> </dt>
+      <dd> <p>
+           If <code>USE_CONTRIB_METIS</code> is <code>yes</code>, then this
+           variable has the path to the METIS library, as either given by the
+           <code>METIS_DIR</code> environment variable, or the
+           <code>--with-metis</code> switch on the command line upon 
+          configuration of the deal.II library.
+           </p>
+      </dd>
     </dl>
 
 
           file for more information on installation of PETSc.)
            </p>
       </dd>
+
+      <dt> <code>lib-contrib-metis</code> </dt>
+      <dd> <p>
+           Path and name of the METIS libraries, if
+           found and used at configuration time.
+          (See the
+          <a href="../readme.html#external-libs" target="body">ReadMe</a>
+          file for more information on installation of METIS.)
+           </p>
+      </dd>
     </dl>
 
 
       </dd>
 
 
+      <dt> <code>include-path-deal2</code> </dt>
+      <dd> <p>
+           Same for the /deal.II library. Include files are in
+           <code>$(include-path-deal2)/*</code>.
+          </p>
+      </dd>
+
+
       <dt> <code>include-path-contrib-hsl</code> </dt>
       <dd> <p>
            If some HSL files are
       </dd>
 
 
-      <dt> <code>include-path-deal2</code> </dt>
+      <dt> <code>include-path-contrib-metis
+           </code> </dt>
       <dd> <p>
-           Same for the /deal.II library. Include files are in
-           <code>$(include-path-deal2)/*</code>.
-          </p>
+           If METIS is used, then this variable has the path to the METIS
+           include files. (See the
+          <a href="../readme.html#external-libs" target="body">ReadMe</a>
+          file for more information on installation of METIS.)
+           </p>
       </dd>
 
 
index b8ad6e0755b0b867694196964d9181d450b4a51b..a92886edf3153992ca8f6e327b61d0b97dda0a34 100644 (file)
@@ -731,6 +731,65 @@ class SparsityPattern : public Subscriptor
                                      */
     bool optimize_diagonal () const;
     
+                                     /**
+                                      * Use the METIS partitioner to generate
+                                      * a partitioning of the degrees of
+                                      * freedom represented by this sparsity
+                                      * pattern. In effect, we view this
+                                      * sparsity pattern as a graph of
+                                      * connections between various degrees of
+                                      * freedom, where each nonzero entry in
+                                      * the sparsity pattern corresponds to an
+                                      * edge between two nodes in the
+                                      * connection graph. The goal is then to
+                                      * decompose this graph into groups of
+                                      * nodes so that a minimal number of
+                                      * edges are cut by the boundaries
+                                      * between node groups. This partitioning
+                                      * is done by METIS. Note that METIS can
+                                      * only partition symmetric sparsity
+                                      * patterns, and that of course the
+                                      * sparsity pattern has to be square. We
+                                      * do not check for symmetry of the
+                                      * sparsity pattern, since this is an
+                                      * expensive operation, but rather leave
+                                      * this as the responsibility of caller
+                                      * of this function.
+                                      *
+                                      * After calling this function, the
+                                      * output array will have values between
+                                      * zero and @p{n_partitions-1} for each
+                                      * node (i.e. row or column of the
+                                      * matrix).
+                                      *
+                                      * This function will generate an error
+                                      * if METIS is not installed unless
+                                      * @p{n_partitions} is one. I.e., you can
+                                      * write a program so that it runs in the
+                                      * single-processor single-partition case
+                                      * without METIS installed, and only
+                                      * requires METIS when multiple
+                                      * partitions are required.
+                                      *
+                                      * Note that the sparsity pattern itself
+                                      * is not changed by calling this
+                                      * function. However, you will likely use
+                                      * the information generated by calling
+                                      * this function to renumber degrees of
+                                      * freedom, after which you will of
+                                      * course have to regenerate the sparsity
+                                      * pattern.
+                                      *
+                                      * This function will rarely be called
+                                      * separately, since in finite element
+                                      * methods you will want to partition the
+                                      * mesh, not the matrix. This can be done
+                                      * by calling
+                                      * @p{GridTools::partition_triangulation}.
+                                      */
+    void partition (const unsigned int         n_partitions,
+                    std::vector<unsigned int> &partition_indices) const;
+    
                                     /**
                                      * Write the data of this object
                                      * en bloc to a file. This is
@@ -928,7 +987,24 @@ class SparsityPattern : public Subscriptor
                    int, int,
                    << "The iterators denote a range of " << arg1
                    << " elements, but the given number of rows was " << arg2);
-    
+                                     /**
+                                      * Exception
+                                      */
+    DeclException0 (ExcMETISNotInstalled);
+                                     /**
+                                      * Exception
+                                      */
+    DeclException1 (ExcInvalidNumberOfPartitions,
+                    int,
+                    << "The number of partitions you gave is " << arg1
+                    << ", but must be greater than zero.");
+                                     /**
+                                      * Exception
+                                      */
+    DeclException2 (ExcInvalidArraySize,
+                    int, int,
+                    << "The array has size " << arg1 << " but should have size "
+                    << arg2);
   private:
                                     /**
                                      * Maximum number of rows that can
index 74de399834d36656b6282ef5d613c1fb2c948054..537617041e286b1bad6cb11d788f50716c47a756 100644 (file)
 #include <numeric>
 #include <functional>
 
+#ifdef DEAL_II_USE_METIS
+extern "C" {
+#  include <metis.h>
+}
+#endif
 
 const unsigned int SparsityPattern::invalid_entry;
 
@@ -899,6 +904,81 @@ SparsityPattern::memory_consumption () const
 
 
 
+void
+SparsityPattern::
+partition (const unsigned int         n_partitions,
+           std::vector<unsigned int> &partition_indices) const
+{
+  Assert (rows==cols, ExcNotQuadratic());
+  Assert (is_compressed(), ExcNotCompressed());
+
+  Assert (n_partitions > 0, ExcInvalidNumberOfPartitions(n_partitions));
+  Assert (partition_indices.size() == rows,
+          ExcInvalidArraySize (partition_indices.size(),rows));
+
+                                   // check for an easy return
+  if (n_partitions == 1)
+    {
+      std::fill_n (partition_indices.begin(), partition_indices.size(), 0U);
+      return;
+    }
+
+                                   // Make sure that METIS is actually
+                                   // installed and detected
+#ifndef DEAL_II_USE_METIS
+  AssertThrow (false, ExcMETISNotInstalled());
+#else
+
+                                   // generate the data structures for
+                                   // METIS. Note that this is particularly
+                                   // simple, since METIS wants exactly our
+                                   // compressed row storage format. we only
+                                   // have to set up a few auxiliary arrays
+  int
+    n = static_cast<signed int>(rows),
+    wgtflag = 0,                          // no weights on nodes or edges
+    numflag = 0,                          // C-style 0-based numbering
+    nparts  = static_cast<int>(n_partitions), // number of subdomains to create
+    dummy;                                // the numbers of edges cut by the
+                                          //   resulting partition
+
+                                   // use default options for METIS
+  int options[5] = { 0,0,0,0,0 };
+
+                                   // one more nuisance: we have to copy our
+                                   // own data to arrays that store signed
+                                   // integers :-(
+  std::vector<idxtype> int_rowstart (rowstart, rowstart+cols+1);
+  std::vector<idxtype> int_colnums (colnums, colnums+max_vec_len+1);
+
+  std::vector<idxtype> int_partition_indices (rows);
+
+                                   // Select which type of partitioning to create
+
+                                   // Use recursive if the number of
+                                   // partitions is less than or equal to 8
+  if (n_partitions <= 8)
+    METIS_PartGraphRecursive(&n, &int_rowstart[0], &int_colnums[0],
+                             NULL, NULL,
+                             &wgtflag, &numflag, &nparts, &options[0],
+                             &dummy, &int_partition_indices[0]);
+  
+                                   // Otherwise  use kway
+  else
+    METIS_PartGraphKway(&n, &int_rowstart[0], &int_colnums[0],
+                        NULL, NULL,
+                        &wgtflag, &numflag, &nparts, &options[0],
+                        &dummy, &int_partition_indices[0]);
+
+                                   // now copy back generated indices into the
+                                   // output array
+  std::copy (int_partition_indices.begin(),
+             int_partition_indices.end(),
+             partition_indices.begin());
+#endif
+}
+
+
 // explicit instantiations
 template void SparsityPattern::copy_from<float> (const FullMatrix<float> &, bool);
 template void SparsityPattern::copy_from<double> (const FullMatrix<double> &, bool);
diff --git a/tests/bits/metis_01.cc b/tests/bits/metis_01.cc
new file mode 100644 (file)
index 0000000..c2ab67e
--- /dev/null
@@ -0,0 +1,92 @@
+//----------------------------  metis_01.cc  ---------------------------
+//    $Id$
+//    Version: $Name$ 
+//
+//    Copyright (C) 2004 by the deal.II authors
+//
+//    This file is subject to QPL and may not be  distributed
+//    without copyright and license information. Please refer
+//    to the file deal.II/doc/license.html for the  text  and
+//    further information on this license.
+//
+//----------------------------  metis_01.cc  ---------------------------
+
+
+// check GridTools::partition_triangulation
+
+#include "../tests.h"
+#include <grid/tria.h>
+#include <grid/tria_accessor.h>
+#include <grid/tria_iterator.h>
+#include <grid/grid_tools.h>
+#include <grid/grid_generator.h>
+#include <fstream>
+#include <iostream>
+
+
+template <int dim>
+void test ()
+{
+  Triangulation<dim> triangulation;
+  GridGenerator::hyper_cube (triangulation);
+  triangulation.refine_global (5-dim);
+
+                                   // subdivide into 5 subdomains
+  deallog << "RECURSIVE" << std::endl;
+  GridTools::partition_triangulation (triangulation, 5);
+  for (typename Triangulation<dim>::active_cell_iterator
+         cell = triangulation.begin_active();
+       cell != triangulation.end(); ++cell)
+    deallog << cell << ' ' << cell->subdomain_id() << std::endl;
+
+                                   // subdivide into 9 subdomains. note that
+                                   // this uses the k-way subdivision (for
+                                   // more than 8 subdomains) rather than the
+                                   // recursive one
+  deallog << "K-WAY" << std::endl;
+  GridTools::partition_triangulation (triangulation, 9);
+  for (typename Triangulation<dim>::active_cell_iterator
+         cell = triangulation.begin_active();
+       cell != triangulation.end(); ++cell)
+    deallog << cell << ' ' << cell->subdomain_id() << std::endl;
+}
+
+
+
+int main ()
+{
+  std::ofstream logfile("metis_01.output");
+  deallog.attach(logfile);
+  deallog.depth_console(0);
+
+  try
+    {
+      test<1> ();
+      test<2> ();
+      test<3> ();
+    }
+  catch (std::exception &exc)
+    {
+      std::cerr << std::endl << std::endl
+               << "----------------------------------------------------"
+               << std::endl;
+      std::cerr << "Exception on processing: " << std::endl
+               << exc.what() << std::endl
+               << "Aborting!" << std::endl
+               << "----------------------------------------------------"
+               << std::endl;
+      
+      return 1;
+    }
+  catch (...) 
+    {
+      std::cerr << std::endl << std::endl
+               << "----------------------------------------------------"
+               << std::endl;
+      std::cerr << "Unknown exception!" << std::endl
+               << "Aborting!" << std::endl
+               << "----------------------------------------------------"
+               << std::endl;
+      return 1;
+    };
+}

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.