Skip to content

Commit 3fc5d46

Browse files
committed
fixes to MPI calling scripts in simple tutorial, and corresponding example calling script
1 parent ade68f1 commit 3fc5d46

2 files changed

Lines changed: 58 additions & 57 deletions

File tree

docs/tutorials/local_sine_tutorial.rst

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ need to write a new allocation function.
3636
If your system doesn't allow you to perform these installations, try adding
3737
``--user`` to the end of each command.
3838

39-
.. _NumPy: https://www.numpy.org/
40-
.. _Matplotlib: https://matplotlib.org/
4139

4240
.. tab-item:: 2. Generator
4341

@@ -385,37 +383,41 @@ need to write a new allocation function.
385383

386384
**Modifying the script**
387385

388-
Only a few changes are necessary to make our code MPI-compatible. Note the following:
386+
Only a few changes are necessary to make our code MPI-compatible. For starters,
387+
comment out the ``libE_specs`` definition:
389388

390389
.. code-block:: python
391390
:linenos:
392391
:lineno-start: 7
393392
394-
libE_specs = LibeSpecs() # class will autodetect MPI runtime
393+
# libE_specs = LibeSpecs(nworkers=4, comms="local")
395394
396-
So that only one process executes the graphing and printing portion of our code,
397-
modify the bottom of the calling script like this:
395+
We'll be parameterizing our MPI runtime with a ``parse_args=True`` argument to
396+
the ``Ensemble`` class instead of ``libE_specs``. We'll also use an ``ensemble.is_manager``
397+
attribute so only the first MPI rank runs the data-processing code.
398+
399+
The bottom of your calling script should now resemble:
398400

399401
.. code-block:: python
400402
:linenos:
401-
:lineno-start: 27
403+
:lineno-start: 28
404+
405+
# replace libE_specs with parse_args=True. Detects MPI runtime
406+
ensemble = Ensemble(sim_specs, gen_specs, exit_criteria, parse_args=True)
402407
403-
ensemble = Ensemble(sim_specs, gen_specs, exit_criteria, libE_specs)
404408
ensemble.add_random_streams()
409+
405410
if __name__ == "__main__":
406-
ensemble.run()
407411
408-
if ensemble.is_manager: # only True on rank 0
409-
H = ensemble.H
410-
print([i for i in H.dtype.fields])
411-
print(H)
412+
ensemble.run() # start the ensemble. Blocks until completion.
412413
413-
import matplotlib.pyplot as plt
414+
if ensemble.is_manager: # only True on rank 0
415+
history = ensemble.H # start visualizing our results
414416
415417
colors = ["b", "g", "r", "y", "m", "c", "k", "w"]
416418
417-
for i in range(1, nworkers + 1):
418-
worker_xy = np.extract(H["sim_worker"] == i, H)
419+
for i in range(1, ensemble.nworkers + 1):
420+
worker_xy = np.extract(history["sim_worker"] == i, history)
419421
x = [entry.tolist()[0] for entry in worker_xy["x"]]
420422
y = [entry for entry in worker_xy["y"]]
421423
plt.scatter(x, y, label="Worker {}".format(i), c=colors[i - 1])
@@ -448,8 +450,10 @@ need to write a new allocation function.
448450
libEnsemble use-case within our
449451
:doc:`Electrostatic Forces tutorial <./executor_forces_tutorial>`.
450452

453+
.. _Matplotlib: https://matplotlib.org/
451454
.. _MPI: https://en.wikipedia.org/wiki/Message_Passing_Interface
452455
.. _MPICH: https://www.mpich.org/
453456
.. _mpi4py: https://mpi4py.readthedocs.io/en/stable/install.html
457+
.. _NumPy: https://www.numpy.org/
454458
.. _here: https://www.mpich.org/downloads/
455459
.. _examples/tutorials/simple_sine: https://github.com/Libensemble/libensemble/tree/develop/examples/tutorials/simple_sine
Lines changed: 38 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,52 @@
11
import matplotlib.pyplot as plt
22
import numpy as np
3-
from mpi4py import MPI
4-
from tutorial_gen import gen_random_sample
5-
from tutorial_sim import sim_find_sine
3+
from gen import gen_random_sample
4+
from sim import sim_find_sine
65

7-
from libensemble.libE import libE
8-
from libensemble.tools import add_unique_random_streams
6+
from libensemble import Ensemble
7+
from libensemble.specs import ExitCriteria, GenSpecs, SimSpecs
98

