From 4fea5a665a1a7f3565112c78bf399a5f433c4138 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Franck=20P=C3=A9rignon?= <franck.perignon@imag.fr>
Date: Wed, 5 Feb 2014 12:49:02 +0000
Subject: [PATCH] Add parent comm in Bridges to deal with (future) intra/inter
 comm context

---
 HySoP/hysop/mpi/topology.py | 97 +++++++++++++++++++++++--------------
 1 file changed, 61 insertions(+), 36 deletions(-)

diff --git a/HySoP/hysop/mpi/topology.py b/HySoP/hysop/mpi/topology.py
index 3386a2705..82be9a6a5 100644
--- a/HySoP/hysop/mpi/topology.py
+++ b/HySoP/hysop/mpi/topology.py
@@ -25,7 +25,7 @@ To get more details try :
 from parmepy.constants import ORDER, np, PARMES_INDEX, debug, PARMES_INTEGER
 from parmepy.mpi.mesh import SubMesh
 from itertools import count
-from parmepy.mpi.main_var import main_comm, main_size, main_rank, MPI
+from parmepy.mpi.main_var import main_comm, MPI
 
 
 class Cartesian(object):
@@ -74,6 +74,8 @@ class Cartesian(object):
         # to 0 if shape[:] = 1
         ## (Source) Communicator used to build the topology
         self._comm_origin = comm
+        ## number of process in comm_origin
+        self._origin_size = self._comm_origin.Get_size()
         ## True if everything has been properly set for this topology
         self.isUpToDate = False
         ## Grid of mpi process layout
@@ -82,7 +84,7 @@ class Cartesian(object):
         if shape is None:
             # If shape is not provided, computation of  the "optimal" processus
             # distribution for each direction of the grid topology.
-            shape = np.asarray(MPI.Compute_dims(main_size, self.dim),
+            shape = np.asarray(MPI.Compute_dims(self._origin_size, self.dim),
                                dtype=PARMES_INDEX)
 
             if cutdir is not None:
@@ -113,7 +115,7 @@ class Cartesian(object):
             self.shape = shape
 
         # Special care for the 1 process case:
-        if main_size == 1:
+        if self._origin_size == 1:
             self.dim = 1
             self.cutdir[-1] = True
 
@@ -210,6 +212,12 @@ class Cartesian(object):
         #      print "A similar topology already exist in the domain's list.\
         #      You'd rather destroy this one and use topo of id", isNew
 
+    def getParent(self):
+        """
+        returns the communicator used to build this topology
+        """
+        return self._comm_origin
+
     @debug
     def setUp(self):
         """Topology set up.
@@ -361,8 +369,8 @@ class Cartesian(object):
             s += str(self.dim) + 'D cartesian Topology of size ' \
                 + str(self.shape) + '\n'
         s += 'Process of coordinates ' + str(self.proc_coords[:])
-        s += ' and of ranks (topo/world) ' + str(self.rank) + '/'
-        s += str(main_rank) + '.\n'
+        s += ' and of ranks (topo/origin) ' + str(self.rank) + '/'
+        s += str(self._comm_origin.Get_rank()) + '.\n'
         s += 'Neighbours coordinates : \n'
         s += str(self.neighbours) + '\n'
         s += 'Ghost layer : ' + str(self.ghosts[:]) + '\n'
@@ -434,11 +442,12 @@ class Bridge(object):
     """
 
     @debug
-    def __init__(self, topoFrom, topoTo):
+    def __init__(self, topoFrom, topoTo, parentComm=None):
         """
         Bridge constructor.
         @param source topology
         @param targeted topology
+        @param parent communicator, if None, use topoFrom.getParent()
         """
         ## Source topology
         self.topoFrom = topoFrom
@@ -475,9 +484,25 @@ class Bridge(object):
 
         self.hasLocalInter = True
 
+        ## Parent communicator
+        ## Todo : define some proper conditions for compatibility
+        ## between topoFrom, topoTo and parent:
+        ## - same size
+        ## - same domain
+        ## - common processus ...
+        ## At the time we check that both topo have
+        ## the same comm_origin.
+        if parentComm is None:
+            self._parentComm = self.topoFrom.getParent()
+        else:
+            self._parentComm = parentComm
+        self._parentRank = self._parentComm.Get_rank()
+        self._parentSize = self._parentComm.Get_size()
         if self.topoFrom == self.topoTo:
             return
 
+        assert(self.topoTo.getParent() is self._parentComm)
+
         # Both topologies must have the
         # same number of mpi processes.
         assert topoFrom.size == topoTo.size
@@ -489,29 +514,32 @@ class Bridge(object):
         start1 = topoFrom.mesh.global_start
         end1 = topoFrom.mesh.global_end
         iglob1 = np.zeros((size1, dom.dimension * 2), dtype=np.int32)
-        iglob1[main_rank, 0::2] = start1
-        iglob1[main_rank, 1::2] = end1
+        iglob1[self._parentRank, 0::2] = start1
+        iglob1[self._parentRank, 1::2] = end1
 
         size2 = topoTo.size
         start2 = topoTo.mesh.global_start
         end2 = topoTo.mesh.global_end
         iglob2 = np.zeros((size2, dom.dimension * 2), dtype=np.int32)
-        iglob2[main_rank, 0::2] = start2
-        iglob2[main_rank, 1::2] = end2
+        iglob2[self._parentRank, 0::2] = start2
+        iglob2[self._parentRank, 1::2] = end2
 
         # 2 Distribute these indices.
-        main_comm.Allgather([iglob1[main_rank, :], MPI.INT], [iglob1, MPI.INT])
-        main_comm.Allgather([iglob2[main_rank, :], MPI.INT], [iglob2, MPI.INT])
+        self._parentComm.Allgather([iglob1[self._parentRank, :], MPI.INT],
+                                   [iglob1, MPI.INT])
+        self._parentComm.Allgather([iglob2[self._parentRank, :], MPI.INT],
+                                   [iglob2, MPI.INT])
 
         # Connectivity :
         sTo = np.zeros((0, 1 + dom.dimension * 2), dtype=np.int)
         indexFrom = []
         for dim in range(dom.dimension):
-            indexFrom.append(range(iglob1[main_rank, dim * 2],
-                                   iglob1[main_rank, dim * 2 + 1] + 1))
+            indexFrom.append(range(iglob1[self._parentRank, dim * 2],
+                                   iglob1[self._parentRank, dim * 2 + 1] + 1))
 
         line = np.zeros((1 + 2 * dom.dimension), dtype=np.int32)
-        listRanks = [i for i in range(main_size) if i != main_rank]
+        listRanks = [i for i in range(self._parentSize)
+                     if i != self._parentRank]
 
         for i in listRanks:
             line[0] = i
@@ -533,8 +561,8 @@ class Bridge(object):
         localFrom = np.zeros((2 * dom.dimension), dtype=np.int32)
 
         for dim in range(dom.dimension):
-            indexTo = range(iglob2[main_rank, dim * 2],
-                            iglob2[main_rank, dim * 2 + 1] + 1)
+            indexTo = range(iglob2[self._parentRank, dim * 2],
+                            iglob2[self._parentRank, dim * 2 + 1] + 1)
             interRow = [k for k in indexFrom[dim] if k in indexTo]
             interRow.sort()
 
@@ -567,15 +595,15 @@ class Bridge(object):
                                        dom.dimension * 2), dtype=np.int)
 
         globalConnectivity[:, 1:] = sTo.copy(order='A')
