From 5966164bef06a5a336fcd6397ee3153dbc90373d Mon Sep 17 00:00:00 2001 From: shudson Date: Mon, 7 Apr 2025 17:35:35 -0500 Subject: [PATCH 01/31] Add release notes for v1.5.0 --- CHANGELOG.rst | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b81a395af8..b827dc3d68 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,45 @@ 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.5.0 +-------------- + +:Date: Apr 8, 2025 + +General Updates: + +* Migrate package build system to `pyproject.toml` (with `pixi` support). #1459 +* Improve handling when no MPI found. #1514 +* `ensemble.save_output()` can save without appending attributes `append_attrs=False`. #1531 +* Improved handling of worker-specific `persis_info` fields when they are not initially provided. #1531 + * Bugfix: Fix `final_gen_send` when there are no worker-specific `persis_info` fields. + * Handle worker-generated `persis_info` fields. + * Ensure `persis_info` is initialized to an empty dictionary in user functions instead of None. + +Examples: + +* Update Ax generator for `Ax v0.5.0`. #1508 +* gpCAM generators renamed. #1516 + * `persistent_gpCAM_ask_tell` to `persistent_gpCAM` + * `persistent_gpCAM_simple` to `persistent_gpCAM_covar` (in fact less simple) +* Persistent generators return `None` as first return value unless `H_o` is updated. #1515 + +Documentation: + +* Revamped Examples and HPC section of documentation. #1501, #1536, #1539 +* Added tutorial and notebook demonstrating surrogate model creation with gpCAM. #1531 +* Updated Aurora guide. #1510 +* Updated and documented APOSMM/WarpX example. #1543 + +:Note: + +* Tests were run on Linux and MacOS with Python versions 3.10, 3.11, 3.12, 3.13 +* Heterogeneous workflows tested on Aurora (ALCF), Polaris (ALCF), and Perlmutter (NERSC). + +:Known Issues: + +* See known issues section in the documentation. + Release 1.4.3 -------------- From 31a60692ab60a7d41b19af3b799732813a6c41b9 Mon Sep 17 00:00:00 2001 From: shudson Date: Mon, 7 Apr 2025 17:41:44 -0500 Subject: [PATCH 02/31] Update version and year --- .wci.yml | 4 ++-- LICENSE | 2 +- libensemble/version.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.wci.yml b/.wci.yml index 78b37075ff..af395fb9af 100644 --- a/.wci.yml +++ b/.wci.yml @@ -16,8 +16,8 @@ description: | language: Python release: - version: 1.4.3 - date: 2024-12-16 + version: 1.5.0 + date: 2025-04-08 documentation: general: https://libensemble.readthedocs.io diff --git a/LICENSE b/LICENSE index de0d1ca0ea..6a45c6a4cf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ BSD 3-Clause License -Copyright (c) 2018-2024, UChicago Argonne, LLC and the libEnsemble Development Team +Copyright (c) 2018-2025, UChicago Argonne, LLC and the libEnsemble Development Team All Rights Reserved. Redistribution and use in source and binary forms, with or without diff --git a/libensemble/version.py b/libensemble/version.py index a5467c834a..5b60188613 100644 --- a/libensemble/version.py +++ b/libensemble/version.py @@ -1 +1 @@ -__version__ = "1.4.3+dev" +__version__ = "1.5.0" From 2dc5b4e9909a04367343ccba382637021ef8a0b3 Mon Sep 17 00:00:00 2001 From: shudson Date: Mon, 7 Apr 2025 18:06:41 -0500 Subject: [PATCH 03/31] Use present tense in release notes --- CHANGELOG.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b827dc3d68..9ff1a6c209 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -18,7 +18,7 @@ General Updates: * Migrate package build system to `pyproject.toml` (with `pixi` support). #1459 * Improve handling when no MPI found. #1514 * `ensemble.save_output()` can save without appending attributes `append_attrs=False`. #1531 -* Improved handling of worker-specific `persis_info` fields when they are not initially provided. #1531 +* Improve handling of worker-specific `persis_info` fields when they are not initially provided. #1531 * Bugfix: Fix `final_gen_send` when there are no worker-specific `persis_info` fields. * Handle worker-generated `persis_info` fields. * Ensure `persis_info` is initialized to an empty dictionary in user functions instead of None. @@ -26,17 +26,17 @@ General Updates: Examples: * Update Ax generator for `Ax v0.5.0`. #1508 -* gpCAM generators renamed. #1516 +* Rename gpCAM generators. #1516 * `persistent_gpCAM_ask_tell` to `persistent_gpCAM` * `persistent_gpCAM_simple` to `persistent_gpCAM_covar` (in fact less simple) * Persistent generators return `None` as first return value unless `H_o` is updated. #1515 Documentation: -* Revamped Examples and HPC section of documentation. #1501, #1536, #1539 -* Added tutorial and notebook demonstrating surrogate model creation with gpCAM. #1531 -* Updated Aurora guide. #1510 -* Updated and documented APOSMM/WarpX example. #1543 +* Revamp Examples and HPC section of documentation. #1501, #1536, #1539 +* Add tutorial and notebook demonstrating surrogate model creation with gpCAM. #1531 +* Update Aurora guide. #1510 +* Update and documented APOSMM/WarpX example. #1543 :Note: From 178253b4010fcc392a0b075884311e70ed593f2e Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 8 Apr 2025 11:03:19 -0500 Subject: [PATCH 04/31] Edit docstring --- .../test_persistent_aposmm_ibcdfo_pounders.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders.py b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders.py index cf7d611547..7523704a0b 100644 --- a/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders.py +++ b/libensemble/tests/regression_tests/test_persistent_aposmm_ibcdfo_pounders.py @@ -14,9 +14,9 @@ These values are then mapped to the normalized emittance - . Execute via one of the following commands: - mpiexec -np 3 python test_persistent_aposmm_ibcdfo.py - python test_persistent_aposmm_ibcdfo.py --nworkers 2 -Both will run with 1 manager, 1 worker running APOSMM+IBCDFO), and 1 worker + mpiexec -np 3 python test_persistent_aposmm_ibcdfo_pounders.py + python test_persistent_aposmm_ibcdfo_pounders.py --nworkers 2 +Both will run with 1 manager, 1 worker running APOSMM+IBCDFO, and 1 worker doing the simulation evaluations. """ From 36f98a605a26dbc96f7541b470cf93569ca03b28 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 8 Apr 2025 11:05:21 -0500 Subject: [PATCH 05/31] Whitespace --- docs/examples/sim_funcs.rst | 4 ++-- docs/examples/sim_funcs/forces_simf_gpu.rst | 2 +- docs/platforms/example_scripts.rst | 2 -- docs/platforms/platforms_index.rst | 10 ---------- docs/tutorials/forces_gpu_tutorial.rst | 2 -- .../bebop_submit_pbs_central.sh | 1 - 6 files changed, 3 insertions(+), 18 deletions(-) diff --git a/docs/examples/sim_funcs.rst b/docs/examples/sim_funcs.rst index 3cdf8bdc11..dad2609049 100644 --- a/docs/examples/sim_funcs.rst +++ b/docs/examples/sim_funcs.rst @@ -36,8 +36,8 @@ Functions that run user applications These use the executor to launch applications and in some cases handle dynamic CPU/GPU allocation. -The ``Variable resources`` module contains basic examples, while the ``Template`` -examples use a simple MPI/OpenMP (with GPU offload option) application (``forces``) +The ``Variable resources`` module contains basic examples, while the ``Template`` +examples use a simple MPI/OpenMP (with GPU offload option) application (``forces``) to demonstrate libEnsemble’s capabilities on various HPC systems. The build_forces.sh_ file gives compile lines for building the simple ``forces`` application on various platforms (use -DGPU to build for GPU). diff --git a/docs/examples/sim_funcs/forces_simf_gpu.rst b/docs/examples/sim_funcs/forces_simf_gpu.rst index 38cb8630e8..4c74d254f1 100644 --- a/docs/examples/sim_funcs/forces_simf_gpu.rst +++ b/docs/examples/sim_funcs/forces_simf_gpu.rst @@ -1,4 +1,4 @@ -Template for GPU executables +Template for GPU executables ---------------------------- .. role:: underline diff --git a/docs/platforms/example_scripts.rst b/docs/platforms/example_scripts.rst index 072cc65f22..24da78afc8 100644 --- a/docs/platforms/example_scripts.rst +++ b/docs/platforms/example_scripts.rst @@ -18,7 +18,6 @@ for more information about the respective systems and configuration. or, if using dynamic resources, :doc:`in the generator<../examples/sim_funcs/forces_simf_gpu_vary_resources>`. - General examples ---------------- @@ -43,7 +42,6 @@ LSF - Basic :caption: /examples/libE_submission_scripts/submit_lsf_simple.sh :language: bash - System Examples --------------- diff --git a/docs/platforms/platforms_index.rst b/docs/platforms/platforms_index.rst index c56ab66aa9..a08a823dc8 100644 --- a/docs/platforms/platforms_index.rst +++ b/docs/platforms/platforms_index.rst @@ -46,14 +46,12 @@ which runs the generator on the manager (using a thread) as below. A SLURM batch script may include: - .. code-block:: bash #SBATCH --nodes 3 python run_libe_forces.py --nworkers 3 - When using **gen_on_manager**, set ``nworkers`` to the number of workers desired for running simulations. Dedicated Mode @@ -64,7 +62,6 @@ True, the MPI executor will not launch applications on nodes where libEnsemble P processes (manager and workers) are running. Workers launch applications onto the remaining nodes in the allocation. - .. list-table:: :widths: 60 40 @@ -84,14 +81,12 @@ remaining nodes in the allocation. A SLURM batch script may include: - .. code-block:: bash #SBATCH --nodes 3 python run_libe_forces.py --nworkers 3 - Note that **gen_on_manager** is not set in the above example. Distributed Running @@ -116,7 +111,6 @@ case, requires :ref:`a careful MPI rank placement `. This allows the libEnsemble worker to read files produced by the application on local node storage. - Configuring the Run ------------------- @@ -159,7 +153,6 @@ Varying resources libEnsemble also features :ref:`dynamic resource assignment`, whereby the number of processes and/or the number of GPUs can be a set for each simulation by the generator. - Overriding Auto-Detection ------------------------- @@ -172,8 +165,6 @@ libE_specs option. When using the MPI Executor, it is possible to override the detected information using the `custom_info` argument. See the :doc:`MPI Executor<../executor/mpi_executor>` for more. - - Systems with Launch/MOM Nodes ----------------------------- @@ -212,7 +203,6 @@ or *to entirely different systems*. Submission scripts for running on launch/MOM nodes and for using Balsam can be found in the :doc:`examples`. - .. _globus_compute_ref: Globus Compute - Remote User Functions diff --git a/docs/tutorials/forces_gpu_tutorial.rst b/docs/tutorials/forces_gpu_tutorial.rst index ab1ee121fc..870b634648 100644 --- a/docs/tutorials/forces_gpu_tutorial.rst +++ b/docs/tutorials/forces_gpu_tutorial.rst @@ -35,7 +35,6 @@ from the simple forces example are highlighted: # Optional - to print GPU settings from libensemble.tools.test_support import check_gpu_setting - def run_forces(H, persis_info, sim_specs, libE_info): """Launches the forces MPI app and auto-assigns ranks and GPU resources. @@ -154,7 +153,6 @@ and use this information however you want. output = np.zeros(1, dtype=sim_specs["out"]) output["energy"][0] = final_energy - return output The above code will assign a GPU to each worker on CUDA-capable systems, diff --git a/examples/libE_submission_scripts/bebop_submit_pbs_central.sh b/examples/libE_submission_scripts/bebop_submit_pbs_central.sh index 4d0aff5894..7fb474194f 100644 --- a/examples/libE_submission_scripts/bebop_submit_pbs_central.sh +++ b/examples/libE_submission_scripts/bebop_submit_pbs_central.sh @@ -5,7 +5,6 @@ #PBS -A [project] #PBS -N libE_example - cd $PBS_O_WORKDIR # Choose MPI backend. Note that the built mpi4py in your environment should match. module load oneapi/mpi From c37db76ddf71e95bb7ab58ae3c0ccad5940af13e Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 8 Apr 2025 11:13:49 -0500 Subject: [PATCH 06/31] Underlines too short --- docs/tutorials/gpcam_tutorial.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/gpcam_tutorial.rst b/docs/tutorials/gpcam_tutorial.rst index 09b523c7a3..a013c1b67e 100644 --- a/docs/tutorials/gpcam_tutorial.rst +++ b/docs/tutorials/gpcam_tutorial.rst @@ -10,7 +10,7 @@ In each iteration, a batch of points is produced for concurrent evaluation, maxi Ensure that libEnsemble, and gpCAM are installed via: ``pip install libensemble gpcam`` Generator function ------------------ +------------------ The gpCAM generator function is called ``persistent_gpCAM``. @@ -179,7 +179,7 @@ For running applications using parallel resources in the simulator see the `forc return term1 + term2 + term3 Calling Script -------------- +-------------- Our calling script configures libEnsemble, the generator function, and the simulator function. It then create the ensemble object and runs the ensemble. @@ -275,7 +275,7 @@ At the end of our calling script we run the ensemble. pprint(H[["sim_id", "x", "f"]][:16]) # See first 16 results Rerun and test model at known points ------------------------------------ +------------------------------------ To see how the accuracy of the surrogate model improves, we can use previously evaluated points as test points and run again with a different seed. @@ -292,7 +292,7 @@ To see how the accuracy of the surrogate model improves, we can use previously e print(persis_info) Viewing model progression ------------------------- +------------------------- Now we can check how our model's values compared against the values at known test points as the ensemble progresses. The comparison is based on the **mean squared error** between the gpCAM model and our known From d9a91c7ef1145899f393b1e39c45b3d9a19b95b7 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 8 Apr 2025 11:15:04 -0500 Subject: [PATCH 07/31] Replacing ~ with - --- docs/platforms/platforms_index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/platforms/platforms_index.rst b/docs/platforms/platforms_index.rst index a08a823dc8..15563cdf79 100644 --- a/docs/platforms/platforms_index.rst +++ b/docs/platforms/platforms_index.rst @@ -134,7 +134,7 @@ and partitions these to workers. The :doc:`MPI Executor<../executor/mpi_executor accesses the resources available to the current worker when launching tasks. Zero-resource workers -~~~~~~~~~~~~~~~~~~~~~ +--------------------- Users with persistent ``gen_f`` functions may notice that the persistent workers are still automatically assigned system resources. This can be resolved by using From 165c668c3473add3a273475a395913ec8362392d Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 8 Apr 2025 11:35:23 -0500 Subject: [PATCH 08/31] Link update --- docs/examples/sim_funcs/forces_simf_gpu_multi_app.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/examples/sim_funcs/forces_simf_gpu_multi_app.rst b/docs/examples/sim_funcs/forces_simf_gpu_multi_app.rst index a190e99fea..8a491e8816 100644 --- a/docs/examples/sim_funcs/forces_simf_gpu_multi_app.rst +++ b/docs/examples/sim_funcs/forces_simf_gpu_multi_app.rst @@ -10,7 +10,7 @@ ranks and GPU resources as requested by the generator. This makes efficient use of each node as the expensive GPU simulations will use the GPUs on the node/s, while the rest of the CPU cores are assigned to the simple CPU-only simulations. -For a realistic use-case see https://journals.aps.org/prab/abstract/10.1103/PhysRevAccelBeams.26.084601 +See this publication_ for a real-world demonstration of these capabilities. .. automodule:: forces_multi_app.forces_simf :members: @@ -39,5 +39,6 @@ up by each worker and these will be used when the simulation is run, unless over More information is available in the :doc:`Forces GPU tutorial <../../tutorials/forces_gpu_tutorial>` and the video_ demonstration on Frontier_. -.. _video: https://www.youtube.com/watch?v=H2fmbZ6DnVc .. _Frontier: https://docs.olcf.ornl.gov/systems/frontier_user_guide.html +.. _publication: https://doi.org/10.1103/PhysRevAccelBeams.26.084601 +.. _video: https://www.youtube.com/watch?v=H2fmbZ6DnVc From c9ca535b82e28a9c804e1d39b867bfc502ad33fb Mon Sep 17 00:00:00 2001 From: shudson Date: Tue, 8 Apr 2025 11:48:34 -0500 Subject: [PATCH 09/31] Bypass label in include --- docs/examples/submission_scripts.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/examples/submission_scripts.rst b/docs/examples/submission_scripts.rst index 1f853585b5..7c37da40ea 100644 --- a/docs/examples/submission_scripts.rst +++ b/docs/examples/submission_scripts.rst @@ -1 +1,5 @@ .. include:: ../platforms/example_scripts.rst + :end-before: .. _slurm_mpi_distributed: + +.. include:: ../platforms/example_scripts.rst + :start-after: .. _slurm_mpi_distributed: From 71fa984a1de9be32253d9cd42151a8ca606f3665 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 8 Apr 2025 11:58:50 -0500 Subject: [PATCH 10/31] More docs edits --- docs/examples/sim_funcs.rst | 4 ++-- docs/platforms/example_scripts.rst | 6 +++--- docs/platforms/platforms_index.rst | 10 +++++----- docs/resource_manager/resource_detection.rst | 8 ++++---- docs/resource_manager/zero_resource_workers.rst | 2 +- docs/tutorials/forces_gpu_tutorial.rst | 4 ++-- libensemble/gen_funcs/persistent_gpCAM.py | 6 +++--- libensemble/tests/regression_tests/test_gpCAM.py | 2 +- .../test_persistent_gp_multitask_ax.py | 2 +- 9 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/examples/sim_funcs.rst b/docs/examples/sim_funcs.rst index dad2609049..be4374d884 100644 --- a/docs/examples/sim_funcs.rst +++ b/docs/examples/sim_funcs.rst @@ -24,7 +24,7 @@ Ideal for simple debugging of generator processes or system testing. Borehole function with kills Chwirut1 vector-valued function Inverse Bayesian likelihood - Norm + Norm Rosenbrock test optimization function Six Hump Camel Test noisy function @@ -37,7 +37,7 @@ These use the executor to launch applications and in some cases handle dynamic CPU/GPU allocation. The ``Variable resources`` module contains basic examples, while the ``Template`` -examples use a simple MPI/OpenMP (with GPU offload option) application (``forces``) +examples use a simple MPI/OpenMP (with GPU offload option) application (``forces``) to demonstrate libEnsemble’s capabilities on various HPC systems. The build_forces.sh_ file gives compile lines for building the simple ``forces`` application on various platforms (use -DGPU to build for GPU). diff --git a/docs/platforms/example_scripts.rst b/docs/platforms/example_scripts.rst index 24da78afc8..d534f0c662 100644 --- a/docs/platforms/example_scripts.rst +++ b/docs/platforms/example_scripts.rst @@ -7,12 +7,12 @@ for more information about the respective systems and configuration. .. note:: It is **highly recommended** that the directive lines (e.g., #SBATCH) in batch - submission scripts do **NOT** specify processor, task, or GPU configuration info - --- these lines should only specify the number of nodes required. + submission scripts do **NOT** specify processor, task, or GPU configuration + information---these lines should only specify the number of nodes required. For example, do not specify ``#SBATCH --gpus-per-node=4`` in order to use four GPUs on the node, when each worker may use less than this, as this may assign - all of the GPUs to a single MPI invocation. Instead, the configuration should + all of the GPUs to a single MPI invocation. Instead, the configuration should be supplied either :doc:`in the simulation function<../examples/sim_funcs/forces_simf_gpu>` or, if using dynamic resources, diff --git a/docs/platforms/platforms_index.rst b/docs/platforms/platforms_index.rst index 15563cdf79..c06cdbe6fd 100644 --- a/docs/platforms/platforms_index.rst +++ b/docs/platforms/platforms_index.rst @@ -89,19 +89,19 @@ remaining nodes in the allocation. Note that **gen_on_manager** is not set in the above example. -Distributed Running --------------------- +Distributed Running +------------------- In the **distributed** approach, libEnsemble can be run using the **mpi4py** communicator, with workers distributed across nodes. This is most often used when workers run simulation code directly, via a Python interface. The user -script is invoked with an MPI runner, for example (using an `mpich` based MPI):: +script is invoked with an MPI runner, for example (using an `mpich`-based MPI):: mpirun -np 4 -ppn 1 python myscript.py The distributed approach, can also be used with the executor, to co-locate workers -with the applications they submit. To ensure workers are placed as required in this -case, requires :ref:`a careful MPI rank placement `. +with the applications they submit. Ensuring that workers are placed as required in this +case requires :ref:`a careful MPI rank placement `. .. image:: ../images/distributed_new_detailed.png :alt: distributed diff --git a/docs/resource_manager/resource_detection.rst b/docs/resource_manager/resource_detection.rst index 474cc1cade..2048eb2793 100644 --- a/docs/resource_manager/resource_detection.rst +++ b/docs/resource_manager/resource_detection.rst @@ -18,17 +18,17 @@ LSF LSB_HOSTS/LSB_MCPU_HOSTS PBS PBS_NODEFILE =========== =========================== -These environment variable names can be modified via the :ref:`resource_info` +These environment variable names can be modified via the :ref:`resource_info` :class:`libE_specs` option. -On other systems you may have to supply a node list in a file called **node_list** -in your run directory. For example, on ALCF system Cooley_, the session node list +On other systems, you may have to supply a node list in a file called **node_list** +in your run directory. For example, on the ALCF system Cooley_, the session node list can be obtained as follows:: cat $COBALT_NODEFILE > node_list Resource detection can be disabled by setting -``libE_specs["disable_resource_manager"] = True``, and users can simply supply run +``libE_specs["disable_resource_manager"] = True``, and users can supply run configuration options on the Executor submit line. This will usually work sufficiently on diff --git a/docs/resource_manager/zero_resource_workers.rst b/docs/resource_manager/zero_resource_workers.rst index 1dc62095e6..4c72cf5d7b 100644 --- a/docs/resource_manager/zero_resource_workers.rst +++ b/docs/resource_manager/zero_resource_workers.rst @@ -53,7 +53,7 @@ concurrency desired by the ensemble, taking into account generators and simulato Users can set generator resources using the *libE_specs* options ``gen_num_procs`` and/or ``gen_num_gpus``, which take integer values. -If only ``gen_num_gpus`` is set, then the number of processors is set to match. +If only ``gen_num_gpus`` is set, then the number of processors is set to match. To vary generator resources, ``persis_info`` settings can be used in allocation functions before calling the ``gen_work`` support function. This takes the diff --git a/docs/tutorials/forces_gpu_tutorial.rst b/docs/tutorials/forces_gpu_tutorial.rst index 870b634648..be487f33cc 100644 --- a/docs/tutorials/forces_gpu_tutorial.rst +++ b/docs/tutorials/forces_gpu_tutorial.rst @@ -7,9 +7,9 @@ to the GPU. The libEnsemble scripts in this example are available under forces_gpu_ in the libEnsemble repository. This example is based on the -:doc:`simple forces tutorial <../tutorials/executor_forces_tutorial>` with +:doc:`simple forces tutorial <../tutorials/executor_forces_tutorial>` with a slightly modified simulation function (to assign GPUs) and a greatly increased -number of particles (allows live GPU usage to be viewed). +number of particles (to allow real-time GPU usage to be viewed). In the first example, each worker will be using one GPU. The code will assign the GPUs available to each worker, using the appropriate method. This works on systems diff --git a/libensemble/gen_funcs/persistent_gpCAM.py b/libensemble/gen_funcs/persistent_gpCAM.py index f130950468..05b08bb5ed 100644 --- a/libensemble/gen_funcs/persistent_gpCAM.py +++ b/libensemble/gen_funcs/persistent_gpCAM.py @@ -212,10 +212,10 @@ def persistent_gpCAM_covar(H_in, persis_info, gen_specs, libE_info): (lb, ub) and on following iterations samples the GP posterior covariance function to find sample points. - If gen_specs["user"]["use_grid"] is set to True the parameter space is + If gen_specs["user"]["use_grid"] is set to True, the parameter space is divided into a mesh of candidate points (num_points in each dimension). - Subsequent points chosen by maximum covariance that are at least a distance - `r` away from each other to explore difference regions. + Subsequent points are chosen with maximum covariance that are at least a + distance `r` away from each other to explore difference regions. If gen_specs["user"]["test_points_file"] is set to a file of evaluated points, then the gpCAM predications are compared at these points to assess diff --git a/libensemble/tests/regression_tests/test_gpCAM.py b/libensemble/tests/regression_tests/test_gpCAM.py index b554752eba..218ecfc918 100644 --- a/libensemble/tests/regression_tests/test_gpCAM.py +++ b/libensemble/tests/regression_tests/test_gpCAM.py @@ -11,7 +11,7 @@ Runs three variants of gpCAM. The first two use the posterior covariance sampling method, whereby the second run uses the grid approach and uses -the points from the first run as it’s test points.The third run uses the +the points from the first run as it’s test points. The third run uses the gpCAM ask/tell interface. See libensemble.gen_funcs.persistent_gpCAM for more details about the diff --git a/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py b/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py index 8df0ae006d..8c589161ad 100644 --- a/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py +++ b/libensemble/tests/regression_tests/test_persistent_gp_multitask_ax.py @@ -2,7 +2,7 @@ Example of multi-fidelity optimization using a persistent GP gen_func (calling Ax). -Test is set to use the gen_on_manager option (persistent generator runs on +This test uses the gen_on_manager option (persistent generator runs on a thread). Therefore nworkers is the number of simulation workers. Execute via one of the following commands: From f713522a26c48188d58ea1632cd3130a70f5b7a6 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 8 Apr 2025 12:06:14 -0500 Subject: [PATCH 11/31] nb-clean to ipynb files --- .../forces_with_executor/forces_tutorial_notebook.ipynb | 4 +--- examples/tutorials/gpcam_surrogate_model/gpcam.ipynb | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/examples/tutorials/forces_with_executor/forces_tutorial_notebook.ipynb b/examples/tutorials/forces_with_executor/forces_tutorial_notebook.ipynb index bf408258a4..b85222e445 100644 --- a/examples/tutorials/forces_with_executor/forces_tutorial_notebook.ipynb +++ b/examples/tutorials/forces_with_executor/forces_tutorial_notebook.ipynb @@ -587,9 +587,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "scrolled": false - }, + "metadata": {}, "outputs": [], "source": [ "! ls -l ensemble/sim*" diff --git a/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb b/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb index 097a391c91..228288c0ee 100644 --- a/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb +++ b/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb @@ -438,8 +438,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.9" + "pygments_lexer": "ipython3" } }, "nbformat": 4, From d5dcd521a5b7f328241116b3c1dd56f48288581c Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 8 Apr 2025 12:08:28 -0500 Subject: [PATCH 12/31] Update CHANGELOG.rst --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ff1a6c209..a4650e9058 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -21,7 +21,7 @@ General Updates: * Improve handling of worker-specific `persis_info` fields when they are not initially provided. #1531 * Bugfix: Fix `final_gen_send` when there are no worker-specific `persis_info` fields. * Handle worker-generated `persis_info` fields. - * Ensure `persis_info` is initialized to an empty dictionary in user functions instead of None. + * Ensure `persis_info` is initialized to an empty dictionary in user functions instead of `None`. Examples: From 5d1278f2c2650ce78b849f38d492b4b657608af3 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Tue, 8 Apr 2025 12:09:30 -0500 Subject: [PATCH 13/31] mono --- CHANGELOG.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ff1a6c209..a4650e9058 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -21,7 +21,7 @@ General Updates: * Improve handling of worker-specific `persis_info` fields when they are not initially provided. #1531 * Bugfix: Fix `final_gen_send` when there are no worker-specific `persis_info` fields. * Handle worker-generated `persis_info` fields. - * Ensure `persis_info` is initialized to an empty dictionary in user functions instead of None. + * Ensure `persis_info` is initialized to an empty dictionary in user functions instead of `None`. Examples: From db26ac9c33819eb5747685090227928cf8d463dc Mon Sep 17 00:00:00 2001 From: jlnav Date: Wed, 9 Apr 2025 11:36:03 -0500 Subject: [PATCH 14/31] small fixes - adjust version in pyproject.toml, fix pydantic version listed in advanced_installation --- docs/advanced_installation.rst | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/advanced_installation.rst b/docs/advanced_installation.rst index 4d436eb2cd..ad3131ee15 100644 --- a/docs/advanced_installation.rst +++ b/docs/advanced_installation.rst @@ -9,7 +9,7 @@ automatically installed alongside libEnsemble: * Python_ ``>= 3.10`` * NumPy_ ``>= 1.21`` * psutil_ ``>= 5.9.4`` -* `pydantic`_ ``<= 1.10.12`` +* `pydantic`_ ``>= 1.10.12`` * pyyaml_ ``>= v6.0`` * tomli_ ``>= 1.2.1`` diff --git a/pyproject.toml b/pyproject.toml index 7aca0ef7ed..12d06091fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", ] -version = "1.4.3+dev" +version = "1.5.0" [project.urls] Documentation = "https://libensemble.readthedocs.io/en/main/" From 1a9f3418ce069cfa04e0a982e30af909bfd4626c Mon Sep 17 00:00:00 2001 From: Stephen Hudson Date: Wed, 9 Apr 2025 12:49:15 -0500 Subject: [PATCH 15/31] Add LUMI support (#1546) --- libensemble/resources/platforms.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/libensemble/resources/platforms.py b/libensemble/resources/platforms.py index 46b357540e..062d0bab44 100644 --- a/libensemble/resources/platforms.py +++ b/libensemble/resources/platforms.py @@ -162,6 +162,19 @@ class GenericROCm(Platform): scheduler_match_slots: bool = True +class Lumi(Platform): + mpi_runner: str = "srun" + cores_per_node: int = 64 + logical_cores_per_node: int = 128 + + +class LumiGPU(Lumi): + gpus_per_node: int = 8 + gpu_setting_type: str = "env" + gpu_setting_name: str = "ROCR_VISIBLE_DEVICES" + scheduler_match_slots: bool = True + + class Perlmutter(Platform): mpi_runner: str = "srun" @@ -243,6 +256,8 @@ class Known_platforms(BaseModel): aurora: Aurora = Aurora() generic_rocm: GenericROCm = GenericROCm() frontier: Frontier = Frontier() + lumi: Lumi = Lumi() + lumi_g: LumiGPU = LumiGPU() perlmutter: Perlmutter = Perlmutter() perlmutter_c: PerlmutterCPU = PerlmutterCPU() perlmutter_g: PerlmutterGPU = PerlmutterGPU() @@ -272,6 +287,16 @@ def known_envs(): else: name = "perlmutter" logger.manager_warning("Perlmutter detected, but no compute partition detected. Are you on login nodes?") + if os.environ.get("SLURM_CLUSTER_NAME") == "lumi": + partition = os.environ.get("SLURM_JOB_PARTITION") + print(f"Lumi partition: {partition}") + if not partition: + logger.manager_warning("LUMI detected, but no compute partition detected. Are you on login nodes?") + if partition and partition.endswith("-g"): + name = "lumi_g" + print(f"Lumi GPU detected: {name}") + else: + name = "lumi" return name From cbabf5a698d7cd75d4b0f5c85d67fe911dac7ac3 Mon Sep 17 00:00:00 2001 From: shudson Date: Wed, 9 Apr 2025 13:03:35 -0500 Subject: [PATCH 16/31] Update release notes --- CHANGELOG.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a4650e9058..799fa6dd8f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -30,6 +30,7 @@ Examples: * `persistent_gpCAM_ask_tell` to `persistent_gpCAM` * `persistent_gpCAM_simple` to `persistent_gpCAM_covar` (in fact less simple) * Persistent generators return `None` as first return value unless `H_o` is updated. #1515 +* Add LUMI to known platforms. #1546 Documentation: @@ -41,7 +42,7 @@ Documentation: :Note: * Tests were run on Linux and MacOS with Python versions 3.10, 3.11, 3.12, 3.13 -* Heterogeneous workflows tested on Aurora (ALCF), Polaris (ALCF), and Perlmutter (NERSC). +* Heterogeneous workflows tested on Aurora (ALCF), Polaris (ALCF), LUMI ((EuroHPC JU)), and Perlmutter (NERSC). :Known Issues: From 877f52be365db7df71aec30efc37ef883a24181e Mon Sep 17 00:00:00 2001 From: jlnav Date: Wed, 9 Apr 2025 13:10:51 -0500 Subject: [PATCH 17/31] make version dynamic in pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 12d06091fc..c9c478e191 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", ] -version = "1.5.0" +dynamic = ["version"] [project.urls] Documentation = "https://libensemble.readthedocs.io/en/main/" From 21f6175e7659de557d4e1c12ca6b33f8d4d01adc Mon Sep 17 00:00:00 2001 From: shudson Date: Wed, 9 Apr 2025 13:44:22 -0500 Subject: [PATCH 18/31] Revert "make version dynamic in pyproject.toml" This reverts commit 877f52be365db7df71aec30efc37ef883a24181e. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index c9c478e191..12d06091fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", ] -dynamic = ["version"] +version = "1.5.0" [project.urls] Documentation = "https://libensemble.readthedocs.io/en/main/" From fa951d7acd8bf7fe64368407ecfe1a1371a38438 Mon Sep 17 00:00:00 2001 From: jlnav Date: Wed, 9 Apr 2025 15:38:46 -0500 Subject: [PATCH 19/31] libE_specs *may* always have a workflow_dir_path, as we're getting the attribute from the object. try the dynamic versioning again... --- libensemble/ensemble.py | 19 ++++++++----------- pyproject.toml | 5 ++++- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/libensemble/ensemble.py b/libensemble/ensemble.py index 9b581a1d1a..412b98c495 100644 --- a/libensemble/ensemble.py +++ b/libensemble/ensemble.py @@ -578,14 +578,11 @@ def save_output(self, basename: str, append_attrs: bool = True): Format: ``_results_History_length=_evals=_ranks=`` """ if self.is_manager: - if self._get_option("libE_specs", "workflow_dir_path"): - save_libE_output( - self.H, - self.persis_info, - basename, - self.nworkers, - dest_path=self.libE_specs.workflow_dir_path, - append_attrs=append_attrs, - ) - else: - save_libE_output(self.H, self.persis_info, basename, self.nworkers, append_attrs=append_attrs) + save_libE_output( + self.H, + self.persis_info, + basename, + self.nworkers, + dest_path=self.libE_specs.workflow_dir_path, + append_attrs=append_attrs, + ) diff --git a/pyproject.toml b/pyproject.toml index 12d06091fc..c6a7ea9f36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ classifiers = [ "Topic :: Scientific/Engineering", "Topic :: Software Development :: Libraries :: Python Modules", ] -version = "1.5.0" +dynamic = ["version"] [project.urls] Documentation = "https://libensemble.readthedocs.io/en/main/" @@ -45,6 +45,9 @@ requires = ["setuptools", "wheel", "pip>=24.3.1,<26", "setuptools>=75.1.0,<79", where = ["."] include = ["libensemble*"] +[tool.setuptools.dynamic] +version = {attr = "libensemble.version.__version__"} + [tool.pixi.project] channels = ["conda-forge"] platforms = ["osx-arm64", "linux-64", "osx-64"] From 714e7e510535d74bf9b6b10c20f74e9a7839a759 Mon Sep 17 00:00:00 2001 From: jlnav Date: Wed, 9 Apr 2025 15:46:09 -0500 Subject: [PATCH 20/31] __all__ in tasmanian doesnt need definition if we'll never do: from libensemble.gen_funcs.persistent_tasmanian import * --- libensemble/gen_funcs/persistent_tasmanian.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libensemble/gen_funcs/persistent_tasmanian.py b/libensemble/gen_funcs/persistent_tasmanian.py index ac491cf6a0..5afb9be1bc 100644 --- a/libensemble/gen_funcs/persistent_tasmanian.py +++ b/libensemble/gen_funcs/persistent_tasmanian.py @@ -10,10 +10,10 @@ from libensemble.tools import parse_args from libensemble.tools.persistent_support import PersistentSupport -__all__ = [ - "sparse_grid_batched", - "sparse_grid_async", -] +# __all__ = [ +# "sparse_grid_batched", +# "sparse_grid_async", +# ] def lex_le(x, y, tol=1e-12): From b57d80c639f56a066a11c8fee0f2eca676da556f Mon Sep 17 00:00:00 2001 From: jlnav Date: Wed, 9 Apr 2025 15:49:00 -0500 Subject: [PATCH 21/31] remove lumi prints in platforms.py --- libensemble/resources/platforms.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/libensemble/resources/platforms.py b/libensemble/resources/platforms.py index 062d0bab44..cf4dde324a 100644 --- a/libensemble/resources/platforms.py +++ b/libensemble/resources/platforms.py @@ -289,12 +289,10 @@ def known_envs(): logger.manager_warning("Perlmutter detected, but no compute partition detected. Are you on login nodes?") if os.environ.get("SLURM_CLUSTER_NAME") == "lumi": partition = os.environ.get("SLURM_JOB_PARTITION") - print(f"Lumi partition: {partition}") if not partition: logger.manager_warning("LUMI detected, but no compute partition detected. Are you on login nodes?") if partition and partition.endswith("-g"): name = "lumi_g" - print(f"Lumi GPU detected: {name}") else: name = "lumi" return name From cd178e3deaeebb9cd4debedce140549917590471 Mon Sep 17 00:00:00 2001 From: shudson Date: Wed, 9 Apr 2025 18:21:36 -0500 Subject: [PATCH 22/31] Update gpCAM notebook --- CHANGELOG.rst | 2 +- examples/tutorials/gpcam_surrogate_model/gpcam.ipynb | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 799fa6dd8f..71cb1119d4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -42,7 +42,7 @@ Documentation: :Note: * Tests were run on Linux and MacOS with Python versions 3.10, 3.11, 3.12, 3.13 -* Heterogeneous workflows tested on Aurora (ALCF), Polaris (ALCF), LUMI ((EuroHPC JU)), and Perlmutter (NERSC). +* Heterogeneous workflows tested on Aurora (ALCF), Polaris (ALCF), LUMI (EuroHPC JU), and Perlmutter (NERSC). :Known Issues: diff --git a/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb b/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb index 228288c0ee..75b0c44041 100644 --- a/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb +++ b/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb @@ -20,10 +20,7 @@ "Ensure that libEnsemble, and gpCAM are installed via: `pip install libensemble gpcam`\n", " \n", "> **Note that for notebooks** the multiprocessing start method should be set to `fork` (default on Linux).\n", - "> To use with `spawn` (default on Windows and macOS), use the `multiprocess` library.\n", - "\n", - "> **Note:** If using **Colab** the cell below installs gpCAM and prevents Colab downgrading numpy due to pre-installs.\n", - "> Restart session when prompted (the warnings can be ignored)." + "> To use with `spawn` (default on Windows and macOS), use the `multiprocess` library." ] }, { @@ -35,8 +32,7 @@ "import sys\n", "if 'google.colab' in sys.modules:\n", " !pip install libensemble\n", - " # Prevent downgraded numpy in colab due to preinstalls\n", - " !pip install --upgrade --force-reinstall numpy==2.1.1 scipy gpcam fvgp" + " !pip install gpcam" ] }, { From 79bcd3771cb434c524ff948a528e76916dc51cdd Mon Sep 17 00:00:00 2001 From: shudson Date: Wed, 9 Apr 2025 20:33:24 -0500 Subject: [PATCH 23/31] Replace flashing live animation with clean post-run version --- .../aposmm/aposmm_tutorial_notebook.ipynb | 117 +++++++++++++----- 1 file changed, 88 insertions(+), 29 deletions(-) diff --git a/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb b/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb index 7898ba7661..38eca21677 100644 --- a/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb +++ b/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb @@ -226,28 +226,7 @@ "source": [ "## Run the Ensemble\n", "\n", - "Optionally run the next cell to set up a live graphic of the optimization progress during execution.\n", - "\n", - "**WARNING**: The graphic may flicker when the ensemble is running." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Configure to view live progress\n", - "from libensemble.tools.live_data.plot2n import Plot2N\n", - "\n", - "libE_specs[\"live_data\"] = Plot2N(plot_type=\"2d\") # Alt: '3d'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, set `persis_info` (to provide random seeds to workers) and run the ensemble:" + "Finally, set persis_info (to provide random seeds to workers) and run the ensemble." ] }, { @@ -290,29 +269,109 @@ " \n", "The first six values correspond to the local minima for the Six-Hump Camel simulation function.\n", "\n", - "The 7th value is a repeat minimum, as APOSMM will continue to start local optimization runs.\n", - "\n", - "Please see the [API reference](https://libensemble.readthedocs.io/en/main/examples/aposmm.html) for more APOSMM configuration options and other information.\n", + "The 7th value is a repeat minimum, as APOSMM will continue to start local optimization runs." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Viewing Animation\n", "\n", + "The following cell produces a 3D animation showing the random sampling points, \n", + "and points produced by the optimization runs, under the local Minima. It may take\n", + "a few seconds to produce the animation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.animation as animation\n", + "from IPython.display import HTML\n", + "from matplotlib.lines import Line2D\n", + "\n", + "def animate_aposmm_3d(H, batch_size):\n", + " x_vals = np.linspace(-2, 2, 50)\n", + " y_vals = np.linspace(-1, 1.1, 50)\n", + " X, Y = np.meshgrid(x_vals, y_vals)\n", + " Z = np.array([six_hump_camel_func(np.array([x, y])) for x, y in zip(X.ravel(), Y.ravel())]).reshape(X.shape)\n", + " fig = plt.figure(figsize=(10, 8))\n", + " ax = fig.add_subplot(111, projection=\"3d\")\n", + " ax.plot_surface(X, Y, Z, cmap=\"winter\", edgecolor=\"none\", alpha=0.3)\n", + " sc_normal = ax.scatter3D([], [], [], s=6, color=\"black\", marker=\"o\", label=\"Point\")\n", + " sc_localp = ax.scatter3D([], [], [], s=40, color=\"red\", marker=\"^\", label=\"Optimization point\")\n", + " custom_M_marker = Line2D([0], [0], linestyle='None', marker='$\\\\mathrm{M}$',\n", + " markersize=8, markerfacecolor='black', markeredgecolor='black', color='white')\n", + " ax.legend([sc_normal, sc_localp, custom_M_marker], [\"Point\", \"Optimization point\", \"Local minimum\"],loc=\"upper left\")\n", + " fig.tight_layout()\n", + " annotations = []\n", + "\n", + " def update(frame):\n", + " for ann in annotations:\n", + " ann.remove()\n", + " annotations.clear()\n", + " end = min((frame + 1) * batch_size, len(H))\n", + " H_sub = H[:end]\n", + " masks = [~H_sub[\"local_pt\"] & ~H_sub[\"local_min\"], H_sub[\"local_pt\"], H_sub[\"local_min\"]]\n", + " (x_n, y_n, f_n), (x_lp, y_lp, f_lp), (x_lm, y_lm, f_lm) = [\n", + " (H_sub[\"x\"][m, 0], H_sub[\"x\"][m, 1], H_sub[\"f\"][m]) for m in masks\n", + " ]\n", + " sc_normal._offsets3d = (x_n, y_n, f_n)\n", + " sc_localp._offsets3d = (x_lp, y_lp, f_lp)\n", + " for i in range(len(x_lm)):\n", + " annotations.append(ax.text(x_lm[i], y_lm[i], f_lm[i], \"M\", color=\"white\", fontsize=12,\n", + " bbox=dict(facecolor=\"black\", alpha=0.7, pad=2), zorder=999\n", + " ))\n", + " return sc_normal, sc_localp\n", + " total_frames = (len(H) + batch_size - 1) // batch_size\n", + " ani = animation.FuncAnimation(fig, update, frames=total_frames, interval=500, blit=False, repeat=False)\n", + " plt.close(fig)\n", + " return HTML(ani.to_jshtml())\n", + "\n", + "# Reduce batch_size for more refined steps\n", + "animate_aposmm_3d(H, batch_size=50)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "## Applications\n", "\n", "APOSMM is not limited to evaluating minima from pure Python simulation functions.\n", "Many common libEnsemble use-cases involve using libEnsemble's Executor to launch user\n", "applications with parameters requested by APOSMM, then evaluate their output using\n", "APOSMM, and repeat until minima are identified. A currently supported example\n", - "can be found in libEnsemble's [WarpX Scaling Test](https://github.com/Libensemble/libensemble/tree/main/libensemble/tests/scaling_tests/warpx)" + "can be found in libEnsemble's [WarpX Scaling Test](https://github.com/Libensemble/libensemble/tree/main/libensemble/tests/scaling_tests/warpx)\n", + "\n", + "Please see the [API reference](https://libensemble.readthedocs.io/en/main/examples/aposmm.html) for more APOSMM configuration options and other information." ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", + "language": "python", "name": "python3" }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.1" } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } From 34339f4a61b3c9d68468bef794d2a989f268bdbf Mon Sep 17 00:00:00 2001 From: jlnav Date: Thu, 10 Apr 2025 09:22:23 -0500 Subject: [PATCH 24/31] add unit test to ensure persis_info being None gets set to empty dict inside function --- .../tests/unit_tests/test_ufunc_runners.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libensemble/tests/unit_tests/test_ufunc_runners.py b/libensemble/tests/unit_tests/test_ufunc_runners.py index 1d3cbb4b2c..09f17b07ec 100644 --- a/libensemble/tests/unit_tests/test_ufunc_runners.py +++ b/libensemble/tests/unit_tests/test_ufunc_runners.py @@ -54,6 +54,20 @@ def tupilize(arg1, arg2): simrunner.shutdown() +def test_persis_info_from_none(): + calc_in, sim_specs, gen_specs = get_ufunc_args() + + def tupilize(arg1, arg2): + return (arg1, arg2) + + sim_specs["sim_f"] = tupilize + simrunner = Runner(sim_specs) + libE_info = {"H_rows": np.array([2, 3, 4]), "workerID": 1, "comm": "fakecomm"} + + result = simrunner.run(calc_in, {"libE_info": libE_info, "persis_info": None, "tag": 1}) + assert result == (calc_in, {}) + + @pytest.mark.extra def test_globus_compute_runner_init(): calc_in, sim_specs, gen_specs = get_ufunc_args() @@ -122,6 +136,7 @@ def test_globus_compute_runner_fail(): if __name__ == "__main__": test_normal_runners() test_thread_runners() + test_persis_info_from_none() test_globus_compute_runner_init() test_globus_compute_runner_pass() test_globus_compute_runner_fail() From d30259eb1b63eb484e3348fda648a4ee09273bc3 Mon Sep 17 00:00:00 2001 From: jlnav Date: Thu, 10 Apr 2025 11:23:45 -0500 Subject: [PATCH 25/31] enable coverage for ax and gpcam, disable coverage for tasmanian --- .codecov.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.codecov.yml b/.codecov.yml index 18ef408010..bf866b089c 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -3,5 +3,4 @@ ignore: - "libensemble/tools/forkable_pdb.py" - "libensemble/tools/live_data/*" - "libensemble/sim_funcs/executor_hworld.py" - - "libensemble/gen_funcs/persistent_ax_multitask.py" - - "libensemble/gen_funcs/persistent_gpCAM.py" + - "libensemble/gen_funcs/persistent_tasmanian.py" From deb58af61d1bd978166c161b78de78b71efa2a2a Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Thu, 10 Apr 2025 11:28:38 -0500 Subject: [PATCH 26/31] Updating input fields --- libensemble/gen_funcs/persistent_sampling.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libensemble/gen_funcs/persistent_sampling.py b/libensemble/gen_funcs/persistent_sampling.py index 44611d06b6..ce4fe51515 100644 --- a/libensemble/gen_funcs/persistent_sampling.py +++ b/libensemble/gen_funcs/persistent_sampling.py @@ -29,8 +29,8 @@ def _get_user_params(user_specs): return b, n, lb, ub -@persistent_input_fields(["f", "x", "sim_id"]) -@output_data([("x", float, (2,))]) +@persistent_input_fields(["sim_id"]) +@output_data([("x", float, (2,))]) # The dimesion 2 is only a default... and is overwritten def persistent_uniform(_, persis_info, gen_specs, libE_info): """ This generation function always enters into persistent mode and returns From 026371cd338182feb8b9d4f152953f597181ec7b Mon Sep 17 00:00:00 2001 From: shudson Date: Thu, 10 Apr 2025 12:30:56 -0500 Subject: [PATCH 27/31] Add grid lines and up opacity --- .../aposmm/aposmm_tutorial_notebook.ipynb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb b/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb index 38eca21677..594057f3c0 100644 --- a/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb +++ b/examples/tutorials/aposmm/aposmm_tutorial_notebook.ipynb @@ -6,7 +6,7 @@ "source": [ "# Parallel Optimization with APOSMM\n", "\n", - "This tutorial demonstrates libEnsemble’s capability to identify multiple minima of simulation output using the built-in APOSMM (Asynchronously Parallel Optimization Solver for finding Multiple Minima) generator function (`gen_f`). In this tutorial, we’ll create a simple simulation function (`sim_f`) that defines a function with multiple minima, then write a libEnsemble calling script that imports APOSMM and parameterizes it to check for minima over a domain of outputs from our `sim_f`.\n", + "This tutorial demonstrates libEnsemble’s capability to identify multiple minima from simulation outputs using the built-in APOSMM (Asynchronously Parallel Optimization Solver for finding Multiple Minima) generator function (`gen_f`). In this tutorial, we’ll create a simple simulation function (`sim_f`) that defines a function with multiple minima, then write a libEnsemble calling script that imports APOSMM and parameterizes it to check for minima over a domain of outputs from our `sim_f`.\n", "\n", "Besides libEnsemble and NumPy, SciPy and mpmath are also required dependencies.\n", "\n", @@ -43,7 +43,6 @@ "outputs": [], "source": [ "# Define our simulation function\n", - "\n", "import numpy as np\n", "\n", "\n", @@ -122,9 +121,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This allocation function starts a single Persistent APOSMM routine and provides ``sim_f`` output for points requested by APOSMM. Points can be sampled points or points from local optimization runs.\n", + "This allocation function starts a single Persistent APOSMM generator to generate points (simulation input parameters), and returns the resulting values from each simulation (run in parallel). Points can be sampled points or points from the parallel local optimization runs.\n", "\n", - "APOSMM supports a wide variety of external optimizers. The following statements set optimizer settings to ``'scipy'`` to indicate to APOSMM which optimization method to use, and help prevent unnecessary imports or package installations:" + "APOSMM supports a wide variety of external optimizers. The following statement sets the optimizer settings to ``'scipy'`` to indicate to APOSMM which optimization method to use, so it is imported at global scope:" ] }, { @@ -142,6 +141,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ + "This script uses the dictionary interface to configure the run (the newer object interface is equally valid).\n", "Set up ``nworkers``, ``libE_specs``, ``sim_specs``, ``gen_specs``, and ``alloc_specs``:" ] }, @@ -279,8 +279,9 @@ "## Viewing Animation\n", "\n", "The following cell produces a 3D animation showing the random sampling points, \n", - "and points produced by the optimization runs, under the local Minima. It may take\n", - "a few seconds to produce the animation." + "the points produced by the optimization runs, and the local Minima.\n", + "\n", + "This may take up to about 30 seconds to produce the 3D animation, depending on system." ] }, { @@ -302,7 +303,7 @@ " Z = np.array([six_hump_camel_func(np.array([x, y])) for x, y in zip(X.ravel(), Y.ravel())]).reshape(X.shape)\n", " fig = plt.figure(figsize=(10, 8))\n", " ax = fig.add_subplot(111, projection=\"3d\")\n", - " ax.plot_surface(X, Y, Z, cmap=\"winter\", edgecolor=\"none\", alpha=0.3)\n", + " ax.plot_surface(X, Y, Z, cmap=\"winter\", edgecolor='k', linewidth=0.1, antialiased=True, alpha=0.5) \n", " sc_normal = ax.scatter3D([], [], [], s=6, color=\"black\", marker=\"o\", label=\"Point\")\n", " sc_localp = ax.scatter3D([], [], [], s=40, color=\"red\", marker=\"^\", label=\"Optimization point\")\n", " custom_M_marker = Line2D([0], [0], linestyle='None', marker='$\\\\mathrm{M}$',\n", From 8da45e886e7bc7f3a99fc881597742c77a97cf69 Mon Sep 17 00:00:00 2001 From: shudson Date: Thu, 10 Apr 2025 13:42:22 -0500 Subject: [PATCH 28/31] Add back gpcam colab import line --- examples/tutorials/gpcam_surrogate_model/gpcam.ipynb | 9 +++++++-- libensemble/gen_funcs/persistent_sampling.py | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb b/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb index 75b0c44041..29616f582e 100644 --- a/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb +++ b/examples/tutorials/gpcam_surrogate_model/gpcam.ipynb @@ -20,7 +20,10 @@ "Ensure that libEnsemble, and gpCAM are installed via: `pip install libensemble gpcam`\n", " \n", "> **Note that for notebooks** the multiprocessing start method should be set to `fork` (default on Linux).\n", - "> To use with `spawn` (default on Windows and macOS), use the `multiprocess` library." + "> To use with `spawn` (default on Windows and macOS), use the `multiprocess` library.\n", + "\n", + "> **Note:** If using **Colab** the cell below installs gpCAM and prevents Colab downgrading numpy due to pre-installs.\n", + "> Restart session when prompted (the warnings can be ignored)." ] }, { @@ -32,7 +35,9 @@ "import sys\n", "if 'google.colab' in sys.modules:\n", " !pip install libensemble\n", - " !pip install gpcam" + " # !pip install gpcam\n", + " # Prevent downgraded numpy in colab due to preinstalls\n", + " !pip install --upgrade --force-reinstall numpy==2.1.1 scipy gpcam fvgp\"" ] }, { diff --git a/libensemble/gen_funcs/persistent_sampling.py b/libensemble/gen_funcs/persistent_sampling.py index ce4fe51515..401ccdaa94 100644 --- a/libensemble/gen_funcs/persistent_sampling.py +++ b/libensemble/gen_funcs/persistent_sampling.py @@ -30,7 +30,7 @@ def _get_user_params(user_specs): @persistent_input_fields(["sim_id"]) -@output_data([("x", float, (2,))]) # The dimesion 2 is only a default... and is overwritten +@output_data([("x", float, (2,))]) # The dimesion of 2 is a default and can be overwritten def persistent_uniform(_, persis_info, gen_specs, libE_info): """ This generation function always enters into persistent mode and returns From ced94fc36bf4ff85a88b3bbd508a51fa010bf432 Mon Sep 17 00:00:00 2001 From: shudson Date: Thu, 10 Apr 2025 14:06:03 -0500 Subject: [PATCH 29/31] Revert ensemble.py to release/v_1.5.0 version --- libensemble/ensemble.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/libensemble/ensemble.py b/libensemble/ensemble.py index 412b98c495..9b581a1d1a 100644 --- a/libensemble/ensemble.py +++ b/libensemble/ensemble.py @@ -578,11 +578,14 @@ def save_output(self, basename: str, append_attrs: bool = True): Format: ``_results_History_length=_evals=_ranks=`` """ if self.is_manager: - save_libE_output( - self.H, - self.persis_info, - basename, - self.nworkers, - dest_path=self.libE_specs.workflow_dir_path, - append_attrs=append_attrs, - ) + if self._get_option("libE_specs", "workflow_dir_path"): + save_libE_output( + self.H, + self.persis_info, + basename, + self.nworkers, + dest_path=self.libE_specs.workflow_dir_path, + append_attrs=append_attrs, + ) + else: + save_libE_output(self.H, self.persis_info, basename, self.nworkers, append_attrs=append_attrs) From edfa3c1723ac90fe01347f21f1266ad052ddf304 Mon Sep 17 00:00:00 2001 From: shudson Date: Thu, 10 Apr 2025 14:08:57 -0500 Subject: [PATCH 30/31] Keep __all__ lines for docs --- libensemble/gen_funcs/persistent_tasmanian.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libensemble/gen_funcs/persistent_tasmanian.py b/libensemble/gen_funcs/persistent_tasmanian.py index 5afb9be1bc..ac491cf6a0 100644 --- a/libensemble/gen_funcs/persistent_tasmanian.py +++ b/libensemble/gen_funcs/persistent_tasmanian.py @@ -10,10 +10,10 @@ from libensemble.tools import parse_args from libensemble.tools.persistent_support import PersistentSupport -# __all__ = [ -# "sparse_grid_batched", -# "sparse_grid_async", -# ] +__all__ = [ + "sparse_grid_batched", + "sparse_grid_async", +] def lex_le(x, y, tol=1e-12): From 58735ab04802ccf8a9c35aa944c156d51e9e6437 Mon Sep 17 00:00:00 2001 From: shudson Date: Thu, 10 Apr 2025 14:17:13 -0500 Subject: [PATCH 31/31] Set date for release 1.5.0 --- .wci.yml | 2 +- CHANGELOG.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.wci.yml b/.wci.yml index af395fb9af..f03aa0c635 100644 --- a/.wci.yml +++ b/.wci.yml @@ -17,7 +17,7 @@ language: Python release: version: 1.5.0 - date: 2025-04-08 + date: 2025-04-10 documentation: general: https://libensemble.readthedocs.io diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 71cb1119d4..bbb2bee549 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,7 +11,7 @@ GitHub issues are referenced, and can be viewed with hyperlinks on the `github r Release 1.5.0 -------------- -:Date: Apr 8, 2025 +:Date: Apr 10, 2025 General Updates: