Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .wci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ description: |
language: Python

release:
version: 1.3.0
date: 2024-05-01
version: 1.4.0
date: 2024-07-25

documentation:
general: https://libensemble.readthedocs.io
Expand Down
35 changes: 35 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,41 @@ GitHub issues are referenced, and can be viewed with hyperlinks on the `github r

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

Release 1.4.0
--------------

:Date: July 25, 2024

* Add a ``live_data`` option for real-time data collection / plotting. #1310
* ``nworkers``/``is_manager`` are set when ``Ensemble`` object is created. #1331/ #1336
* This update locks the comms method when ``Ensemble`` object is created.
* Add a ``group_size`` option to deal with unevenly resourced nodes. #1349
* Bug fix: Fix shutdown hang on worker error when using ``gen_on_manager``. #1348
* Bug fix: Log level was locked to ``INFO`` when using class interface.
* Updated code to support ``numpy`` 2.0.

Documentation:

* Notebook examples with Colab links added to documentation. #1310
* E.g., https://colab.research.google.com/github/Libensemble/libensemble/blob/develop/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb
* Example of templating input files added to forces tutorial. #1310

Example user functions:

* Update ``gpCAM`` generators to work with latest interface.
* Change ``one_d_func`` to ``norm_eval``. Works with multiple dimensions. #1352 / #1354

:Note:

* Tests were run on Linux and MacOS with Python versions 3.9, 3.10, 3.11, 3.12
* Heterogeneous workflows tested on Frontier (OLCF), Polaris (ALCF), and Perlmutter (NERSC).
* Note that tests have been recently run on Aurora (ALCF), but the system was unavailable at time of release.
* Tests were also run on Bebop and Improv LCRC systems.

:Known Issues:

* See known issues section in the documentation.

Release 1.3.0
--------------

Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ and an exit condition. Run the following four-worker example via ``python this_f

gen_specs = GenSpecs(
gen_f=uniform_random_sample,
outputs=[("x", float, (2,))],
outputs=[("x", float, 2)],
user={
"gen_batch_size": 50,
"lb": np.array([-3, -2]),
Expand Down
70 changes: 40 additions & 30 deletions docs/running_libE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ generator and simulator functions. Many :doc:`examples<examples/examples_index>`
are available.

There are currently three communication options for libEnsemble (determining how
the Manager and Workers communicate). These are ``mpi``, ``local``, ``tcp``.
The default is ``mpi``.
the Manager and Workers communicate). These are ``local``, ``mpi``, ``tcp``.
The default is ``local`` if ``nworkers`` is specified, otherwise ``mpi``.

Note that ``local`` comms can be used on multi-node systems, where
the :doc:`MPI executor<executor/overview>` is used to distribute MPI applications
across the nodes. Indeed, this is the most commonly used option, even on large
supercomputers.

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

.. tab-set::

.. tab-item:: MPI Comms

This option uses mpi4py_ for the Manager/Worker communication. It is used automatically if
you run your libEnsemble calling script with an MPI runner such as::

mpirun -np N python myscript.py

where ``N`` is the number of processes. This will launch one manager and
``N-1`` workers.

This option requires ``mpi4py`` to be installed to interface with the MPI on your system.
It works on a standalone system, and with both
:doc:`central and distributed modes<platforms/platforms_index>` of running libEnsemble on
multi-node systems.

It also potentially scales the best when running with many workers on HPC systems.

**Limitations of MPI mode**

If launching MPI applications from workers, then MPI is nested. **This is not
supported with Open MPI**. This can be overcome by using a proxy launcher
(see :doc:`Balsam<executor/balsam_2_executor>`). This nesting does work
with MPICH_ and its derivative MPI implementations.

It is also unsuitable to use this mode when running on the **launch** nodes of
three-tier systems (e.g., Summit). In that case ``local`` mode is recommended.

.. tab-item:: Local Comms

Uses Python's built-in multiprocessing_ module.
The ``comms`` type ``local`` and number of workers ``nworkers`` may
be provided in :ref:`libE_specs<datastruct-libe-specs>`.

Then run::

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

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

The following abbreviated line is equivalent to the above::

python myscript.py -n N

libEnsemble will run on **one node** in this scenario. To
:doc:`disallow this node<platforms/platforms_index>`
from app-launches (if running libEnsemble on a compute node),
set ``libE_specs["dedicated_mode"] = True``.

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

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

.. tab-item:: MPI Comms

This option uses mpi4py_ for the Manager/Worker communication. It is used automatically if
you run your libEnsemble calling script with an MPI runner such as::

mpirun -np N python myscript.py

where ``N`` is the number of processes. This will launch one manager and
``N-1`` workers.

This option requires ``mpi4py`` to be installed to interface with the MPI on your system.
It works on a standalone system, and with both
:doc:`central and distributed modes<platforms/platforms_index>` of running libEnsemble on
multi-node systems.

It also potentially scales the best when running with many workers on HPC systems.

**Limitations of MPI mode**

If launching MPI applications from workers, then MPI is nested. **This is not
supported with Open MPI**. This can be overcome by using a proxy launcher
(see :doc:`Balsam<executor/balsam_2_executor>`). This nesting does work
with MPICH_ and its derivative MPI implementations.

It is also unsuitable to use this mode when running on the **launch** nodes of
three-tier systems (e.g., Summit). In that case ``local`` mode is recommended.

.. tab-item:: TCP Comms

Run the Manager on one system and launch workers to remote
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@
" task = exctr.submit(app_name=\"forces\", app_args=args, num_procs=1)\n",
"\n",
" # Block until the task finishes\n",
" task.wait(timeout=60)\n",
" task.wait()\n",
"\n",
" output, calc_status = read_output(sim_specs)\n",
"\n",
Expand Down Expand Up @@ -232,11 +232,11 @@
"import numpy as np\n",
"from pprint import pprint\n",
"\n",
"# from forces_simf import run_forces # Sim func from current dir\n",
"# from forces_simf import run_forces # Use is sim function is in a file\n",
"\n",
"from libensemble import Ensemble\n",
"from libensemble.specs import ExitCriteria, GenSpecs, LibeSpecs, SimSpecs\n",
"from libensemble.gen_funcs.sampling import uniform_random_sample\n",
"from libensemble.tools import add_unique_random_streams\n",
"from libensemble.executors import MPIExecutor\n",
"\n",
"# Initialize MPI Executor\n",
Expand Down Expand Up @@ -266,32 +266,27 @@
"metadata": {},
"outputs": [],
"source": [
"nworkers = 2\n",
"\n",
"# Global settings - including creating directories for each simulation\n",
"libE_specs = {\n",
" \"nworkers\": nworkers,\n",
" \"comms\": \"local\",\n",
" \"sim_dirs_make\": True,\n",
"}\n",
"\n",
"# State the sim_f, inputs, outputs\n",
"sim_specs = {\n",
" \"sim_f\": run_forces,\n",
" \"in\": [\"x\"], # Name of input for sim_f (defined in gen_specs[\"out\"])\n",
" \"out\": [(\"energy\", float)],\n",
"}\n",
"\n",
"# State the gen_f, inputs, outputs, additional parameters\n",
"gen_specs = {\n",
" \"gen_f\": uniform_random_sample,\n",
" \"out\": [(\"x\", float, (1,))],\n",
" \"user\": {\n",
"libE_specs = LibeSpecs(\n",
" nworkers=2,\n",
" sim_dirs_make=True,\n",
")\n",
"\n",
"gen_specs = GenSpecs(\n",
" gen_f=uniform_random_sample,\n",
" outputs=[(\"x\", float, (1,))],\n",
" user={\n",
" \"lb\": np.array([1000]), # min particles\n",
" \"ub\": np.array([3000]), # max particles\n",
" \"gen_batch_size\": 8,\n",
" },\n",
"}"
")\n",
"\n",
"sim_specs = SimSpecs(\n",
" sim_f=run_forces,\n",
" inputs=[\"x\"], # Name of input for sim_f (defined in gen_specs.outputs)\n",
" outputs=[(\"energy\", float)],\n",
")"
]
},
{
Expand All @@ -308,10 +303,7 @@
"outputs": [],
"source": [
"# Instruct libEnsemble to exit after this many simulations\n",
"exit_criteria = {\"sim_max\": 8}\n",
"\n",
"# Seed random streams for each worker, particularly for gen_f\n",
"persis_info = add_unique_random_streams({}, nworkers + 1)\n",
"exit_criteria = ExitCriteria(sim_max=8)\n",
"\n",
"# Initialize ensemble object, passing executor.\n",
"ensemble = Ensemble(\n",
Expand All @@ -320,8 +312,10 @@
" gen_specs=gen_specs,\n",
" sim_specs=sim_specs,\n",
" exit_criteria=exit_criteria,\n",
" persis_info=persis_info,\n",
")"
")\n",
"\n",
"# Seed random streams for each worker, particularly for gen_f\n",
"ensemble.add_random_streams()"
]
},
{
Expand Down Expand Up @@ -559,19 +553,17 @@
"input_file = \"forces_input\"\n",
"\n",
"# Add a field to libE_specs\n",
"libE_specs[\"sim_dir_copy_files\"] = [input_file]\n",
"ensemble.libE_specs = libE_specs\n",
"\n",
"ensemble.sim_specs = {\n",
" \"sim_f\": run_forces_using_file,\n",
" \"in\": [\"x\"], # Name of input for sim_f (defined in gen_specs[\"out\"])\n",
" \"out\": [(\"energy\", float)],\n",
" \"user\": {\"input_filename\": input_file, \"input_names\": [\"particles\"]},\n",
"}\n",
"ensemble.libE_specs.sim_dir_copy_files = [input_file]\n",
"\n",
"ensemble.sim_specs = SimSpecs(\n",
" sim_f=run_forces_using_file,\n",
" inputs=[\"x\"], # Name of input for sim_f (defined in gen_specs.outputs)\n",
" outputs=[(\"energy\", float)],\n",
" user={\"input_filename\": input_file, \"input_names\": [\"particles\"]},\n",
")\n",
"\n",
"# To reset random number seed in the generator\n",
"ensemble.persis_info = add_unique_random_streams({}, nworkers + 1)\n",
"ensemble.add_random_streams()\n",
"\n",
"# Clean up any previous outputs and launch libEnsemble\n",
"cleanup()\n",
Expand All @@ -595,7 +587,9 @@
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"! ls -l ensemble/sim*"
Expand Down
2 changes: 1 addition & 1 deletion libensemble/tests/unit_tests/test_ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_ensemble_parse_args_false():
from libensemble.ensemble import Ensemble
from libensemble.specs import LibeSpecs

# Ensemble(parse_args=False) by default, so these specs wont be overwritten:
# Ensemble(parse_args=False) by default, so these specs won't be overwritten:
e = Ensemble(libE_specs={"comms": "local", "nworkers": 4})
assert hasattr(e, "nworkers"), "nworkers should've passed from libE_specs to Ensemble class"
assert isinstance(e.libE_specs, LibeSpecs), "libE_specs should've been cast to class"
Expand Down
2 changes: 1 addition & 1 deletion libensemble/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.3.0+dev"
__version__ = "1.4.0"