From 579ac35b9dc840cb725cda3b33ad4739336a01c1 Mon Sep 17 00:00:00 2001 From: jlnav Date: Fri, 6 May 2022 15:28:45 -0500 Subject: [PATCH 1/7] if misc str received as calc_status, format into log message. accept str calc_status on manager end --- libensemble/manager.py | 4 ++-- libensemble/message_numbers.py | 1 + libensemble/worker.py | 10 +++++----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libensemble/manager.py b/libensemble/manager.py index 326396909..c0bf7c8e4 100644 --- a/libensemble/manager.py +++ b/libensemble/manager.py @@ -388,7 +388,7 @@ def _check_received_calc(D_recv): EVAL_GEN_TAG, ], "Aborting, Unknown calculation type received. " "Received type: {}".format(calc_type) - assert calc_status in [ + assert (calc_status in [ FINISHED_PERSISTENT_SIM_TAG, FINISHED_PERSISTENT_GEN_TAG, UNSET_TAG, @@ -400,7 +400,7 @@ def _check_received_calc(D_recv): WORKER_KILL, TASK_FAILED, WORKER_DONE, - ], "Aborting: Unknown calculation status received. " "Received status: {}".format(calc_status) + ] or isinstance(calc_status, str)), "Aborting: Unknown calculation status received. " "Received status: {}".format(calc_status) def _receive_from_workers(self, persis_info): """Receives calculation output from workers. Loops over all diff --git a/libensemble/message_numbers.py b/libensemble/message_numbers.py index 448c80cc8..97bd202ba 100644 --- a/libensemble/message_numbers.py +++ b/libensemble/message_numbers.py @@ -35,6 +35,7 @@ CALC_EXCEPTION = 35 # Reserved: Automatically used if gen_f or sim_f raised an exception. calc_status_strings = { + UNSET_TAG: "Not set", FINISHED_PERSISTENT_SIM_TAG: "Persis sim finished", FINISHED_PERSISTENT_GEN_TAG: "Persis gen finished", MAN_SIGNAL_FINISH: "Manager killed on finish", diff --git a/libensemble/worker.py b/libensemble/worker.py index 02de95c93..87dd57746 100644 --- a/libensemble/worker.py +++ b/libensemble/worker.py @@ -283,9 +283,9 @@ def _handle_calc(self, Work, calc_in): assert isinstance(out, tuple), "Calculation output must be a tuple." assert len(out) >= 2, "Calculation output must be at least two elements." - calc_status = out[2] if len(out) >= 3 else UNSET_TAG - - if calc_status is None: + if len(out) >= 3: + calc_status = out[2] + else: calc_status = UNSET_TAG # Check for buffered receive @@ -311,7 +311,7 @@ def _handle_calc(self, Work, calc_in): calc_type_strings[calc_type], timer, task.timer, - calc_status_strings.get(calc_status, "Not set"), + calc_status_strings.get(calc_status, calc_status), ) else: calc_msg = "{} {}: {} {} Status: {}".format( @@ -319,7 +319,7 @@ def _handle_calc(self, Work, calc_in): calc_id, calc_type_strings[calc_type], timer, - calc_status_strings.get(calc_status, "Not set"), + calc_status_strings.get(calc_status, calc_status), ) logging.getLogger(LogConfig.config.stats_name).info(calc_msg) From 91d541f5b7eefcf245fa677bfa852d0c99f9a597 Mon Sep 17 00:00:00 2001 From: jlnav Date: Fri, 6 May 2022 16:23:21 -0500 Subject: [PATCH 2/7] flake8 --- libensemble/manager.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libensemble/manager.py b/libensemble/manager.py index c0bf7c8e4..bee38dba1 100644 --- a/libensemble/manager.py +++ b/libensemble/manager.py @@ -400,7 +400,8 @@ def _check_received_calc(D_recv): WORKER_KILL, TASK_FAILED, WORKER_DONE, - ] or isinstance(calc_status, str)), "Aborting: Unknown calculation status received. " "Received status: {}".format(calc_status) + ] or isinstance(calc_status, str)), \ + "Aborting: Unknown calculation status received. " "Received status: {}".format(calc_status) def _receive_from_workers(self, persis_info): """Receives calculation output from workers. Loops over all From 5b23629c41aceeefa12f6e527b6e02ef7b542994 Mon Sep 17 00:00:00 2001 From: jlnav Date: Mon, 9 May 2022 11:37:27 -0500 Subject: [PATCH 3/7] some rearranging of message_numbers and an assert in manager --- libensemble/manager.py | 30 ++++++++---------------------- libensemble/message_numbers.py | 23 +++++++++++++++-------- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/libensemble/manager.py b/libensemble/manager.py index bee38dba1..eec169557 100644 --- a/libensemble/manager.py +++ b/libensemble/manager.py @@ -12,22 +12,19 @@ import numpy as np from libensemble.utils.timer import Timer + from libensemble.message_numbers import ( EVAL_SIM_TAG, - FINISHED_PERSISTENT_SIM_TAG, EVAL_GEN_TAG, - FINISHED_PERSISTENT_GEN_TAG, - STOP_TAG, - UNSET_TAG, PERSIS_STOP, - WORKER_KILL, - WORKER_KILL_ON_ERR, - WORKER_KILL_ON_TIMEOUT, - TASK_FAILED, - WORKER_DONE, + STOP_TAG, MAN_SIGNAL_FINISH, MAN_SIGNAL_KILL, + FINISHED_PERSISTENT_SIM_TAG, + FINISHED_PERSISTENT_GEN_TAG, + calc_status_strings, ) + from libensemble.message_numbers import calc_type_strings from libensemble.comms.comms import CommFinishedException from libensemble.worker import WorkerErrMsg @@ -388,19 +385,8 @@ def _check_received_calc(D_recv): EVAL_GEN_TAG, ], "Aborting, Unknown calculation type received. " "Received type: {}".format(calc_type) - assert (calc_status in [ - FINISHED_PERSISTENT_SIM_TAG, - FINISHED_PERSISTENT_GEN_TAG, - UNSET_TAG, - PERSIS_STOP, - MAN_SIGNAL_FINISH, - MAN_SIGNAL_KILL, - WORKER_KILL_ON_ERR, - WORKER_KILL_ON_TIMEOUT, - WORKER_KILL, - TASK_FAILED, - WORKER_DONE, - ] or isinstance(calc_status, str)), \ + assert (calc_status in list(calc_status_strings.keys())+[PERSIS_STOP] + or isinstance(calc_status, str)), \ "Aborting: Unknown calculation status received. " "Received status: {}".format(calc_status) def _receive_from_workers(self, persis_info): diff --git a/libensemble/message_numbers.py b/libensemble/message_numbers.py index 97bd202ba..7392fd208 100644 --- a/libensemble/message_numbers.py +++ b/libensemble/message_numbers.py @@ -1,4 +1,6 @@ -# --- Tags +# ------------------------------- +# -- Basic User Function Tags --- +# ------------------------------- UNSET_TAG = 0 @@ -10,18 +12,23 @@ # When received by the manager, tells manager that worker is done with sim eval. EVAL_GEN_TAG = 2 -STOP_TAG = 3 # Manager tells worker (or persistent calc) to stop -PERSIS_STOP = 4 # Manager tells persistent calculation to stop +STOP_TAG = 3 # Manager tells worker (or persistent user_f) to stop +PERSIS_STOP = 4 # Manager tells persistent user_f to stop # last_message_number_rst_tag -calc_type_strings = {EVAL_SIM_TAG: 'sim', EVAL_GEN_TAG: 'gen', PERSIS_STOP: 'STOP with work', None: 'No type set'} - +calc_type_strings = { + EVAL_SIM_TAG: "sim", + EVAL_GEN_TAG: "gen", + PERSIS_STOP: "STOP with work", + None: "No type set", +} -# --- Signal flags (in message body vs tags) +# -------------------------------------- +# -- Calculation Status/Signal Tags ---- +# -------------------------------------- # first_calc_status_rst_tag -# CALC STATUS/SIGNAL FLAGS FINISHED_PERSISTENT_SIM_TAG = 11 # tells manager sim_f done persistent mode FINISHED_PERSISTENT_GEN_TAG = 12 # tells manager gen_f done persistent mode MAN_SIGNAL_FINISH = 20 # Kill tasks and shutdown worker @@ -32,7 +39,7 @@ TASK_FAILED = 33 # Calc had tasks that failed WORKER_DONE = 34 # Calculation was successful # last_calc_status_rst_tag -CALC_EXCEPTION = 35 # Reserved: Automatically used if gen_f or sim_f raised an exception. +CALC_EXCEPTION = 35 # Reserved: Automatically used if user_f raised an exception calc_status_strings = { UNSET_TAG: "Not set", From 3a8d360bd17aad28578d5dffaaf73d22f4fb7035 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Mon, 9 May 2022 13:01:43 -0500 Subject: [PATCH 4/7] Black --- libensemble/manager.py | 6 +++--- setup.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libensemble/manager.py b/libensemble/manager.py index f1bab7371..e41bd98c7 100644 --- a/libensemble/manager.py +++ b/libensemble/manager.py @@ -385,9 +385,9 @@ def _check_received_calc(D_recv): EVAL_GEN_TAG, ], "Aborting, Unknown calculation type received. " "Received type: {}".format(calc_type) - assert (calc_status in list(calc_status_strings.keys())+[PERSIS_STOP] - or isinstance(calc_status, str)), \ - "Aborting: Unknown calculation status received. " "Received status: {}".format(calc_status) + assert calc_status in list(calc_status_strings.keys()) + [PERSIS_STOP] or isinstance( + calc_status, str + ), "Aborting: Unknown calculation status received. " "Received status: {}".format(calc_status) def _receive_from_workers(self, persis_info): """Receives calculation output from workers. Loops over all diff --git a/setup.py b/setup.py index 25b4bc057..dc89c3bb0 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ DOCLINES = (__doc__ or "").split("\n") -exec(open('libensemble/version.py').read()) +exec(open("libensemble/version.py").read()) class Run_TestSuite(TestCommand): From 7cb4a7d819d9b536af0658bc5da77887c40c61a8 Mon Sep 17 00:00:00 2001 From: Jeffrey Larson Date: Mon, 9 May 2022 15:25:42 -0500 Subject: [PATCH 5/7] Whitespace --- libensemble/manager.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libensemble/manager.py b/libensemble/manager.py index e41bd98c7..6cd5d1d85 100644 --- a/libensemble/manager.py +++ b/libensemble/manager.py @@ -284,7 +284,7 @@ def _check_work_order(self, Work, w): ) else: assert self.W[w - 1]["active"] == 0, ( - "Allocation function requested work be sent to worker %d, an " "already active worker." % w + "Allocation function requested work be sent to worker %d, an already active worker." % w ) work_rows = Work["libE_info"]["H_rows"] if len(work_rows): @@ -297,7 +297,7 @@ def _check_work_order(self, Work, w): hist_fields = self.hist.H.dtype.names diff_fields = list(work_fields.difference(hist_fields)) - assert not diff_fields, "Allocation function requested invalid fields {}" "be sent to worker={}.".format( + assert not diff_fields, "Allocation function requested invalid fields {} be sent to worker={}.".format( diff_fields, w ) @@ -383,11 +383,11 @@ def _check_received_calc(D_recv): assert calc_type in [ EVAL_SIM_TAG, EVAL_GEN_TAG, - ], "Aborting, Unknown calculation type received. " "Received type: {}".format(calc_type) + ], "Aborting, Unknown calculation type received. Received type: {}".format(calc_type) assert calc_status in list(calc_status_strings.keys()) + [PERSIS_STOP] or isinstance( calc_status, str - ), "Aborting: Unknown calculation status received. " "Received status: {}".format(calc_status) + ), "Aborting: Unknown calculation status received. Received status: {}".format(calc_status) def _receive_from_workers(self, persis_info): """Receives calculation output from workers. Loops over all From a957d1e60d13f4200887f57bf19de8dae70c1c34 Mon Sep 17 00:00:00 2001 From: jlnav Date: Mon, 9 May 2022 16:48:20 -0500 Subject: [PATCH 6/7] refactor calc_status docs, add a tiny custom calc_status to inverse_bayes.py --- docs/data_structures/calc_status.rst | 49 ++++++++++++++++++++------ libensemble/sim_funcs/inverse_bayes.py | 2 +- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/docs/data_structures/calc_status.rst b/docs/data_structures/calc_status.rst index 3a4c14fec..5e49f0794 100644 --- a/docs/data_structures/calc_status.rst +++ b/docs/data_structures/calc_status.rst @@ -3,16 +3,18 @@ calc_status =========== -The ``calc_status`` is an integer attribute with named (enumerated) values and -a corresponding description that can be used in :ref:`sim_f` or -:ref:`gen_f` functions to capture the status of a calculation. This -is returned to the manager and printed to the ``libE_stats.txt`` file. Only the -status values ``FINISHED_PERSISTENT_SIM_TAG`` and -``FINISHED_PERSISTENT_GEN_TAG`` are currently used by the manager, but others -can still provide a useful summary in libE_stats.txt. The user determines the -status of the calculation, since it could include multiple application runs. It -can be added as a third return variable in sim_f or gen_f functions. -The calc_status codes are in the ``libensemble.message_numbers`` module. +The ``calc_status`` is similar to an exit code, and is either a built-in integer +attribute with a named (enumerated) value and corresponding description, or a +user-specified string. They are determined within user functions to capture the +status of a calculation, and returned to the manager and printed to the ``libE_stats.txt`` file. +Only the status values ``FINISHED_PERSISTENT_SIM_TAG`` and ``FINISHED_PERSISTENT_GEN_TAG`` +are currently used by the manager, but others can still provide a useful summary in ``libE_stats.txt``. +The user is responsible for determining the status of a user function instance, since +a given instance could include multiple application runs of mixed rates of success. + +The ``calc_status`` is the third optional return value from a user function +Built-in codes are available in the ``libensemble.message_numbers`` module, but +users are also free to return any custom string. Example of ``calc_status`` used along with :ref:`Executor` in sim_f: @@ -51,6 +53,33 @@ Example of ``calc_status`` used along with :ref:`Executor` in si return output, persis_info, calc_status +Example of defining and returning a custom ``calc_status`` if the built-in values +are insufficient: + +.. code-block:: python + :linenos: + + from libensemble.message_numbers import WORKER_DONE, TASK_FAILED + + task = exctr.submit(calc_type='sim', num_procs=cores, wait_on_start=True) + + task.wait(timeout=60) + + file_output = read_task_output(task) + if task.errcode == 0: + if "fail" in file_output: + calc_status = "Task failed successfully?" + else: + calc_status = WORKER_DONE + else: + calc_status = TASK_FAILED + + outspecs = sim_specs['out'] + output = np.zeros(1, dtype=outspecs) + output['energy'][0] = final_energy + + return output, persis_info, calc_status + See forces_simf.py_ for a complete example. See uniform_or_localopt.py_ for an example of using ``FINISHED_PERSISTENT_GEN_TAG``. diff --git a/libensemble/sim_funcs/inverse_bayes.py b/libensemble/sim_funcs/inverse_bayes.py index 8c04310e9..ea6c1e802 100644 --- a/libensemble/sim_funcs/inverse_bayes.py +++ b/libensemble/sim_funcs/inverse_bayes.py @@ -12,7 +12,7 @@ def likelihood_calculator(H, persis_info, sim_specs, _): for i, x in enumerate(H["x"]): H_o["like"][i] = six_hump_camel_func(x) - return H_o, persis_info + return H_o, persis_info, "custom_status" def six_hump_camel_func(x): From 6a76a5180e29a6e314f84196b49727c305d70e3d Mon Sep 17 00:00:00 2001 From: jlnav Date: Mon, 9 May 2022 16:48:56 -0500 Subject: [PATCH 7/7] small edit --- docs/data_structures/calc_status.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/data_structures/calc_status.rst b/docs/data_structures/calc_status.rst index 5e49f0794..18bae3aa8 100644 --- a/docs/data_structures/calc_status.rst +++ b/docs/data_structures/calc_status.rst @@ -12,7 +12,7 @@ are currently used by the manager, but others can still provide a useful summary The user is responsible for determining the status of a user function instance, since a given instance could include multiple application runs of mixed rates of success. -The ``calc_status`` is the third optional return value from a user function +The ``calc_status`` is the third optional return value from a user function. Built-in codes are available in the ``libensemble.message_numbers`` module, but users are also free to return any custom string.