1414
1515from .. import openpmd_api_cxx as io
1616
17- # MPI is an optional dependency
18- if io .variants ['mpi' ]:
19- try :
20- from mpi4py import MPI
21- HAVE_MPI = True
22- except (ImportError , ModuleNotFoundError ):
23- print ("""
24- openPMD-api was built with support for MPI,
25- but mpi4py Python package was not found.
26- Will continue in serial mode.""" ,
27- file = sys .stderr )
28- HAVE_MPI = False
29- else :
30- HAVE_MPI = False
31-
32- debug = False
33-
34-
35- class FallbackMPICommunicator :
36- def __init__ (self ):
37- self .size = 1
38- self .rank = 0
39-
4017
4118def parse_args (program_name ):
4219 parser = argparse .ArgumentParser (
@@ -51,8 +28,19 @@ def parse_args(program_name):
5128or multiplexing the data path in streaming setups.
5229Parallelization with MPI is optionally possible and is done automatically
5330as soon as the mpi4py package is found and this tool is called in an MPI
54- context. In that case, each dataset will be equally sliced along the dimension
55- with the largest extent.
31+ context.
32+ Parallelization with MPI is optionally possible and can be switched on with
33+ the --mpi switch, resp. switched off with the --no-mpi switch.
34+ By default, openpmd-pipe will use MPI if all of the following conditions
35+ are fulfilled:
36+ 1) The mpi4py package can be imported.
37+ 2) The openPMD-api has been built with support for MPI.
38+ 3) The MPI size is greater than 1.
39+ By default, the openPMD-api will be initialized without an MPI communicator
40+ if the MPI size is 1. This is to simplify the use of the JSON backend
41+ which is only available in serial openPMD.
42+ With parallelization enabled, each dataset will be equally sliced along
43+ the dimension with the largest extent.
5644
5745Examples:
5846 {0} --infile simData.h5 --outfile simData_%T.bp
@@ -72,10 +60,45 @@ def parse_args(program_name):
7260 type = str ,
7361 default = '{}' ,
7462 help = 'JSON config for the out file' )
63+ # MPI, default: Import mpi4py if available and openPMD is parallel,
64+ # but don't use if MPI size is 1 (this makes it easier to interact with
65+ # JSON, since that backend is unavailable in parallel)
66+ if io .variants ['mpi' ]:
67+ parser .add_argument ('--mpi' , action = 'store_true' )
68+ parser .add_argument ('--no-mpi' , dest = 'mpi' , action = 'store_false' )
69+ parser .set_defaults (mpi = None )
7570
7671 return parser .parse_args ()
7772
7873
74+ args = parse_args (sys .argv [0 ])
75+ # MPI is an optional dependency
76+ if io .variants ['mpi' ] and (args .mpi is None or args .mpi ):
77+ try :
78+ from mpi4py import MPI
79+ HAVE_MPI = True
80+ except (ImportError , ModuleNotFoundError ):
81+ if args .mpi :
82+ raise
83+ else :
84+ print ("""
85+ openPMD-api was built with support for MPI,
86+ but mpi4py Python package was not found.
87+ Will continue in serial mode.""" ,
88+ file = sys .stderr )
89+ HAVE_MPI = False
90+ else :
91+ HAVE_MPI = False
92+
93+ debug = False
94+
95+
96+ class FallbackMPICommunicator :
97+ def __init__ (self ):
98+ self .size = 1
99+ self .rank = 0
100+
101+
79102class Chunk :
80103 """
81104 A Chunk is an n-dimensional hypercube, defined by an offset and an extent.
@@ -178,7 +201,7 @@ def __init__(self, infile, outfile, inconfig, outconfig, comm):
178201 self .comm = comm
179202
180203 def run (self ):
181- if self .comm .size == 1 :
204+ if not HAVE_MPI or ( args . mpi is None and self .comm .size == 1 ) :
182205 print ("Opening data source" )
183206 sys .stdout .flush ()
184207 inseries = io .Series (self .infile , io .Access .read_only ,
@@ -320,16 +343,15 @@ def __copy(self, src, dest, current_path="/data/"):
320343
321344
322345def main ():
323- args = parse_args (sys .argv [0 ])
324346 if not args .infile or not args .outfile :
325347 print ("Please specify parameters --infile and --outfile." )
326348 sys .exit (1 )
327- if (HAVE_MPI ):
328- run_pipe = pipe (args .infile , args .outfile , args .inconfig ,
329- args .outconfig , MPI .COMM_WORLD )
349+ if HAVE_MPI :
350+ communicator = MPI .COMM_WORLD
330351 else :
331- run_pipe = pipe (args .infile , args .outfile , args .inconfig ,
332- args .outconfig , FallbackMPICommunicator ())
352+ communicator = FallbackMPICommunicator ()
353+ run_pipe = pipe (args .infile , args .outfile , args .inconfig , args .outconfig ,
354+ communicator )
333355
334356 run_pipe .run ()
335357
0 commit comments