-        globalConnectivity[:, 0] = main_rank
+        globalConnectivity[:, 0] = self._parentRank
 
-        if main_rank == 0:
-            for i in range(1, main_size):
-                temp = main_comm.recv(source=i)
+        if self._parentRank == 0:
+            for i in range(1, self._parentSize):
+                temp = self._parentComm.recv(source=i)
                 globalConnectivity = np.vstack((globalConnectivity, temp))
 
         else:
-            main_comm.ssend(globalConnectivity, dest=0)
+            self._parentComm.ssend(globalConnectivity, dest=0)
 
         ## recvFrom[:,0] rank of the sending process in main_comm
         ## recvFrom[:,1:] local indices (start,end, ...)
@@ -586,8 +614,8 @@ class Bridge(object):
         ## an array that will be saved at positions of indices 2:5
         ## in the first dir and 1:3 in second dir
         rFrom = np.empty((), dtype=np.int32)
-        if main_rank == 0:
-            for fromRank in range(main_size):
+        if self._parentRank == 0:
+            for fromRank in range(self._parentSize):
                 cond1 = globalConnectivity[:, 1] == fromRank
                 cond2 = globalConnectivity[:, 0] != fromRank
                 cond = cond1 & cond2
@@ -595,13 +623,13 @@ class Bridge(object):
                 cond1 = np.ones((sol.shape[1]), dtype=np.bool)
                 cond1[1] = False
                 sol = np.compress(cond1, sol, axis=1)
-                if(fromRank != main_rank):
-                    main_comm.ssend(sol, dest=fromRank)
+                if(fromRank != self._parentRank):
+                    self._parentComm.ssend(sol, dest=fromRank)
                 else:
                     rFrom = sol.copy()
 
         else:
-            rFrom = main_comm.recv(source=0)
+            rFrom = self._parentComm.recv(source=0)
 
         # Final setup for recvFrom and sendTo : shift from
         # global indices to local ones.
@@ -636,14 +664,11 @@ class Bridge(object):
         """ TopologyBridge info display """
         s = '======== Bridge from topology ' + str(self.topoFrom.getId())
         s += ' to topology ' + str(self.topoTo.getId()) + ' ========\n'
-        s += '[' + str(main_rank) + '] sendTo :' + str(self.sendTo) + '\n'
-        s += '[' + str(main_rank) + '] recvFrom :' + str(self.recvFrom) + '\n'
-        s += '[' + str(main_rank) + '] iTo :' + str(self.ito) + '\n'
-        s += '[' + str(main_rank) + '] iFrom :' + str(self.ifrom) + '\n'
+        s += '[' + str(self._parentRank) + '] sendTo :'
+        s += str(self.sendTo) + '\n'
+        s += '[' + str(self._parentRank) + '] recvFrom :'
+        s += str(self.recvFrom) + '\n'
+        s += '[' + str(self._parentRank) + '] iTo :' + str(self.ito) + '\n'
+        s += '[' + str(self._parentRank) + '] iFrom :' + str(self.ifrom) + '\n'
         s += '=================================\n'
         return s
-
-if __name__ == "__main__":
-    print "This module defines the following classes:"
-    print "- Cartesian Topology: ", Cartesian.__doc__
-    print "- Bridge between topologies: ", Bridge.__doc__
-- 
GitLab