]> https://gitweb.dealii.org/ - dealii.git/commitdiff
add Triangulation::ghost_owners() and level_ghost_owners() 1679/head
authorTimo Heister <timo.heister@gmail.com>
Sun, 27 Sep 2015 17:41:37 +0000 (13:41 -0400)
committerTimo Heister <timo.heister@gmail.com>
Sun, 4 Oct 2015 14:32:03 +0000 (10:32 -0400)
doc/news/changes.h
include/deal.II/distributed/tria.h
include/deal.II/distributed/tria_base.h
source/distributed/tria.cc
source/distributed/tria_base.cc
tests/mpi/tria_ghost_owners_01.cc [new file with mode: 0644]
tests/mpi/tria_ghost_owners_01.mpirun=7.output [new file with mode: 0644]
tests/mpi/tria_ghost_owners_02.cc [new file with mode: 0644]
tests/mpi/tria_ghost_owners_02.mpirun=11.output [new file with mode: 0644]
tests/mpi/tria_ghost_owners_02.mpirun=5.output [new file with mode: 0644]

index 3ad05671c42d54bc6a91944e285963bee6d4b844..507e29eb7bd2b2ff9886839c7fdb83cbfb83117d 100644 (file)
@@ -159,6 +159,12 @@ inconvenience this causes.
 <a name="general"></a>
 <h3>General</h3>
 <ol>
+  <li> New: Triangulation::ghost_owners() returns the set of MPI ranks of the
+  ghost cells. Similarly ::level_ghost_owners() for level ghosts.
+  <br>
+  (Timo Heister, 2015/09/30)
+  </li>
+
   <li> New: FunctionParser now supports pow(a,b).
   <br>
   (Timo Heister, 2015/09/30)
index 00c22c20c61a25a2f01265b55bc9aa587625d5cb..7638ab9adeec1fcb94bc74bc0db20d1f25b1e8a1 100644 (file)
@@ -822,6 +822,13 @@ namespace parallel
 
     private:
 
+      /**
+       * Override the function to update the number cache so we can fill
+       * data like @p level_ghost_owners.
+       *
+       */
+      virtual void update_number_cache ();
+
       /**
        * store the Settings.
        */
index 5e0cfbf4e0945352c76866e5b561ca7ef4c717e7..5217c2a5cd36c974087191935344b6a6fbe931a7 100644 (file)
@@ -132,6 +132,26 @@ namespace parallel
      */
     types::subdomain_id locally_owned_subdomain () const;
 
+    /**
+     * Returns a set of MPI ranks of the processors that have at least one
+     * ghost cell adjacent to the cells of the local processor. In other
+     * words, this is the set of subdomain_id() for all ghost cells.
+     *
+     * @note: If @p i is contained in the list of processor @p j, then @p j
+     * will also be contained in the list of processor @p i.
+     **/
+    const std::set<unsigned int> &ghost_owners () const;
+
+    /**
+     * Returns a set of MPI ranks of the processors that have at least one
+     * level ghost cell adjacent to our cells used in geometric multigrid. In
+     * other words, this is the set of level_subdomain_id() for all level
+     * ghost cells.
+     *
+     * @note: If @p i is contained in the list of processor @p j, then @p j
+     * will also be contained in the list of processor @p i.
+     **/
+    const std::set<unsigned int> &level_ghost_owners () const;
 
   protected:
     /**
@@ -142,24 +162,48 @@ namespace parallel
     MPI_Comm mpi_communicator;
 
     /**
-     * The subdomain id to be used for the current processor.
+     * The subdomain id to be used for the current processor. This is the MPI
+     * rank.
      */
     types::subdomain_id my_subdomain;
 
     /**
-     * total number of subdomains.
+     * The total number of subdomains (or the size of the MPI communicator).
      */
     types::subdomain_id n_subdomains;
 
     /**
-     * A structure that contains some numbers about the distributed
+     * A structure that contains information about the distributed
      * triangulation.
      */
     struct NumberCache
     {
+      /**
+       *  This vector stores the number of locally owned active cells per MPI
+       *  rank.
+       */
       std::vector<unsigned int> n_locally_owned_active_cells;
+      /**
+       * The total number of active cells (sum of
+       * @p n_locally_owned_active_cells).
+       */
       types::global_dof_index   n_global_active_cells;
+      /**
+       * The global number of levels computed as the maximum number of levels
+       * taken over all MPI ranks, so <tt>n_levels()<=n_global_levels =
+       * max(n_levels() on proc i)</tt>.
+       */
       unsigned int              n_global_levels;
+      /**
+       * A set containing the subdomain_id (MPI rank) of the owners of the
+       * ghost cells on this processor.
+       */
+      std::set<unsigned int> ghost_owners;
+      /**
+       * A set containing the MPI ranks of the owners of the level ghost cells
+       * on this processor (for all levels).
+       */
+      std::set<unsigned int> level_ghost_owners;
 
       NumberCache();
     };
@@ -169,7 +213,7 @@ namespace parallel
     /**
      * Update the number_cache variable after mesh creation or refinement.
      */
-    void update_number_cache ();
+    virtual void update_number_cache ();
 
 
   };
index a4765c4ea025521064183b62f1ae290a645cc3b0..09a7961a93d4a5d8eed92eba90f2710207e2649d 100644 (file)
@@ -2791,6 +2791,31 @@ namespace parallel
       return dealii::internal::p4est::functions<dim>::checksum (parallel_forest);
     }
 
+    template <int dim, int spacedim>
+    void
+    Triangulation<dim,spacedim>::
+    update_number_cache ()
+    {
+      parallel::Triangulation<dim,spacedim>::update_number_cache();
+
+      if (this->n_levels() == 0)
+        return;
+
+      if (settings & construct_multigrid_hierarchy)
+        {
+          // find level ghost owners
+          for (typename Triangulation<dim,spacedim>::cell_iterator
+               cell = this->begin();
+               cell != this->end();
+               ++cell)
+            if (cell->level_subdomain_id() != numbers::artificial_subdomain_id
+                && cell->level_subdomain_id() != this->locally_owned_subdomain())
+              this->number_cache.level_ghost_owners.insert(cell->level_subdomain_id());
+
+          Assert(this->number_cache.level_ghost_owners.size() < Utilities::MPI::n_mpi_processes(this->mpi_communicator), ExcInternalError());
+        }
+    }
+
 
     template <int dim, int spacedim>
     typename dealii::internal::p4est::types<dim>::tree *
index ff948468ebcb8bafeb8fac0d85a782c42d476568..e898831469dc057985aa8a95bb45ac4b3b97c3e6 100644 (file)
@@ -151,6 +151,9 @@ namespace parallel
                number_cache.n_locally_owned_active_cells.end(),
                0);
 
+    number_cache.ghost_owners.clear ();
+    number_cache.level_ghost_owners.clear ();
+
     if (this->n_levels() == 0)
       {
         // Skip communication done below if we do not have any cells
@@ -163,6 +166,19 @@ namespace parallel
         return;
       }
 
