From 55df3b3f01aba71aa0f0b4265dc5741d35814b9a Mon Sep 17 00:00:00 2001
From: Thomas Witkowski <thomas.witkowski@gmx.de>
Date: Sat, 8 Dec 2012 18:29:20 +0000
Subject: [PATCH] Introduced initial partitioner.

---
 AMDiS/src/parallel/CheckerPartitioner.cc |  6 +--
 AMDiS/src/parallel/CheckerPartitioner.h  |  2 +-
 AMDiS/src/parallel/MeshDistributor.cc    | 63 ++++++++++++++++--------
 AMDiS/src/parallel/MeshDistributor.h     |  6 +++
 AMDiS/src/parallel/MeshPartitioner.cc    |  6 ++-
 AMDiS/src/parallel/MeshPartitioner.h     |  8 ++-
 AMDiS/src/parallel/ParMetisPartitioner.h |  4 +-
 AMDiS/src/parallel/SimplePartitioner.h   |  4 +-
 AMDiS/src/parallel/ZoltanPartitioner.cc  |  5 +-
 AMDiS/src/parallel/ZoltanPartitioner.h   |  2 +-
 10 files changed, 71 insertions(+), 35 deletions(-)

diff --git a/AMDiS/src/parallel/CheckerPartitioner.cc b/AMDiS/src/parallel/CheckerPartitioner.cc
index 5142e61a..a44e00ca 100644
--- a/AMDiS/src/parallel/CheckerPartitioner.cc
+++ b/AMDiS/src/parallel/CheckerPartitioner.cc
@@ -16,15 +16,15 @@
 
 namespace AMDiS {
 
-  CheckerPartitioner::CheckerPartitioner(MPI::Intracomm *comm)
-    : MeshPartitioner(comm),
+  CheckerPartitioner::CheckerPartitioner(string name, MPI::Intracomm *comm)
+    : MeshPartitioner(name, comm),
       mpiRank(mpiComm->Get_rank()),
       mpiSize(mpiComm->Get_size()),
       mode(0),
       multilevel(false)
   {
     string modestr = "";
-    Parameters::get("parallel->partitioner->mode", modestr);
+    Parameters::get(initFileStr + "->mode", modestr);
     
     if (modestr == "x-stripes")
       mode = 1;
diff --git a/AMDiS/src/parallel/CheckerPartitioner.h b/AMDiS/src/parallel/CheckerPartitioner.h
index 4933e8a1..2844be67 100644
--- a/AMDiS/src/parallel/CheckerPartitioner.h
+++ b/AMDiS/src/parallel/CheckerPartitioner.h
@@ -35,7 +35,7 @@ namespace AMDiS {
   class CheckerPartitioner : public MeshPartitioner
   {
   public:
-    CheckerPartitioner(MPI::Intracomm *comm);
+    CheckerPartitioner(string name, MPI::Intracomm *comm);
 
     ~CheckerPartitioner() {}
 
diff --git a/AMDiS/src/parallel/MeshDistributor.cc b/AMDiS/src/parallel/MeshDistributor.cc
index ba828905..740b171b 100644
--- a/AMDiS/src/parallel/MeshDistributor.cc
+++ b/AMDiS/src/parallel/MeshDistributor.cc
@@ -77,6 +77,7 @@ namespace AMDiS {
       mesh(NULL),
       refineManager(NULL),
       partitioner(NULL),
+      initialPartitioner(NULL),
       deserialized(false),
       writeSerializationFile(false),
       repartitioningAllowed(false),
@@ -104,36 +105,57 @@ namespace AMDiS {
     Parameters::get(name + "->repartition ith change", repartitionIthChange);
     Parameters::get(name + "->repartition wait after fail", repartitioningWaitAfterFail);
     Parameters::get(name + "->mesh adaptivity", meshAdaptivity);
+
     
+    // === Create partitioner object. ===
+
     string partStr = "parmetis";
     Parameters::get(name + "->partitioner", partStr);
 
     if (partStr == "parmetis") 
-      partitioner = new ParMetisPartitioner(&mpiComm);
+      partitioner = new ParMetisPartitioner("parallel->partitioner", &mpiComm);
 
     if (partStr == "zoltan") {
 #ifdef HAVE_ZOLTAN
-      partitioner = new ZoltanPartitioner(&mpiComm);
+      partitioner = new ZoltanPartitioner("parallel->partitioner", &mpiComm);
 #else
       ERROR_EXIT("AMDiS was compiled without Zoltan support. Therefore you cannot make use of it!\n");
 #endif
     }
 
     if (partStr == "checker")
-      partitioner = new CheckerPartitioner(&mpiComm);
+      partitioner = new CheckerPartitioner("parallel->partitioner", &mpiComm);
 
     if (partStr == "simple")
-      partitioner = new SimplePartitioner(&mpiComm);
+      partitioner = new SimplePartitioner("parallel->partitioner", &mpiComm);
+
+
+    // === Create initial partitioner object. ===
+
+    partStr = "";
+    Parameters::get(name + "->initial partitioner", partStr);
+    if (partStr == "") {
+      initialPartitioner = partitioner;
+    } else {    
+      if (partStr == "checker") {
+	initialPartitioner = 
+	  new CheckerPartitioner("parallel->initial partitioner", &mpiComm);
+      } else {
+	ERROR_EXIT("Not yet supported, but very easy to implement!\n");
+      }
+    }
+
+
+    // === And read some more parameters. ===
 
     int tmp = 0;
     Parameters::get(name + "->box partitioning", tmp);
     partitioner->setBoxPartitioning(static_cast<bool>(tmp));
+    initialPartitioner->setBoxPartitioning(static_cast<bool>(tmp));
 
     Parameters::get(name + "->print timings", printTimings);
     Parameters::get(name + "->print memory usage", printMemoryUsage);
 
-    TEST_EXIT(partitioner)("Could not create partitioner \"%s\"!\n", partStr.c_str());
-
     // If required, create hierarchical mesh level structure.
     createMeshLevelStructure();
   }
@@ -141,8 +163,10 @@ namespace AMDiS {
 
   MeshDistributor::~MeshDistributor()
   {
-    if (partitioner)
+    if (partitioner) {
       delete partitioner;
+      partitioner = NULL;
+    }
   }
 
 
@@ -357,18 +381,24 @@ namespace AMDiS {
     createMacroElementInfo();
 
     // create an initial partitioning of the mesh
-    bool useInitialPartitioning = partitioner->createInitialPartitioning();
+    bool useInitialPartitioning = 
+      initialPartitioner->createInitialPartitioning();
 
     // set the element weights, which are 1 at the very first begin
     setInitialElementWeights();
 
-    if (!useInitialPartitioning) {
+    if (!useInitialPartitioning) {   
       // and now partition the mesh    
-      bool partitioningSucceed = partitioner->partition(elemWeights, INITIAL);
+      bool partitioningSucceed = 
+	initialPartitioner->partition(elemWeights, INITIAL);
       TEST_EXIT(partitioningSucceed)("Initial partitioning does not work!\n");
     }
 
-    partitioner->createPartitionMap(partitionMap);
+    initialPartitioner->createPartitionMap(partitionMap);
+
+    if (initialPartitioner != partitioner) {
+      *partitioner = *initialPartitioner;
+    }
   }
 
 
@@ -462,6 +492,7 @@ namespace AMDiS {
     }
     
     partitioner->setMesh(mesh);
+    initialPartitioner->setMesh(mesh);
     
 
     // === Check whether the stationary problem should be serialized. ===
@@ -1446,15 +1477,7 @@ namespace AMDiS {
     if (!partitioner->meshChanged()) {
       MSG("Mesh partition does not create a new partition!\n");
       MSG("Try to refine partitioning!\n");
-      partitioningSucceed = partitioner->partition(elemWeights, REFINE_PART);
-      if (partitioningSucceed) {
-	MSG("OKAY, ERST MAL GUT!\n");
-	if (partitioner->meshChanged())
-	  MSG("UND JA, DAS WARS!\n");
-	else
-	  MSG("NE, LEIDER NICHT!\n");
-      }
-      
+      partitioningSucceed = partitioner->partition(elemWeights, REFINE_PART);     
       if (!partitioningSucceed || !partitioner->meshChanged()) {
 	mpiComm.Barrier();
 	repartitioningFailed = repartitioningWaitAfterFail;;
diff --git a/AMDiS/src/parallel/MeshDistributor.h b/AMDiS/src/parallel/MeshDistributor.h
index e0884ef7..a5578de7 100644
--- a/AMDiS/src/parallel/MeshDistributor.h
+++ b/AMDiS/src/parallel/MeshDistributor.h
@@ -504,6 +504,12 @@ namespace AMDiS {
     /// the ranks.
     MeshPartitioner *partitioner;
 
+    /// Pointer to a mesh partitioner that is used for the very first 
+    /// partitioning of the mesh. In most cases, this pointer points to the
+    /// same object as \ref partitioner, but this must not be the case in
+    /// general.
+    MeshPartitioner *initialPartitioner;
+
     /// Weights for the elements, i.e., the number of leaf elements within 
     /// this element.
     map<int, double> elemWeights;
diff --git a/AMDiS/src/parallel/MeshPartitioner.cc b/AMDiS/src/parallel/MeshPartitioner.cc
index 195e0187..0206f5f1 100644
--- a/AMDiS/src/parallel/MeshPartitioner.cc
+++ b/AMDiS/src/parallel/MeshPartitioner.cc
@@ -34,7 +34,8 @@ namespace AMDiS {
     map<int, int> arhElCodeSize;
 
     string partitioningFile = "";
-    Parameters::get("parallel->initial partitioning file", partitioningFile);
+    Parameters::get(initFileStr + "->initial partitioning file", 
+		    partitioningFile);
     if (partitioningFile != "") {
       MSG("Read initial partitioning file: %s\n", partitioningFile.c_str());
 
@@ -54,7 +55,8 @@ namespace AMDiS {
       useInitialPartitioning = true;
     } else {
       string arhMetaFile = "";
-      Parameters::get("parallel->partitioner->read meta arh", arhMetaFile);
+      Parameters::get(initFileStr + "->read meta arh", 
+		      arhMetaFile);
       bool partitioningArhBased = (arhMetaFile != "");
       if (partitioningArhBased) {
 	int nProc = ArhReader::readMetaData(arhMetaFile, mapElInRank, arhElCodeSize);
diff --git a/AMDiS/src/parallel/MeshPartitioner.h b/AMDiS/src/parallel/MeshPartitioner.h
index 396a6bd7..2401d1cd 100644
--- a/AMDiS/src/parallel/MeshPartitioner.h
+++ b/AMDiS/src/parallel/MeshPartitioner.h
@@ -53,8 +53,9 @@ namespace AMDiS {
   class MeshPartitioner
   {
   public:
-    MeshPartitioner(MPI::Intracomm *comm)
-      : mpiComm(comm),
+    MeshPartitioner(string name, MPI::Intracomm *comm)
+      : initFileStr(name),
+	mpiComm(comm),
 	mesh(NULL),
 	boxPartitioning(false),
 	mapLocalGlobal(NULL)
@@ -149,6 +150,9 @@ namespace AMDiS {
     }
 
   protected:
+    /// Prefix for reading parameters from init file.
+    string initFileStr;
+
     /// Pointer to the MPI communicator the mesh partitioner should make use of.
     MPI::Intracomm *mpiComm;
 
diff --git a/AMDiS/src/parallel/ParMetisPartitioner.h b/AMDiS/src/parallel/ParMetisPartitioner.h
index 210e3738..f896eb29 100644
--- a/AMDiS/src/parallel/ParMetisPartitioner.h
+++ b/AMDiS/src/parallel/ParMetisPartitioner.h
@@ -168,8 +168,8 @@ namespace AMDiS {
   class ParMetisPartitioner : public MeshPartitioner
   {
   public:
-    ParMetisPartitioner(MPI::Intracomm *comm)
-      : MeshPartitioner(comm),
+    ParMetisPartitioner(string name, MPI::Intracomm *comm)
+      : MeshPartitioner(name, comm),
         parMetisMesh(NULL),
 	itr(1000000.0)
     {}
diff --git a/AMDiS/src/parallel/SimplePartitioner.h b/AMDiS/src/parallel/SimplePartitioner.h
index be853289..43387178 100644
--- a/AMDiS/src/parallel/SimplePartitioner.h
+++ b/AMDiS/src/parallel/SimplePartitioner.h
@@ -40,8 +40,8 @@ namespace AMDiS {
   class SimplePartitioner : public MeshPartitioner
   {
   public:
-    SimplePartitioner(MPI::Intracomm *comm)
-      : MeshPartitioner(comm)
+    SimplePartitioner(string name, MPI::Intracomm *comm)
+      : MeshPartitioner(name, comm)
     {}
 
     ~SimplePartitioner() {}
diff --git a/AMDiS/src/parallel/ZoltanPartitioner.cc b/AMDiS/src/parallel/ZoltanPartitioner.cc
index cce8a3a3..214780fc 100644
--- a/AMDiS/src/parallel/ZoltanPartitioner.cc
+++ b/AMDiS/src/parallel/ZoltanPartitioner.cc
@@ -18,8 +18,9 @@
 
 namespace AMDiS {
 
-  ZoltanPartitioner::ZoltanPartitioner(MPI::Intracomm *comm)
-    : MeshPartitioner(comm),
+  ZoltanPartitioner::ZoltanPartitioner(string name,
+				       MPI::Intracomm *comm)
+    : MeshPartitioner(name, comm),
       zoltan(*comm),
       elWeights(NULL)
   {}
diff --git a/AMDiS/src/parallel/ZoltanPartitioner.h b/AMDiS/src/parallel/ZoltanPartitioner.h
index a54e32f8..fa1ecbff 100644
--- a/AMDiS/src/parallel/ZoltanPartitioner.h
+++ b/AMDiS/src/parallel/ZoltanPartitioner.h
@@ -37,7 +37,7 @@ namespace AMDiS {
   class ZoltanPartitioner : public MeshPartitioner
   {
   public:
-    ZoltanPartitioner(MPI::Intracomm *comm);
+    ZoltanPartitioner(string name, MPI::Intracomm *comm);
 
     ~ZoltanPartitioner() {}
       
-- 
GitLab