10-
libE_specs = {"comms": "mpi"} # 'nworkers' removed, 'comms' now 'mpi'
9+
# libE_specs = LibeSpecs(nworkers=4, comms="local")
1110

12-
nworkers = MPI.COMM_WORLD.Get_size() - 1 # one process belongs to manager
13-
is_manager = MPI.COMM_WORLD.Get_rank() == 0 # manager process has MPI rank 0
14-
15-
gen_specs = {
16-
"gen_f": gen_random_sample, # Our generator function
17-
"out": [("x", float, (1,))], # gen_f output (name, type, size).
18-
"user": {
19-
"lower": np.array([-3]), # random sampling lower bound
20-
"upper": np.array([3]), # random sampling upper bound
21-
"gen_batch_size": 5, # number of values gen_f will generate per call
11+
gen_specs = GenSpecs(
12+
gen_f=gen_random_sample, # Our generator function
13+
out=[("x", float, (1,))], # gen_f output (name, type, size)
14+
user={
15+
"lower": np.array([-3]), # lower boundary for random sampling
16+
"upper": np.array([3]), # upper boundary for random sampling
17+
"gen_batch_size": 5, # number of x's gen_f generates per call
2218
},
23-
}
19+
)
20+
21+
sim_specs = SimSpecs(
22+
sim_f=sim_find_sine, # Our simulator function
23+
inputs=["x"], # Input field names. "x" from gen_f output
24+
out=[("y", float)], # sim_f output. "y" = sine("x")
25+
)
26+
27+
exit_criteria = ExitCriteria(sim_max=80) # Stop libEnsemble after 80 simulations
2428

25-
sim_specs = {
26-
"sim_f": sim_find_sine, # Our simulator function
27-
"in": ["x"], # Input field names. 'x' from gen_f output
28-
"out": [("y", float)], # sim_f output. 'y' = sine('x')
29-
}
29+
ensemble = Ensemble(sim_specs, gen_specs, exit_criteria, parse_args=True)
3030

31-
persis_info = add_unique_random_streams({}, nworkers + 1) # Initialize manager/workers random streams
31+
ensemble.add_random_streams() # setup the random streams unique to each worker
3232

33-
exit_criteria = {"sim_max": 80} # Stop libEnsemble after 80 simulations
33+
if __name__ == "__main__":
3434

35-
H, persis_info, flag = libE(sim_specs, gen_specs, exit_criteria, persis_info, libE_specs=libE_specs)
35+
ensemble.run() # start the ensemble. Blocks until completion.
3636

37-
# Some (optional) statements to visualize our History array
38-
# Only the manager process should execute this
39-
if is_manager:
40-
print([i for i in H.dtype.fields])
41-
print(H)
37+
if ensemble.is_manager: # only True on rank 0
38+
history = ensemble.H # start visualizing our results
4239

43-
colors = ["b", "g", "r", "y", "m", "c", "k", "w"]
40+
colors = ["b", "g", "r", "y", "m", "c", "k", "w"]
4441

45-
for i in range(1, nworkers + 1):
46-
worker_xy = np.extract(H["sim_worker"] == i, H)
47-
x = [entry.tolist()[0] for entry in worker_xy["x"]]
48-
y = [entry for entry in worker_xy["y"]]
49-
plt.scatter(x, y, label=f"Worker {i}", c=colors[i - 1])
42+
for i in range(1, ensemble.nworkers + 1):
43+
worker_xy = np.extract(history["sim_worker"] == i, history)
44+
x = [entry.tolist()[0] for entry in worker_xy["x"]]
45+
y = [entry for entry in worker_xy["y"]]
46+
plt.scatter(x, y, label="Worker {}".format(i), c=colors[i - 1])
5047

51-
plt.title("Sine calculations for a uniformly sampled random distribution")
52-
plt.xlabel("x")
53-
plt.ylabel("sine(x)")
54-
plt.legend(loc="lower right")
55-
plt.savefig("tutorial_sines.png")
48+
plt.title("Sine calculations for a uniformly sampled random distribution")
49+
plt.xlabel("x")
50+
plt.ylabel("sine(x)")
51+
plt.legend(loc="lower right")
52+
plt.savefig("tutorial_sines.png")

0 commit comments

Comments
 (0)