I'm learning MPI (using mpi4py in Python) and using it to parallelize an iterative Laplace solver. My initial design decision was to use classes to implement the solver (since that's what I did for a single processor). But now that I have done it, it seems like this is not the right way to do it. This is the structure of the program ("..." represents physical problem-specific portions, not shown):
class xyz:
def __init__(self):
self.parallel_setup()
...
def parallel_setup(self):
self.comm = MPI.COMM_WORLD
self.rank = self.comm.Get_rank()
self.nprocs = self.comm.Get_size()
def func1(self):
...
def func2(self):
...
def main():
...
solver = xyz()
solver.func1()
solver.func2()
if __name__ == '__main__':
main()
Now I guess I'm ending up instantiating the class in multiple processes, which is probably not what I want? Also, I'm making the communicator object a member variable, which is also probably not the right idea? I just want to use the multi-processor picture within the solver to parallelize processes. What is the right approach to use here?
In any case, what are the problems I'll be running into with this approach? I mean, I haven't seen any "issues" while running (though I've run into a host of other problems, which I don't feel are related (?) - like the solver not converging at all, but the solution "looking" okayish nevertheless). Please ask for more info if so required. I don't exactly know what to provide further.
Your approach is entirely correct. MPI is process based, meaning that each process in a way behaves completely independently. So if process 1 initialized MPI, but process 2 does not initialize MPI, the latter has no access to MPI: each process needs to initialize MPI. Some magic behind the scenes will then connect all the processes together into one big world communicator.
Likewise, storing the communicator in your object is also perfectly fine. Each process needs to remember it, and this is better than having a global variable.