Skip to content

Commit c483791

Browse files
authored
Merge pull request #1372 from Libensemble/release/v_1.4.0
Release/v 1.4.0
2 parents 9f2f547 + fe7dc4b commit c483791

7 files changed

Lines changed: 115 additions & 76 deletions

File tree

.wci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ description: |
1616
language: Python
1717

1818
release:
19-
version: 1.3.0
20-
date: 2024-05-01
19+
version: 1.4.0
20+
date: 2024-07-25
2121

2222
documentation:
2323
general: https://libensemble.readthedocs.io

CHANGELOG.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,41 @@ GitHub issues are referenced, and can be viewed with hyperlinks on the `github r
88

99
.. _`github releases page`: https://github.com/Libensemble/libensemble/releases
1010

11+
Release 1.4.0
12+
--------------
13+
14+
:Date: July 25, 2024
15+
16+
* Add a ``live_data`` option for real-time data collection / plotting. #1310
17+
* ``nworkers``/``is_manager`` are set when ``Ensemble`` object is created. #1331/ #1336
18+
* This update locks the comms method when ``Ensemble`` object is created.
19+
* Add a ``group_size`` option to deal with unevenly resourced nodes. #1349
20+
* Bug fix: Fix shutdown hang on worker error when using ``gen_on_manager``. #1348
21+
* Bug fix: Log level was locked to ``INFO`` when using class interface.
22+
* Updated code to support ``numpy`` 2.0.
23+
24+
Documentation:
25+
26+
* Notebook examples with Colab links added to documentation. #1310
27+
* E.g., https://colab.research.google.com/github/Libensemble/libensemble/blob/develop/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb
28+
* Example of templating input files added to forces tutorial. #1310
29+
30+
Example user functions:
31+
32+
* Update ``gpCAM`` generators to work with latest interface.
33+
* Change ``one_d_func`` to ``norm_eval``. Works with multiple dimensions. #1352 / #1354
34+
35+
:Note:
36+
37+
* Tests were run on Linux and MacOS with Python versions 3.9, 3.10, 3.11, 3.12
38+
* Heterogeneous workflows tested on Frontier (OLCF), Polaris (ALCF), and Perlmutter (NERSC).
39+
* Note that tests have been recently run on Aurora (ALCF), but the system was unavailable at time of release.
40+
* Tests were also run on Bebop and Improv LCRC systems.
41+
42+
:Known Issues:
43+
44+
* See known issues section in the documentation.
45+
1146
Release 1.3.0
1247
--------------
1348

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ and an exit condition. Run the following four-worker example via ``python this_f
5959
6060
gen_specs = GenSpecs(
6161
gen_f=uniform_random_sample,
62-
outputs=[("x", float, (2,))],
62+
outputs=[("x", float, 2)],
6363
user={
6464
"gen_batch_size": 50,
6565
"lb": np.array([-3, -2]),

docs/running_libE.rst

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,13 @@ generator and simulator functions. Many :doc:`examples<examples/examples_index>`
2424
are available.
2525

2626
There are currently three communication options for libEnsemble (determining how
27-
the Manager and Workers communicate). These are ``mpi``, ``local``, ``tcp``.
28-
The default is ``mpi``.
27+
the Manager and Workers communicate). These are ``local``, ``mpi``, ``tcp``.
28+
The default is ``local`` if ``nworkers`` is specified, otherwise ``mpi``.
29+
30+
Note that ``local`` comms can be used on multi-node systems, where
31+
the :doc:`MPI executor<executor/overview>` is used to distribute MPI applications
32+
across the nodes. Indeed, this is the most commonly used option, even on large
33+
supercomputers.
2934

3035
.. note::
3136
You do not need the ``mpi`` communication mode to use the
@@ -34,38 +39,12 @@ The default is ``mpi``.
3439

3540
.. tab-set::
3641

37-
.. tab-item:: MPI Comms
38-
39-
This option uses mpi4py_ for the Manager/Worker communication. It is used automatically if
40-
you run your libEnsemble calling script with an MPI runner such as::
41-
42-
mpirun -np N python myscript.py
43-
44-
where ``N`` is the number of processes. This will launch one manager and
45-
``N-1`` workers.
46-
47-
This option requires ``mpi4py`` to be installed to interface with the MPI on your system.
48-
It works on a standalone system, and with both
49-
:doc:`central and distributed modes<platforms/platforms_index>` of running libEnsemble on
50-
multi-node systems.
51-
52-
It also potentially scales the best when running with many workers on HPC systems.
53-
54-
**Limitations of MPI mode**
55-
56-
If launching MPI applications from workers, then MPI is nested. **This is not
57-
supported with Open MPI**. This can be overcome by using a proxy launcher
58-
(see :doc:`Balsam<executor/balsam_2_executor>`). This nesting does work
59-
with MPICH_ and its derivative MPI implementations.
60-
61-
It is also unsuitable to use this mode when running on the **launch** nodes of
62-
three-tier systems (e.g., Summit). In that case ``local`` mode is recommended.
63-
6442
.. tab-item:: Local Comms
6543

6644
Uses Python's built-in multiprocessing_ module.
6745
The ``comms`` type ``local`` and number of workers ``nworkers`` may
6846
be provided in :ref:`libE_specs<datastruct-libe-specs>`.
47+
6948
Then run::
7049

7150
python myscript.py
@@ -78,12 +57,16 @@ The default is ``mpi``.
7857

7958
This will launch one manager and ``N`` workers.
8059

60+
The following abbreviated line is equivalent to the above::
61+
62+
python myscript.py -n N
63+
8164
libEnsemble will run on **one node** in this scenario. To
8265
:doc:`disallow this node<platforms/platforms_index>`
8366
from app-launches (if running libEnsemble on a compute node),
8467
set ``libE_specs["dedicated_mode"] = True``.
8568

86-
This mode is often used to run on a **launch** node of a three-tier
69+
This mode can also be used to run on a **launch** node of a three-tier
8770
system (e.g., Summit), ensuring the whole compute-node allocation is available for
8871
launching apps. Make sure there are no imports of ``mpi4py`` in your Python scripts.
8972

@@ -97,6 +80,33 @@ The default is ``mpi``.
9780
- In some scenarios, any import of ``mpi4py`` will cause this to break.
9881
- Does not have the potential scaling of MPI mode, but is sufficient for most users.
9982

83+
.. tab-item:: MPI Comms
84+
85+
This option uses mpi4py_ for the Manager/Worker communication. It is used automatically if
86+
you run your libEnsemble calling script with an MPI runner such as::
87+
88+
mpirun -np N python myscript.py
89+
90+
where ``N`` is the number of processes. This will launch one manager and
91+
``N-1`` workers.
92+
93+
This option requires ``mpi4py`` to be installed to interface with the MPI on your system.
94+
It works on a standalone system, and with both
95+
:doc:`central and distributed modes<platforms/platforms_index>` of running libEnsemble on
96+
multi-node systems.
97+
98+
It also potentially scales the best when running with many workers on HPC systems.
99+
100+
**Limitations of MPI mode**
101+
102+
If launching MPI applications from workers, then MPI is nested. **This is not
103+
supported with Open MPI**. This can be overcome by using a proxy launcher
104+
(see :doc:`Balsam<executor/balsam_2_executor>`). This nesting does work
105+
with MPICH_ and its derivative MPI implementations.
106+
107+
It is also unsuitable to use this mode when running on the **launch** nodes of
108+
three-tier systems (e.g., Summit). In that case ``local`` mode is recommended.
109+
100110
.. tab-item:: TCP Comms
101111

102112
Run the Manager on one system and launch workers to remote

examples/tutorials/forces_with_executor/forces_tutorial_notebook.ipynb

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@
181181
" task = exctr.submit(app_name=\"forces\", app_args=args, num_procs=1)\n",
182182
"\n",
183183
" # Block until the task finishes\n",
184-
" task.wait(timeout=60)\n",
184+
" task.wait()\n",
185185
"\n",
186186
" output, calc_status = read_output(sim_specs)\n",
187187
"\n",
@@ -232,11 +232,11 @@
232232
"import numpy as np\n",
233233
"from pprint import pprint\n",
234234
"\n",
235-
"# from forces_simf import run_forces # Sim func from current dir\n",
235+
"# from forces_simf import run_forces # Use is sim function is in a file\n",
236236
"\n",
237237
"from libensemble import Ensemble\n",
238+
"from libensemble.specs import ExitCriteria, GenSpecs, LibeSpecs, SimSpecs\n",
238239
"from libensemble.gen_funcs.sampling import uniform_random_sample\n",
239-
"from libensemble.tools import add_unique_random_streams\n",
240240
"from libensemble.executors import MPIExecutor\n",
241241
"\n",
242242
"# Initialize MPI Executor\n",
@@ -266,32 +266,27 @@
266266
"metadata": {},
267267
"outputs": [],
268268
"source": [
269-
"nworkers = 2\n",
270-
"\n",
271269
"# Global settings - including creating directories for each simulation\n",
272-
"libE_specs = {\n",
273-
" \"nworkers\": nworkers,\n",
274-
" \"comms\": \"local\",\n",
275-
" \"sim_dirs_make\": True,\n",
276-
"}\n",
277-
"\n",
278-
"# State the sim_f, inputs, outputs\n",
279-
"sim_specs = {\n",
280-
" \"sim_f\": run_forces,\n",
281-
" \"in\": [\"x\"], # Name of input for sim_f (defined in gen_specs[\"out\"])\n",
282-
" \"out\": [(\"energy\", float)],\n",
283-
"}\n",
284-
"\n",
285-
"# State the gen_f, inputs, outputs, additional parameters\n",
286-
"gen_specs = {\n",
287-
" \"gen_f\": uniform_random_sample,\n",
288-
" \"out\": [(\"x\", float, (1,))],\n",
289-
" \"user\": {\n",
270+
"libE_specs = LibeSpecs(\n",
271+
" nworkers=2,\n",
272+
" sim_dirs_make=True,\n",
273+
")\n",
274+
"\n",
275+
"gen_specs = GenSpecs(\n",
276+
" gen_f=uniform_random_sample,\n",
277+
" outputs=[(\"x\", float, (1,))],\n",
278+
" user={\n",
290279
" \"lb\": np.array([1000]), # min particles\n",
291280
" \"ub\": np.array([3000]), # max particles\n",
292281
" \"gen_batch_size\": 8,\n",
293282
" },\n",
294-
"}"
283+
")\n",
284+
"\n",
285+
"sim_specs = SimSpecs(\n",
286+
" sim_f=run_forces,\n",
287+
" inputs=[\"x\"], # Name of input for sim_f (defined in gen_specs.outputs)\n",
288+
" outputs=[(\"energy\", float)],\n",
289+
")"
295290
]
296291
},
297292
{
@@ -308,10 +303,7 @@
308303
"outputs": [],
309304
"source": [
310305
"# Instruct libEnsemble to exit after this many simulations\n",
311-
"exit_criteria = {\"sim_max\": 8}\n",
312-
"\n",
313-
"# Seed random streams for each worker, particularly for gen_f\n",
314-
"persis_info = add_unique_random_streams({}, nworkers + 1)\n",
306+
"exit_criteria = ExitCriteria(sim_max=8)\n",
315307
"\n",
316308
"# Initialize ensemble object, passing executor.\n",
317309
"ensemble = Ensemble(\n",
@@ -320,8 +312,10 @@
320312
" gen_specs=gen_specs,\n",
321313
" sim_specs=sim_specs,\n",
322314
" exit_criteria=exit_criteria,\n",
323-
" persis_info=persis_info,\n",
324-
")"
315+
")\n",
316+
"\n",
317+
"# Seed random streams for each worker, particularly for gen_f\n",
318+
"ensemble.add_random_streams()"
325319
]
326320
},
327321
{
@@ -559,19 +553,17 @@
559553
"input_file = \"forces_input\"\n",
560554
"\n",
561555
"# Add a field to libE_specs\n",
562-
"libE_specs[\"sim_dir_copy_files\"] = [input_file]\n",
563-
"ensemble.libE_specs = libE_specs\n",
564-
"\n",
565-
"ensemble.sim_specs = {\n",
566-
" \"sim_f\": run_forces_using_file,\n",
567-
" \"in\": [\"x\"], # Name of input for sim_f (defined in gen_specs[\"out\"])\n",
568-
" \"out\": [(\"energy\", float)],\n",
569-
" \"user\": {\"input_filename\": input_file, \"input_names\": [\"particles\"]},\n",
570-
"}\n",
556+
"ensemble.libE_specs.sim_dir_copy_files = [input_file]\n",
571557
"\n",
558+
"ensemble.sim_specs = SimSpecs(\n",
559+
" sim_f=run_forces_using_file,\n",
560+
" inputs=[\"x\"], # Name of input for sim_f (defined in gen_specs.outputs)\n",
561+
" outputs=[(\"energy\", float)],\n",
562+
" user={\"input_filename\": input_file, \"input_names\": [\"particles\"]},\n",
563+
")\n",
572564
"\n",
573565
"# To reset random number seed in the generator\n",
574-
"ensemble.persis_info = add_unique_random_streams({}, nworkers + 1)\n",
566+
"ensemble.add_random_streams()\n",
575567
"\n",
576568
"# Clean up any previous outputs and launch libEnsemble\n",
577569
"cleanup()\n",
@@ -595,7 +587,9 @@
595587
{
596588
"cell_type": "code",
597589
"execution_count": null,
598-
"metadata": {},
590+
"metadata": {
591+
"scrolled": false
592+
},
599593
"outputs": [],
600594
"source": [
601595
"! ls -l ensemble/sim*"

libensemble/tests/unit_tests/test_ensemble.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def test_ensemble_parse_args_false():
2222
from libensemble.ensemble import Ensemble
2323
from libensemble.specs import LibeSpecs
2424

25-
# Ensemble(parse_args=False) by default, so these specs wont be overwritten:
25+
# Ensemble(parse_args=False) by default, so these specs won't be overwritten:
2626
e = Ensemble(libE_specs={"comms": "local", "nworkers": 4})
2727
assert hasattr(e, "nworkers"), "nworkers should've passed from libE_specs to Ensemble class"
2828
assert isinstance(e.libE_specs, LibeSpecs), "libE_specs should've been cast to class"

libensemble/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "1.3.0+dev"
1+
__version__ = "1.4.0"

0 commit comments

Comments
 (0)