+
+    {
+      // find ghost owners
+      for (typename Triangulation<dim,spacedim>::active_cell_iterator
+           cell = this->begin_active();
+           cell != this->end();
+           ++cell)
+        if (cell->is_ghost())
+          number_cache.ghost_owners.insert(cell->subdomain_id());
+
+      Assert(number_cache.ghost_owners.size() < Utilities::MPI::n_mpi_processes(mpi_communicator), ExcInternalError());
+    }
+
     if (this->n_levels() > 0)
       for (typename Triangulation<dim,spacedim>::active_cell_iterator
            cell = this->begin_active();
@@ -205,8 +221,25 @@ namespace parallel
     return my_subdomain;
   }
 
+  template <int dim, int spacedim>
+  const std::set<unsigned int> &
+  Triangulation<dim,spacedim>::
+  ghost_owners () const
+  {
+    return number_cache.ghost_owners;
+  }
+
+  template <int dim, int spacedim>
+  const std::set<unsigned int> &
+  Triangulation<dim,spacedim>::
+  level_ghost_owners () const
+  {
+    return number_cache.level_ghost_owners;
+  }
+
+} // end namespace parallel
+
 
-}
 
 
 /*-------------- Explicit Instantiations -------------------------------*/
diff --git a/tests/mpi/tria_ghost_owners_01.cc b/tests/mpi/tria_ghost_owners_01.cc
new file mode 100644 (file)
index 0000000..c75ba10
--- /dev/null
@@ -0,0 +1,145 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2009 - 2015 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, 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 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+
+// test Tria::(level_)ghost_owners()
+
+#include "../tests.h"
+
+
+#include <deal.II/base/logstream.h>
+#include <deal.II/base/tensor.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/lac/vector.h>
+#include <deal.II/distributed/tria.h>
+#include <deal.II/distributed/grid_refinement.h>
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_out.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/base/utilities.h>
+
+
+#include <fstream>
+
+
+// make sure if i is in s on proc j, j is in s on proc i
+void mpi_check(const std::set<unsigned int> &s)
+{
+  MPI_Barrier(MPI_COMM_WORLD);
+  unsigned int tag = 1234;
+  for (std::set<unsigned int>::iterator it = s.begin();
+       it != s.end(); ++it)
+    MPI_Send(NULL, 0, MPI_INT, *it, tag, MPI_COMM_WORLD);
+
+  for (unsigned int i=0; i<s.size(); ++i)
+    {
+      MPI_Status status;
+      MPI_Recv(NULL, 0, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status);
+      if ((s.end() == s.find(status.MPI_SOURCE)))
+        deallog << status.MPI_SOURCE <<  " NOTOKAY" << std::endl;
+      Assert(s.end() != s.find(status.MPI_SOURCE), ExcInternalError());
+    }
+  MPI_Barrier(MPI_COMM_WORLD);
+}
+
+
+template <int dim>
+void test()
+{
+  unsigned int myid = Utilities::MPI::this_mpi_process (MPI_COMM_WORLD);
+
+  parallel::distributed::Triangulation<dim> tr(MPI_COMM_WORLD, Triangulation<dim>::
+                                               limit_level_difference_at_vertices,
+                                               parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+
+  std::vector<unsigned int> sub(dim, 1);
+  sub[0] = 5;
+  Point<dim> p;
+  p[0]=5;
+  for (unsigned int i=1; i<dim; ++i)
+    p[i] = 1;
+  GridGenerator::subdivided_hyper_rectangle(tr,
+                                            sub,
+                                            Point<dim>(),
+                                            p);
+  tr.refine_global (2);
+
+
+  for (unsigned int ref=0; ref<=3; ++ref)
+    {
+      deallog << "* cycle " << ref << std::endl;
+
+      deallog << "ghost owners: ";
+      std::set<unsigned int> ghost_owners = tr.ghost_owners();
+      for (std::set<unsigned int>::iterator it = ghost_owners.begin(); it!=ghost_owners.end(); ++it)
+        deallog << *it << " ";
+      deallog << std::endl;
+
+      mpi_check(ghost_owners);
+
+      deallog << "level ghost owners: ";
+      std::set<unsigned int> level_ghost_owners = tr.level_ghost_owners();
+      for (std::set<unsigned int>::iterator it = level_ghost_owners.begin(); it!=level_ghost_owners.end(); ++it)
+        deallog << *it << " ";
+      deallog << std::endl;
+
+      mpi_check(level_ghost_owners);
+
+      // owners need to be a subset of level owners:
+      bool is_subset = std::includes(level_ghost_owners.begin(), level_ghost_owners.end(), ghost_owners.begin(), ghost_owners.end());
+      Assert(is_subset, ExcInternalError());
+
+      Vector<float> indicators (tr.dealii::Triangulation<dim>::n_active_cells());
+      std::set<unsigned int> neighbors;
+      {
+        for (typename Triangulation<dim>::active_cell_iterator
+             cell = tr.begin_active(); cell != tr.end(); ++cell)
+          if (!cell->is_artificial())
+            {
+              if (cell->is_ghost())
+                neighbors.insert(cell->subdomain_id());
+              indicators[cell->index()] = cell->index();
+            }
+      }
+
+      Assert(neighbors == ghost_owners, ExcInternalError());
+
+      parallel::distributed::GridRefinement
+      ::refine_and_coarsen_fixed_number (tr, indicators,
+                                         0.3, 0.0);
+      tr.execute_coarsening_and_refinement ();
+      if (myid == 0)
+        deallog << "total active cells = "
+                << tr.n_global_active_cells() << std::endl;
+    }
+
+  deallog << "OK" << std::endl;
+}
+
+
+int main(int argc, char *argv[])
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, 1);
+
+  MPILogInitAll all;
+  deallog.push("2d");
+  test<2>();
+  deallog.pop();
+  deallog.push("3d");
+  test<3>();
+  deallog.pop();
+}
diff --git a/tests/mpi/tria_ghost_owners_01.mpirun=7.output b/tests/mpi/tria_ghost_owners_01.mpirun=7.output
new file mode 100644 (file)
index 0000000..30c981b
--- /dev/null
@@ -0,0 +1,203 @@
+
+DEAL:0:2d::* cycle 0
+DEAL:0:2d::ghost owners: 1 2 
+DEAL:0:2d::level ghost owners: 1 2 
+DEAL:0:2d::total active cells = 149
+DEAL:0:2d::* cycle 1
+DEAL:0:2d::ghost owners: 1 2 
+DEAL:0:2d::level ghost owners: 1 2 
+DEAL:0:2d::total active cells = 227
+DEAL:0:2d::* cycle 2
+DEAL:0:2d::ghost owners: 1 2 
+DEAL:0:2d::level ghost owners: 1 2 
+DEAL:0:2d::total active cells = 467
+DEAL:0:2d::* cycle 3
+DEAL:0:2d::ghost owners: 1 2 
+DEAL:0:2d::level ghost owners: 1 2 
+DEAL:0:2d::total active cells = 728
+DEAL:0:2d::OK
+DEAL:0:3d::* cycle 0
+DEAL:0:3d::ghost owners: 1 2 
+DEAL:0:3d::level ghost owners: 1 2 
+DEAL:0:3d::total active cells = 1020
+DEAL:0:3d::* cycle 1
+DEAL:0:3d::ghost owners: 1 2 
+DEAL:0:3d::level ghost owners: 1 2 
+DEAL:0:3d::total active cells = 3785
+DEAL:0:3d::* cycle 2
+DEAL:0:3d::ghost owners: 1 2 
+DEAL:0:3d::level ghost owners: 1 2 
+DEAL:0:3d::total active cells = 11702
+DEAL:0:3d::* cycle 3
+DEAL:0:3d::ghost owners: 1 2 
+DEAL:0:3d::level ghost owners: 1 2 
+DEAL:0:3d::total active cells = 37868
+DEAL:0:3d::OK
+
+DEAL:1:2d::* cycle 0
+DEAL:1:2d::ghost owners: 0 2 3 
+DEAL:1:2d::level ghost owners: 0 2 3 
+DEAL:1:2d::* cycle 1
+DEAL:1:2d::ghost owners: 0 2 3 
+DEAL:1:2d::level ghost owners: 0 2 3 
+DEAL:1:2d::* cycle 2
+DEAL:1:2d::ghost owners: 0 2 
+DEAL:1:2d::level ghost owners: 0 2 3 
+DEAL:1:2d::* cycle 3
+DEAL:1:2d::ghost owners: 0 2 
+DEAL:1:2d::level ghost owners: 0 2 3 
+DEAL:1:2d::OK
+DEAL:1:3d::* cycle 0
+DEAL:1:3d::ghost owners: 0 2 3 
+DEAL:1:3d::level ghost owners: 0 2 3 
+DEAL:1:3d::* cycle 1
+DEAL:1:3d::ghost owners: 0 2 3 
+DEAL:1:3d::level ghost owners: 0 2 3 
+DEAL:1:3d::* cycle 2
+DEAL:1:3d::ghost owners: 0 2 3 4 
+DEAL:1:3d::level ghost owners: 0 2 3 4 
+DEAL:1:3d::* cycle 3
+DEAL:1:3d::ghost owners: 0 2 3 4 5 
+DEAL:1:3d::level ghost owners: 0 2 3 4 5 
+DEAL:1:3d::OK
+
+
+DEAL:2:2d::* cycle 0
+DEAL:2:2d::ghost owners: 0 1 3 4 
+DEAL:2:2d::level ghost owners: 0 1 3 4 
+DEAL:2:2d::* cycle 1
+DEAL:2:2d::ghost owners: 0 1 3 
+DEAL:2:2d::level ghost owners: 0 1 3 4 
+DEAL:2:2d::* cycle 2
+DEAL:2:2d::ghost owners: 0 1 3 4 
+DEAL:2:2d::level ghost owners: 0 1 3 4 
+DEAL:2:2d::* cycle 3
+DEAL:2:2d::ghost owners: 0 1 3 
+DEAL:2:2d::level ghost owners: 0 1 3 4 5 
+DEAL:2:2d::OK
+DEAL:2:3d::* cycle 0
+DEAL:2:3d::ghost owners: 0 1 3 4 
+DEAL:2:3d::level ghost owners: 0 1 3 4 
+DEAL:2:3d::* cycle 1
+DEAL:2:3d::ghost owners: 0 1 3 4 
+DEAL:2:3d::level ghost owners: 0 1 3 4 
+DEAL:2:3d::* cycle 2
+DEAL:2:3d::ghost owners: 0 1 3 4 5 6 
+DEAL:2:3d::level ghost owners: 0 1 3 4 5 6 
+DEAL:2:3d::* cycle 3
+DEAL:2:3d::ghost owners: 0 1 3 4 5 
+DEAL:2:3d::level ghost owners: 0 1 3 4 5 6 
+DEAL:2:3d::OK
+
+
+DEAL:3:2d::* cycle 0
+DEAL:3:2d::ghost owners: 1 2 4 5 
+DEAL:3:2d::level ghost owners: 1 2 4 5 
+DEAL:3:2d::* cycle 1
+DEAL:3:2d::ghost owners: 1 2 4 5 
+DEAL:3:2d::level ghost owners: 1 2 4 5 
+DEAL:3:2d::* cycle 2
+DEAL:3:2d::ghost owners: 2 4 5 
+DEAL:3:2d::level ghost owners: 1 2 4 5 
+DEAL:3:2d::* cycle 3
+DEAL:3:2d::ghost owners: 2 4 5 
+DEAL:3:2d::level ghost owners: 1 2 4 5 
+DEAL:3:2d::OK
+DEAL:3:3d::* cycle 0
+DEAL:3:3d::ghost owners: 1 2 4 5 
+DEAL:3:3d::level ghost owners: 1 2 4 5 
+DEAL:3:3d::* cycle 1
+DEAL:3:3d::ghost owners: 1 2 4 5 6 
+DEAL:3:3d::level ghost owners: 1 2 4 5 6 
+DEAL:3:3d::* cycle 2
+DEAL:3:3d::ghost owners: 1 2 4 5 6 
+DEAL:3:3d::level ghost owners: 1 2 4 5 6 
+DEAL:3:3d::* cycle 3
+DEAL:3:3d::ghost owners: 1 2 4 5 6 
+DEAL:3:3d::level ghost owners: 1 2 4 5 6 
+DEAL:3:3d::OK
+
+
+DEAL:4:2d::* cycle 0
+DEAL:4:2d::ghost owners: 2 3 5 6 
+DEAL:4:2d::level ghost owners: 2 3 5 6 
+DEAL:4:2d::* cycle 1
+DEAL:4:2d::ghost owners: 3 5 6 
+DEAL:4:2d::level ghost owners: 2 3 5 6 
+DEAL:4:2d::* cycle 2
+DEAL:4:2d::ghost owners: 2 3 5 
+DEAL:4:2d::level ghost owners: 2 3 5 6 
+DEAL:4:2d::* cycle 3
+DEAL:4:2d::ghost owners: 3 5 6 
+DEAL:4:2d::level ghost owners: 2 3 5 6 
+DEAL:4:2d::OK
+DEAL:4:3d::* cycle 0
+DEAL:4:3d::ghost owners: 2 3 5 6 
+DEAL:4:3d::level ghost owners: 2 3 5 6 
+DEAL:4:3d::* cycle 1
+DEAL:4:3d::ghost owners: 2 3 5 6 
+DEAL:4:3d::level ghost owners: 2 3 5 6 
+DEAL:4:3d::* cycle 2
+DEAL:4:3d::ghost owners: 1 2 3 5 6 
+DEAL:4:3d::level ghost owners: 1 2 3 5 6 
+DEAL:4:3d::* cycle 3
+DEAL:4:3d::ghost owners: 1 2 3 5 6 
+DEAL:4:3d::level ghost owners: 1 2 3 5 6 
+DEAL:4:3d::OK
+
+
+DEAL:5:2d::* cycle 0
+DEAL:5:2d::ghost owners: 3 4 6 
+DEAL:5:2d::level ghost owners: 3 4 6 
+DEAL:5:2d::* cycle 1
+DEAL:5:2d::ghost owners: 3 4 6 
+DEAL:5:2d::level ghost owners: 3 4 6 
+DEAL:5:2d::* cycle 2
+DEAL:5:2d::ghost owners: 3 4 6 
+DEAL:5:2d::level ghost owners: 3 4 6 
+DEAL:5:2d::* cycle 3
+DEAL:5:2d::ghost owners: 3 4 6 
+DEAL:5:2d::level ghost owners: 2 3 4 6 
+DEAL:5:2d::OK
+DEAL:5:3d::* cycle 0
+DEAL:5:3d::ghost owners: 3 4 6 
+DEAL:5:3d::level ghost owners: 3 4 6 
+DEAL:5:3d::* cycle 1
+DEAL:5:3d::ghost owners: 3 4 6 
+DEAL:5:3d::level ghost owners: 3 4 6 
+DEAL:5:3d::* cycle 2
+DEAL:5:3d::ghost owners: 2 3 4 6 
+DEAL:5:3d::level ghost owners: 2 3 4 6 
+DEAL:5:3d::* cycle 3
+DEAL:5:3d::ghost owners: 1 2 3 4 6 
+DEAL:5:3d::level ghost owners: 1 2 3 4 6 
+DEAL:5:3d::OK
+
+
+DEAL:6:2d::* cycle 0
+DEAL:6:2d::ghost owners: 4 5 
+DEAL:6:2d::level ghost owners: 4 5 
+DEAL:6:2d::* cycle 1
+DEAL:6:2d::ghost owners: 4 5 
+DEAL:6:2d::level ghost owners: 4 5 
+DEAL:6:2d::* cycle 2
+DEAL:6:2d::ghost owners: 5 
+DEAL:6:2d::level ghost owners: 4 5 
+DEAL:6:2d::* cycle 3
+DEAL:6:2d::ghost owners: 4 5 
+DEAL:6:2d::level ghost owners: 4 5 
+DEAL:6:2d::OK
+DEAL:6:3d::* cycle 0
+DEAL:6:3d::ghost owners: 4 5 
+DEAL:6:3d::level ghost owners: 4 5 
+DEAL:6:3d::* cycle 1
+DEAL:6:3d::ghost owners: 3 4 5 
+DEAL:6:3d::level ghost owners: 3 4 5 
+DEAL:6:3d::* cycle 2
+DEAL:6:3d::ghost owners: 2 3 4 5 
+DEAL:6:3d::level ghost owners: 2 3 4 5 
+DEAL:6:3d::* cycle 3
+DEAL:6:3d::ghost owners: 3 4 5 
+DEAL:6:3d::level ghost owners: 2 3 4 5 
+DEAL:6:3d::OK
+
diff --git a/tests/mpi/tria_ghost_owners_02.cc b/tests/mpi/tria_ghost_owners_02.cc
new file mode 100644 (file)
index 0000000..1a85498
--- /dev/null
@@ -0,0 +1,138 @@
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2009 - 2015 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, 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 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+
+// test Tria::ghost_owners() like tria_ghost_owners_01 but with one coarse
+// cell
+
+#include "../tests.h"
+
+
+#include <deal.II/base/logstream.h>
+#include <deal.II/base/tensor.h>
+#include <deal.II/grid/tria.h>
+#include <deal.II/lac/vector.h>
+#include <deal.II/distributed/tria.h>
+#include <deal.II/distributed/grid_refinement.h>
+#include <deal.II/grid/tria_accessor.h>
+#include <deal.II/grid/grid_generator.h>
+#include <deal.II/grid/grid_out.h>
+#include <deal.II/grid/grid_tools.h>
+#include <deal.II/base/utilities.h>
+
+
+#include <fstream>
+
+
+
+
+// make sure if i is in s on proc j, j is in s on proc i
+void mpi_check(const std::set<unsigned int> &s)
+{
+  MPI_Barrier(MPI_COMM_WORLD);
+  unsigned int tag = 1234;
+  for (std::set<unsigned int>::iterator it = s.begin();
+       it != s.end(); ++it)
+    MPI_Send(NULL, 0, MPI_INT, *it, tag, MPI_COMM_WORLD);
+
+  for (unsigned int i=0; i<s.size(); ++i)
+    {
+      MPI_Status status;
+      MPI_Recv(NULL, 0, MPI_INT, MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status);
+      if ((s.end() == s.find(status.MPI_SOURCE)))
+        deallog << status.MPI_SOURCE <<  " NOTOKAY" << std::endl;
+      Assert(s.end() != s.find(status.MPI_SOURCE), ExcInternalError());
+    }
+  MPI_Barrier(MPI_COMM_WORLD);
+}
+
+template <int dim>
+void test()
+{
+  unsigned int myid = Utilities::MPI::this_mpi_process (MPI_COMM_WORLD);
+
+  parallel::distributed::Triangulation<dim> tr(MPI_COMM_WORLD, Triangulation<dim>::
+                                               limit_level_difference_at_vertices,
+                                               parallel::distributed::Triangulation<dim>::construct_multigrid_hierarchy);
+
+  GridGenerator::hyper_cube(tr);
+  tr.refine_global (5-dim);
+
+
+  for (unsigned int ref=0; ref<=3; ++ref)
+    {
+      deallog << "* cycle " << ref << std::endl;
+
+      deallog << "ghost owners: ";
+      std::set<unsigned int> ghost_owners = tr.ghost_owners();
+      for (std::set<unsigned int>::iterator it = ghost_owners.begin(); it!=ghost_owners.end(); ++it)
+        deallog << *it << " ";
+      deallog << std::endl;
+
+      mpi_check(ghost_owners);
+
+      deallog << "level ghost owners: ";
+      std::set<unsigned int> level_ghost_owners = tr.level_ghost_owners();
+      for (std::set<unsigned int>::iterator it = level_ghost_owners.begin(); it!=level_ghost_owners.end(); ++it)
+        deallog << *it << " ";
+      deallog << std::endl;
+
+      mpi_check(level_ghost_owners);
+
+      // owners need to be a subset of level owners:
+      bool is_subset = std::includes(level_ghost_owners.begin(), level_ghost_owners.end(), ghost_owners.begin(), ghost_owners.end());
+      Assert(is_subset, ExcInternalError());
+
+      Vector<float> indicators (tr.dealii::Triangulation<dim>::n_active_cells());
+      std::set<unsigned int> neighbors;
+      {
+        for (typename Triangulation<dim>::active_cell_iterator
+             cell = tr.begin_active(); cell != tr.end(); ++cell)
+          if (!cell->is_artificial())
+            {
+              if (cell->is_ghost())
+                neighbors.insert(cell->subdomain_id());
+              indicators[cell->index()] = cell->index();
+            }
+      }
+
+      Assert(neighbors == ghost_owners, ExcInternalError());
+
+      parallel::distributed::GridRefinement
+      ::refine_and_coarsen_fixed_number (tr, indicators,
+                                         0.3, 0.0);
+      tr.execute_coarsening_and_refinement ();
+      if (myid == 0)
+        deallog << "total active cells = "
+                << tr.n_global_active_cells() << std::endl;
+    }
+
+  deallog << "OK" << std::endl;
+}
+
+
+int main(int argc, char *argv[])
+{
+  Utilities::MPI::MPI_InitFinalize mpi_initialization (argc, argv, 1);
+
+  MPILogInitAll all;
+  deallog.push("2d");
+  test<2>();
+  deallog.pop();
+  deallog.push("3d");
+  test<3>();
+  deallog.pop();
+}
diff --git a/tests/mpi/tria_ghost_owners_02.mpirun=11.output b/tests/mpi/tria_ghost_owners_02.mpirun=11.output
new file mode 100644 (file)
index 0000000..59ffd4c
--- /dev/null
@@ -0,0 +1,315 @@
+
+DEAL:0:2d::* cycle 0
+DEAL:0:2d::ghost owners: 1 2 
+DEAL:0:2d::level ghost owners: 1 2 3 5 8 
+DEAL:0:2d::total active cells = 124
+DEAL:0:2d::* cycle 1
+DEAL:0:2d::ghost owners: 1 2 3 5 6 
+DEAL:0:2d::level ghost owners: 1 2 3 5 6 8 
+DEAL:0:2d::total active cells = 169
+DEAL:0:2d::* cycle 2
+DEAL:0:2d::ghost owners: 1 2 
+DEAL:0:2d::level ghost owners: 1 2 5 7 
+DEAL:0:2d::total active cells = 190
+DEAL:0:2d::* cycle 3
+DEAL:0:2d::ghost owners: 1 
+DEAL:0:2d::level ghost owners: 1 2 3 6 9 
+DEAL:0:2d::total active cells = 304
+DEAL:0:2d::OK
+DEAL:0:3d::* cycle 0
+DEAL:0:3d::ghost owners: 2 3 4 6 7 8 10 
+DEAL:0:3d::level ghost owners: 2 3 4 6 7 8 10 
+DEAL:0:3d::total active cells = 197
+DEAL:0:3d::* cycle 1
+DEAL:0:3d::ghost owners: 1 2 4 7 8 
+DEAL:0:3d::level ghost owners: 1 2 4 7 8 
+DEAL:0:3d::total active cells = 617
+DEAL:0:3d::* cycle 2
+DEAL:0:3d::ghost owners: 1 2 3 4 6 9 10 
+DEAL:0:3d::level ghost owners: 1 2 3 4 6 9 10 
+DEAL:0:3d::total active cells = 1793
+DEAL:0:3d::* cycle 3
+DEAL:0:3d::ghost owners: 1 2 3 4 5 6 8 9 10 
+DEAL:0:3d::level ghost owners: 1 2 3 4 5 6 8 9 10 
+DEAL:0:3d::total active cells = 6357
+DEAL:0:3d::OK
+
+DEAL:1:2d::* cycle 0
+DEAL:1:2d::ghost owners: 0 2 3 4 5 6 
+DEAL:1:2d::level ghost owners: 0 2 3 4 5 6 
+DEAL:1:2d::* cycle 1
+DEAL:1:2d::ghost owners: 0 2 3 5 6 8 
+DEAL:1:2d::level ghost owners: 0 2 3 5 6 8 
+DEAL:1:2d::* cycle 2
+DEAL:1:2d::ghost owners: 0 2 4 
+DEAL:1:2d::level ghost owners: 0 2 4 5 
+DEAL:1:2d::* cycle 3
+DEAL:1:2d::ghost owners: 0 2 3 5 
+DEAL:1:2d::level ghost owners: 0 2 3 5 
+DEAL:1:2d::OK
+DEAL:1:3d::* cycle 0
+DEAL:1:3d::ghost owners: 
+DEAL:1:3d::level ghost owners: 
+DEAL:1:3d::* cycle 1
+DEAL:1:3d::ghost owners: 0 2 4 5 7 8 
+DEAL:1:3d::level ghost owners: 0 2 4 5 7 8 
+DEAL:1:3d::* cycle 2
+DEAL:1:3d::ghost owners: 0 2 3 4 6 7 9 10 
+DEAL:1:3d::level ghost owners: 0 2 3 4 6 7 9 10 
+DEAL:1:3d::* cycle 3
+DEAL:1:3d::ghost owners: 0 2 3 4 5 6 8 9 10 
+DEAL:1:3d::level ghost owners: 0 2 3 4 5 6 8 9 10 
+DEAL:1:3d::OK
+
+
+DEAL:2:2d::* cycle 0
+DEAL:2:2d::ghost owners: 0 1 3 4 5 6 8 
+DEAL:2:2d::level ghost owners: 0 1 3 4 5 6 8 
+DEAL:2:2d::* cycle 1
+DEAL:2:2d::ghost owners: 0 1 3 
+DEAL:2:2d::level ghost owners: 0 1 3 5 8 
+DEAL:2:2d::* cycle 2
+DEAL:2:2d::ghost owners: 0 1 3 4 5 7 
+DEAL:2:2d::level ghost owners: 0 1 3 4 5 7 
+DEAL:2:2d::* cycle 3
+DEAL:2:2d::ghost owners: 1 3 6 7 
+DEAL:2:2d::level ghost owners: 0 1 3 5 6 7 9 
+DEAL:2:2d::OK
+DEAL:2:3d::* cycle 0
+DEAL:2:3d::ghost owners: 0 3 4 6 7 8 10 
+DEAL:2:3d::level ghost owners: 0 3 4 6 7 8 10 
+DEAL:2:3d::* cycle 1
+DEAL:2:3d::ghost owners: 0 1 3 4 5 6 7 8 9 
+DEAL:2:3d::level ghost owners: 0 1 3 4 5 6 7 8 9 
+DEAL:2:3d::* cycle 2
+DEAL:2:3d::ghost owners: 0 1 3 4 5 6 7 9 10 
+DEAL:2:3d::level ghost owners: 0 1 3 4 5 6 7 9 10 
+DEAL:2:3d::* cycle 3
+DEAL:2:3d::ghost owners: 0 1 3 4 5 6 8 9 10 
+DEAL:2:3d::level ghost owners: 0 1 3 4 5 6 8 9 10 
+DEAL:2:3d::OK
+
+
+DEAL:3:2d::* cycle 0
+DEAL:3:2d::ghost owners: 1 2 4 5 
+DEAL:3:2d::level ghost owners: 0 1 2 4 5 8 
+DEAL:3:2d::* cycle 1
+DEAL:3:2d::ghost owners: 0 1 2 4 5 6 8 9 
+DEAL:3:2d::level ghost owners: 0 1 2 4 5 6 8 9 
+DEAL:3:2d::* cycle 2
+DEAL:3:2d::ghost owners: 2 4 
+DEAL:3:2d::level ghost owners: 2 4 
+DEAL:3:2d::* cycle 3
+DEAL:3:2d::ghost owners: 1 2 4 5 7 9 
+DEAL:3:2d::level ghost owners: 0 1 2 4 5 6 7 9 
+DEAL:3:2d::OK
+DEAL:3:3d::* cycle 0
+DEAL:3:3d::ghost owners: 0 2 4 6 7 8 10 
+DEAL:3:3d::level ghost owners: 0 2 4 6 7 8 10 
+DEAL:3:3d::* cycle 1
+DEAL:3:3d::ghost owners: 2 4 6 7 8 9 
+DEAL:3:3d::level ghost owners: 2 4 6 7 8 9 
+DEAL:3:3d::* cycle 2
+DEAL:3:3d::ghost owners: 0 1 2 4 5 6 8 9 10 
+DEAL:3:3d::level ghost owners: 0 1 2 4 5 6 8 9 10 
+DEAL:3:3d::* cycle 3
+DEAL:3:3d::ghost owners: 0 1 2 4 5 9 10 
+DEAL:3:3d::level ghost owners: 0 1 2 4 5 8 9 10 
+DEAL:3:3d::OK
+
+
+DEAL:4:2d::* cycle 0
+DEAL:4:2d::ghost owners: 1 2 3 5 6 8 9 
+DEAL:4:2d::level ghost owners: 1 2 3 5 6 8 9 
+DEAL:4:2d::* cycle 1
+DEAL:4:2d::ghost owners: 3 5 8 9 
+DEAL:4:2d::level ghost owners: 3 5 8 9 
+DEAL:4:2d::* cycle 2
+DEAL:4:2d::ghost owners: 1 2 3 5 7 8 
+DEAL:4:2d::level ghost owners: 1 2 3 5 7 8 
+DEAL:4:2d::* cycle 3
+DEAL:4:2d::ghost owners: 3 5 6 
+DEAL:4:2d::level ghost owners: 3 5 6 
+DEAL:4:2d::OK
+DEAL:4:3d::* cycle 0
+DEAL:4:3d::ghost owners: 0 2 3 6 7 8 10 
+DEAL:4:3d::level ghost owners: 0 2 3 6 7 8 10 
+DEAL:4:3d::* cycle 1
+DEAL:4:3d::ghost owners: 0 1 2 3 5 6 7 8 9 10 
+DEAL:4:3d::level ghost owners: 0 1 2 3 5 6 7 8 9 10 
+DEAL:4:3d::* cycle 2
+DEAL:4:3d::ghost owners: 0 1 2 3 5 6 8 9 10 
+DEAL:4:3d::level ghost owners: 0 1 2 3 5 6 8 9 10 
+DEAL:4:3d::* cycle 3
+DEAL:4:3d::ghost owners: 0 1 2 3 5 6 8 9 10 
+DEAL:4:3d::level ghost owners: 0 1 2 3 5 6 8 9 10 
+DEAL:4:3d::OK
+
+
+DEAL:5:2d::* cycle 0
+DEAL:5:2d::ghost owners: 1 2 3 4 6 7 8 9 
+DEAL:5:2d::level ghost owners: 0 1 2 3 4 6 7 8 9 
+DEAL:5:2d::* cycle 1
+DEAL:5:2d::ghost owners: 0 1 3 4 6 7 9 
+DEAL:5:2d::level ghost owners: 0 1 2 3 4 6 7 8 9 
+DEAL:5:2d::* cycle 2
+DEAL:5:2d::ghost owners: 2 4 6 7 8 
+DEAL:5:2d::level ghost owners: 0 1 2 4 6 7 8 9 
+DEAL:5:2d::* cycle 3
+DEAL:5:2d::ghost owners: 1 3 4 6 7 9 
+DEAL:5:2d::level ghost owners: 1 2 3 4 6 7 9 10 
+DEAL:5:2d::OK
+DEAL:5:3d::* cycle 0
+DEAL:5:3d::ghost owners: 
+DEAL:5:3d::level ghost owners: 
+DEAL:5:3d::* cycle 1
+DEAL:5:3d::ghost owners: 1 2 4 6 7 8 9 10 
+DEAL:5:3d::level ghost owners: 1 2 4 6 7 8 9 10 
+DEAL:5:3d::* cycle 2
+DEAL:5:3d::ghost owners: 2 3 4 6 8 9 10 
+DEAL:5:3d::level ghost owners: 2 3 4 6 8 9 10 
+DEAL:5:3d::* cycle 3
+DEAL:5:3d::ghost owners: 0 1 2 3 4 6 7 9 10 
+DEAL:5:3d::level ghost owners: 0 1 2 3 4 6 7 8 9 10 
+DEAL:5:3d::OK
+
+
+DEAL:6:2d::* cycle 0
+DEAL:6:2d::ghost owners: 1 2 4 5 7 8 9 
+DEAL:6:2d::level ghost owners: 1 2 4 5 7 8 9 
+DEAL:6:2d::* cycle 1
+DEAL:6:2d::ghost owners: 0 1 3 5 7 8 
+DEAL:6:2d::level ghost owners: 0 1 3 5 7 8 10 
+DEAL:6:2d::* cycle 2
+DEAL:6:2d::ghost owners: 5 7 8 9 
+DEAL:6:2d::level ghost owners: 5 7 8 9 
+DEAL:6:2d::* cycle 3
+DEAL:6:2d::ghost owners: 2 4 5 7 9 10 
+DEAL:6:2d::level ghost owners: 0 2 3 4 5 7 8 9 10 
+DEAL:6:2d::OK
+DEAL:6:3d::* cycle 0
+DEAL:6:3d::ghost owners: 0 2 3 4 7 8 10 
+DEAL:6:3d::level ghost owners: 0 2 3 4 7 8 10 
+DEAL:6:3d::* cycle 1
+DEAL:6:3d::ghost owners: 2 3 4 5 7 8 9 10 
+DEAL:6:3d::level ghost owners: 2 3 4 5 7 8 9 10 
+DEAL:6:3d::* cycle 2
+DEAL:6:3d::ghost owners: 0 1 2 3 4 5 7 8 9 10 
+DEAL:6:3d::level ghost owners: 0 1 2 3 4 5 7 8 9 10 
+DEAL:6:3d::* cycle 3
+DEAL:6:3d::ghost owners: 0 1 2 4 5 7 8 9 
+DEAL:6:3d::level ghost owners: 0 1 2 4 5 7 8 9 10 
+DEAL:6:3d::OK
+
+
+DEAL:7:2d::* cycle 0
+DEAL:7:2d::ghost owners: 5 6 8 9 
+DEAL:7:2d::level ghost owners: 5 6 8 9 
+DEAL:7:2d::* cycle 1
+DEAL:7:2d::ghost owners: 5 6 8 10 
+DEAL:7:2d::level ghost owners: 5 6 8 10 
+DEAL:7:2d::* cycle 2
+DEAL:7:2d::ghost owners: 2 4 5 6 8 9 
+DEAL:7:2d::level ghost owners: 0 2 4 5 6 8 9 10 
+DEAL:7:2d::* cycle 3
+DEAL:7:2d::ghost owners: 2 3 5 6 8 9 
+DEAL:7:2d::level ghost owners: 2 3 5 6 8 9 10 
+DEAL:7:2d::OK
+DEAL:7:3d::* cycle 0
+DEAL:7:3d::ghost owners: 0 2 3 4 6 8 10 
+DEAL:7:3d::level ghost owners: 0 2 3 4 6 8 10 
+DEAL:7:3d::* cycle 1
+DEAL:7:3d::ghost owners: 0 1 2 3 4 5 6 8 9 10 
+DEAL:7:3d::level ghost owners: 0 1 2 3 4 5 6 8 9 10 
+DEAL:7:3d::* cycle 2
+DEAL:7:3d::ghost owners: 1 2 6 8 9 10 
+DEAL:7:3d::level ghost owners: 1 2 6 8 9 10 
+DEAL:7:3d::* cycle 3
+DEAL:7:3d::ghost owners: 5 6 8 9 10 
+DEAL:7:3d::level ghost owners: 5 6 8 9 10 
+DEAL:7:3d::OK
+
+
+DEAL:8:2d::* cycle 0
+DEAL:8:2d::ghost owners: 2 4 5 6 7 9 10 
+DEAL:8:2d::level ghost owners: 0 2 3 4 5 6 7 9 10 
+DEAL:8:2d::* cycle 1
+DEAL:8:2d::ghost owners: 1 3 4 6 7 9 10 
+DEAL:8:2d::level ghost owners: 0 1 2 3 4 5 6 7 9 10 
+DEAL:8:2d::* cycle 2
+DEAL:8:2d::ghost owners: 4 5 6 7 9 10 
+DEAL:8:2d::level ghost owners: 4 5 6 7 9 10 
+DEAL:8:2d::* cycle 3
+DEAL:8:2d::ghost owners: 7 9 10 
+DEAL:8:2d::level ghost owners: 6 7 9 10 
+DEAL:8:2d::OK
+DEAL:8:3d::* cycle 0
+DEAL:8:3d::ghost owners: 0 2 3 4 6 7 10 
+DEAL:8:3d::level ghost owners: 0 2 3 4 6 7 10 
+DEAL:8:3d::* cycle 1
+DEAL:8:3d::ghost owners: 0 1 2 3 4 5 6 7 9 10 
+DEAL:8:3d::level ghost owners: 0 1 2 3 4 5 6 7 9 10 
+DEAL:8:3d::* cycle 2
+DEAL:8:3d::ghost owners: 3 4 5 6 7 9 10 
+DEAL:8:3d::level ghost owners: 3 4 5 6 7 9 10 
+DEAL:8:3d::* cycle 3
+DEAL:8:3d::ghost owners: 0 1 2 4 6 7 9 10 
+DEAL:8:3d::level ghost owners: 0 1 2 3 4 5 6 7 9 10 
+DEAL:8:3d::OK
+
+
+DEAL:9:2d::* cycle 0
+DEAL:9:2d::ghost owners: 4 5 6 7 8 10 
+DEAL:9:2d::level ghost owners: 4 5 6 7 8 10 
+DEAL:9:2d::* cycle 1
+DEAL:9:2d::ghost owners: 3 4 5 8 10 
+DEAL:9:2d::level ghost owners: 3 4 5 8 10 
+DEAL:9:2d::* cycle 2
+DEAL:9:2d::ghost owners: 6 7 8 10 
+DEAL:9:2d::level ghost owners: 5 6 7 8 10 
+DEAL:9:2d::* cycle 3
+DEAL:9:2d::ghost owners: 3 5 6 7 8 10 
+DEAL:9:2d::level ghost owners: 0 2 3 5 6 7 8 10 
+DEAL:9:2d::OK
+DEAL:9:3d::* cycle 0
+DEAL:9:3d::ghost owners: 
+DEAL:9:3d::level ghost owners: 
+DEAL:9:3d::* cycle 1
+DEAL:9:3d::ghost owners: 2 3 4 5 6 7 8 10 
+DEAL:9:3d::level ghost owners: 2 3 4 5 6 7 8 10 
+DEAL:9:3d::* cycle 2
+DEAL:9:3d::ghost owners: 0 1 2 3 4 5 6 7 8 10 
+DEAL:9:3d::level ghost owners: 0 1 2 3 4 5 6 7 8 10 
+DEAL:9:3d::* cycle 3
+DEAL:9:3d::ghost owners: 0 1 2 3 4 5 6 7 8 10 
+DEAL:9:3d::level ghost owners: 0 1 2 3 4 5 6 7 8 10 
+DEAL:9:3d::OK
+
+
+DEAL:10:2d::* cycle 0
+DEAL:10:2d::ghost owners: 8 9 
+DEAL:10:2d::level ghost owners: 8 9 
+DEAL:10:2d::* cycle 1
+DEAL:10:2d::ghost owners: 7 8 9 
+DEAL:10:2d::level ghost owners: 6 7 8 9 
+DEAL:10:2d::* cycle 2
+DEAL:10:2d::ghost owners: 8 9 
+DEAL:10:2d::level ghost owners: 7 8 9 
+DEAL:10:2d::* cycle 3
+DEAL:10:2d::ghost owners: 6 8 9 
+DEAL:10:2d::level ghost owners: 5 6 7 8 9 
+DEAL:10:2d::OK
+DEAL:10:3d::* cycle 0
+DEAL:10:3d::ghost owners: 0 2 3 4 6 7 8 
+DEAL:10:3d::level ghost owners: 0 2 3 4 6 7 8 
+DEAL:10:3d::* cycle 1
+DEAL:10:3d::ghost owners: 4 5 6 7 8 9 
+DEAL:10:3d::level ghost owners: 4 5 6 7 8 9 
+DEAL:10:3d::* cycle 2
+DEAL:10:3d::ghost owners: 0 1 2 3 4 5 6 7 8 9 
+DEAL:10:3d::level ghost owners: 0 1 2 3 4 5 6 7 8 9 
+DEAL:10:3d::* cycle 3
+DEAL:10:3d::ghost owners: 0 1 2 3 4 5 7 8 9 
+DEAL:10:3d::level ghost owners: 0 1 2 3 4 5 6 7 8 9 
+DEAL:10:3d::OK
+
diff --git a/tests/mpi/tria_ghost_owners_02.mpirun=5.output b/tests/mpi/tria_ghost_owners_02.mpirun=5.output
new file mode 100644 (file)
index 0000000..7729338
--- /dev/null
@@ -0,0 +1,147 @@
+
+DEAL:0:2d::* cycle 0
+DEAL:0:2d::ghost owners: 1 2 
+DEAL:0:2d::level ghost owners: 1 2 3 
+DEAL:0:2d::total active cells = 130
+DEAL:0:2d::* cycle 1
+DEAL:0:2d::ghost owners: 1 2 3 
+DEAL:0:2d::level ghost owners: 1 2 3 
+DEAL:0:2d::total active cells = 214
+DEAL:0:2d::* cycle 2
+DEAL:0:2d::ghost owners: 1 2 
+DEAL:0:2d::level ghost owners: 1 2 3 
+DEAL:0:2d::total active cells = 418
+DEAL:0:2d::* cycle 3
+DEAL:0:2d::ghost owners: 1 2 3 
+DEAL:0:2d::level ghost owners: 1 2 3 
+DEAL:0:2d::total active cells = 625
+DEAL:0:2d::OK
+DEAL:0:3d::* cycle 0
+DEAL:0:3d::ghost owners: 1 2 3 4 
+DEAL:0:3d::level ghost owners: 1 2 3 4 
+DEAL:0:3d::total active cells = 197
+DEAL:0:3d::* cycle 1
+DEAL:0:3d::ghost owners: 1 2 3 4 
+DEAL:0:3d::level ghost owners: 1 2 3 4 
+DEAL:0:3d::total active cells = 701
+DEAL:0:3d::* cycle 2
+DEAL:0:3d::ghost owners: 1 2 3 4 
+DEAL:0:3d::level ghost owners: 1 2 3 4 
+DEAL:0:3d::total active cells = 1989
+DEAL:0:3d::* cycle 3
+DEAL:0:3d::ghost owners: 1 2 3 4 
+DEAL:0:3d::level ghost owners: 1 2 3 4 
+DEAL:0:3d::total active cells = 7001
+DEAL:0:3d::OK
+
+DEAL:1:2d::* cycle 0
+DEAL:1:2d::ghost owners: 0 2 3 
+DEAL:1:2d::level ghost owners: 0 2 3 
+DEAL:1:2d::* cycle 1
+DEAL:1:2d::ghost owners: 0 2 3 4 
+DEAL:1:2d::level ghost owners: 0 2 3 4 
+DEAL:1:2d::* cycle 2
+DEAL:1:2d::ghost owners: 0 2 3 
+DEAL:1:2d::level ghost owners: 0 2 3 4 
+DEAL:1:2d::* cycle 3
+DEAL:1:2d::ghost owners: 0 2 3 
+DEAL:1:2d::level ghost owners: 0 2 3 
+DEAL:1:2d::OK
+DEAL:1:3d::* cycle 0
+DEAL:1:3d::ghost owners: 0 2 3 4 
+DEAL:1:3d::level ghost owners: 0 2 3 4 
+DEAL:1:3d::* cycle 1
+DEAL:1:3d::ghost owners: 0 2 3 4 
+DEAL:1:3d::level ghost owners: 0 2 3 4 
+DEAL:1:3d::* cycle 2
+DEAL:1:3d::ghost owners: 0 2 3 4 
+DEAL:1:3d::level ghost owners: 0 2 3 4 
+DEAL:1:3d::* cycle 3
+DEAL:1:3d::ghost owners: 0 2 3 4 
+DEAL:1:3d::level ghost owners: 0 2 3 4 
+DEAL:1:3d::OK
+
+
+DEAL:2:2d::* cycle 0
+DEAL:2:2d::ghost owners: 0 1 3 4 
+DEAL:2:2d::level ghost owners: 0 1 3 4 
+DEAL:2:2d::* cycle 1
+DEAL:2:2d::ghost owners: 0 1 3 4 
+DEAL:2:2d::level ghost owners: 0 1 3 4 
+DEAL:2:2d::* cycle 2
+DEAL:2:2d::ghost owners: 0 1 3 4 
+DEAL:2:2d::level ghost owners: 0 1 3 4 
+DEAL:2:2d::* cycle 3
+DEAL:2:2d::ghost owners: 0 1 3 4 
+DEAL:2:2d::level ghost owners: 0 1 3 4 
+DEAL:2:2d::OK
+DEAL:2:3d::* cycle 0
+DEAL:2:3d::ghost owners: 0 1 3 4 
+DEAL:2:3d::level ghost owners: 0 1 3 4 
+DEAL:2:3d::* cycle 1
+DEAL:2:3d::ghost owners: 0 1 3 4 
+DEAL:2:3d::level ghost owners: 0 1 3 4 
+DEAL:2:3d::* cycle 2
+DEAL:2:3d::ghost owners: 0 1 3 4 
+DEAL:2:3d::level ghost owners: 0 1 3 4 
+DEAL:2:3d::* cycle 3
+DEAL:2:3d::ghost owners: 0 1 3 4 
+DEAL:2:3d::level ghost owners: 0 1 3 4 
+DEAL:2:3d::OK
+
+
+DEAL:3:2d::* cycle 0
+DEAL:3:2d::ghost owners: 1 2 4 
+DEAL:3:2d::level ghost owners: 0 1 2 4 
+DEAL:3:2d::* cycle 1
+DEAL:3:2d::ghost owners: 0 1 2 4 
+DEAL:3:2d::level ghost owners: 0 1 2 4 
+DEAL:3:2d::* cycle 2
+DEAL:3:2d::ghost owners: 1 2 4 
+DEAL:3:2d::level ghost owners: 0 1 2 4 
+DEAL:3:2d::* cycle 3
+DEAL:3:2d::ghost owners: 0 1 2 4 
+DEAL:3:2d::level ghost owners: 0 1 2 4 
+DEAL:3:2d::OK
+DEAL:3:3d::* cycle 0
+DEAL:3:3d::ghost owners: 0 1 2 4 
+DEAL:3:3d::level ghost owners: 0 1 2 4 
+DEAL:3:3d::* cycle 1
+DEAL:3:3d::ghost owners: 0 1 2 4 
+DEAL:3:3d::level ghost owners: 0 1 2 4 
+DEAL:3:3d::* cycle 2
+DEAL:3:3d::ghost owners: 0 1 2 4 
+DEAL:3:3d::level ghost owners: 0 1 2 4 
+DEAL:3:3d::* cycle 3
+DEAL:3:3d::ghost owners: 0 1 2 4 
+DEAL:3:3d::level ghost owners: 0 1 2 4 
+DEAL:3:3d::OK
+
+
+DEAL:4:2d::* cycle 0
+DEAL:4:2d::ghost owners: 2 3 
+DEAL:4:2d::level ghost owners: 2 3 
+DEAL:4:2d::* cycle 1
+DEAL:4:2d::ghost owners: 1 2 3 
+DEAL:4:2d::level ghost owners: 1 2 3 
+DEAL:4:2d::* cycle 2
+DEAL:4:2d::ghost owners: 2 3 
+DEAL:4:2d::level ghost owners: 1 2 3 
+DEAL:4:2d::* cycle 3
+DEAL:4:2d::ghost owners: 2 3 
+DEAL:4:2d::level ghost owners: 2 3 
+DEAL:4:2d::OK
+DEAL:4:3d::* cycle 0
+DEAL:4:3d::ghost owners: 0 1 2 3 
+DEAL:4:3d::level ghost owners: 0 1 2 3 
+DEAL:4:3d::* cycle 1
+DEAL:4:3d::ghost owners: 0 1 2 3 
+DEAL:4:3d::level ghost owners: 0 1 2 3 
+DEAL:4:3d::* cycle 2
+DEAL:4:3d::ghost owners: 0 1 2 3 
+DEAL:4:3d::level ghost owners: 0 1 2 3 
+DEAL:4:3d::* cycle 3
+DEAL:4:3d::ghost owners: 0 1 2 3 
+DEAL:4:3d::level ghost owners: 0 1 2 3 
+DEAL:4:3d::OK
+

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.