Simulation Functions

Below are example simulation functions available in libEnsemble. Most of these demonstrate an inexpensive algorithm and do not launch tasks (user applications). To see an example of a simulation function launching tasks, see the Electrostatic Forces tutorial.

Important

See the API for simulation functions here.

six_hump_camel

This module contains various versions that evaluate the six-hump camel function.

Six-hump camel function is documented here:

https://www.sfu.ca/~ssurjano/camel6.html

six_hump_camel.six_hump_camel(H, persis_info, sim_specs, libE_info)

Input Fields: ['x']

Output Datatypes: [('f', <class 'float'>)]

Evaluates the six hump camel function for a collection of points given in H["x"]. Additionally evaluates the gradient if "grad" is a field in sim_specs["out"] and pauses for sim_specs["user"]["pause_time"]] if defined.

See also

test_uniform_sampling.py # noqa

six_hump_camel.six_hump_camel_simple(x, _, sim_specs)

Input Fields: ['x']

Output Datatypes: [('f', <class 'float'>)]

Evaluates the six hump camel function for a single point x.

See also

test_fast_alloc.py # noqa

six_hump_camel.persistent_six_hump_camel(H, persis_info, sim_specs, libE_info)

Similar to six_hump_camel, but runs in persistent mode.

six_hump_camel.py
  1"""
  2This module contains various versions that evaluate the six-hump camel function.
  3
  4Six-hump camel function is documented here:
  5  https://www.sfu.ca/~ssurjano/camel6.html
  6
  7"""
  8
  9__all__ = [
 10    "six_hump_camel",
 11    "six_hump_camel_simple",
 12    "persistent_six_hump_camel",
 13]
 14
 15import sys
 16import time
 17
 18import numpy as np
 19
 20from libensemble.message_numbers import EVAL_SIM_TAG, FINISHED_PERSISTENT_SIM_TAG, PERSIS_STOP, STOP_TAG
 21from libensemble.specs import input_fields, output_data
 22from libensemble.tools.persistent_support import PersistentSupport
 23
 24
 25@input_fields(["x"])
 26@output_data([("f", float)])
 27def six_hump_camel(H, persis_info, sim_specs, libE_info):
 28    """
 29    Evaluates the six hump camel function for a collection of points given in ``H["x"]``.
 30    Additionally evaluates the gradient if ``"grad"`` is a field in
 31    ``sim_specs["out"]`` and pauses for ``sim_specs["user"]["pause_time"]]`` if
 32    defined.
 33
 34    .. seealso::
 35        `test_uniform_sampling.py  <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_uniform_sampling.py>`_ # noqa
 36    """
 37
 38    batch = len(H["x"])
 39    H_o = np.zeros(batch, dtype=sim_specs["out"])
 40
 41    for i, x in enumerate(H["x"]):
 42        H_o["f"][i] = six_hump_camel_func(x)
 43
 44        if "grad" in H_o.dtype.names:
 45            H_o["grad"][i] = six_hump_camel_grad(x)
 46
 47        if "user" in sim_specs and "pause_time" in sim_specs["user"]:
 48            time.sleep(sim_specs["user"]["pause_time"])
 49
 50    return H_o, persis_info
 51
 52
 53@input_fields(["x"])
 54@output_data([("f", float)])
 55def six_hump_camel_simple(x, _, sim_specs):
 56    """
 57    Evaluates the six hump camel function for a single point ``x``.
 58
 59    .. seealso::
 60        `test_fast_alloc.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_fast_alloc.py>`_ # noqa
 61    """
 62
 63    H_o = np.zeros(1, dtype=sim_specs["out"])
 64
 65    H_o["f"] = six_hump_camel_func(x[0][0][:2])  # Ignore more than 2 entries of x
 66
 67    if sim_specs["user"].get("pause_time"):
 68        time.sleep(sim_specs["user"]["pause_time"])
 69
 70    if sim_specs["user"].get("rand"):
 71        H_o["f"] += np.random.normal(0, 1)
 72
 73    return H_o
 74
 75
 76def persistent_six_hump_camel(H, persis_info, sim_specs, libE_info):
 77    """
 78    Similar to ``six_hump_camel``, but runs in persistent mode.
 79    """
 80
 81    ps = PersistentSupport(libE_info, EVAL_SIM_TAG)
 82
 83    # Either start with a work item to process - or just start and wait for data
 84    if H.size > 0:
 85        tag = None
 86        Work = None
 87        calc_in = H
 88    else:
 89        tag, Work, calc_in = ps.recv()
 90
 91    while tag not in [STOP_TAG, PERSIS_STOP]:
 92        # calc_in: This should either be a function (unpack_work ?) or included/unpacked in ps.recv/ps.send_recv.
 93        if Work is not None:
 94            persis_info = Work.get("persis_info", persis_info)
 95            libE_info = Work.get("libE_info", libE_info)
 96
 97        # Call standard six_hump_camel sim
 98        H_o, persis_info = six_hump_camel(calc_in, persis_info, sim_specs, libE_info)
 99
100        tag, Work, calc_in = ps.send_recv(H_o)
101
102    final_return = None
103
104    # Overwrite final point - for testing only
105    if sim_specs["user"].get("replace_final_fields", 0):
106        calc_in = np.ones(1, dtype=[("x", float, (2,))])
107        H_o, persis_info = six_hump_camel(calc_in, persis_info, sim_specs, libE_info)
108        final_return = H_o
109
110    return final_return, persis_info, FINISHED_PERSISTENT_SIM_TAG
111
112
113def six_hump_camel_func(x):
114    """
115    Definition of the six-hump camel
116    """
117    x1 = x[0]
118    x2 = x[1]
119    term1 = (4 - 2.1 * x1**2 + (x1**4) / 3) * x1**2
120    term2 = x1 * x2
121    term3 = (-4 + 4 * x2**2) * x2**2
122
123    return term1 + term2 + term3
124
125
126def six_hump_camel_grad(x):
127    """
128    Definition of the six-hump camel gradient
129    """
130
131    x1 = x[0]
132    x2 = x[1]
133    grad = np.zeros(2)
134
135    grad[0] = 2.0 * (x1**5 - 4.2 * x1**3 + 4.0 * x1 + 0.5 * x2)
136    grad[1] = x1 + 16 * x2**3 - 8 * x2
137
138    return grad
139
140
141if __name__ == "__main__":
142    x = (float(sys.argv[1]), float(sys.argv[2]))
143    result = six_hump_camel_func(x)
144    print(result)

chwirut

chwirut1.chwirut_eval(H, _, sim_specs)

Evaluates the chwirut objective function at a given set of points in H["x"]. If "obj_component" is a field in sim_specs["out"], only that component of the objective will be evaluated. Otherwise, all 214 components are evaluated and returned in the "fvec" field.

See also

test_persistent_aposmm_pounders.py # noqa for an example where the entire fvec is computed each call.

See also

test_uniform_sampling_one_residual_at_a_time.py # noqa for an example where one component of fvec is computed per call

noisy_vector_mapping

This module contains a test noisy function

noisy_vector_mapping.func_wrapper(H, persis_info, sim_specs, libE_info)

Wraps an objective function

noisy_vector_mapping.noisy_function(x)
noisy_vector_mapping.py
 1"""
 2This module contains a test noisy function
 3"""
 4
 5import numpy as np
 6from numpy import cos, sin
 7from numpy.linalg import norm
 8
 9
10def func_wrapper(H, persis_info, sim_specs, libE_info):
11    """
12    Wraps an objective function
13
14    .. seealso::
15        `test_persistent_fd_param_finder.py` <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_fd_param_finder.py>`_ # noqa
16    """
17
18    batch = len(H["x"])
19    H0 = np.zeros(batch, dtype=sim_specs["out"])
20
21    for i, x in enumerate(H["x"]):
22        H0["f_val"][i] = noisy_function(x)[H["f_ind"][i]]
23
24    return H0, persis_info
25
26
27def noisy_function(x):
28    """ """
29    x1 = x[0]
30    x2 = x[1]
31    term1 = (4 - 2.1 * x1**2 + (x1**4) / 3) * x1**2
32    term2 = x1 * x2
33    term3 = (-4 + 4 * x2**2) * x2**2
34
35    phi1 = 0.9 * sin(100 * norm(x, 1)) * cos(100 * norm(x, np.inf)) + 0.1 * cos(norm(x, 2))
36    phi1 = phi1 * (4 * phi1**2 - 3)
37
38    phi2 = 0.8 * sin(100 * norm(x, 1)) * cos(100 * norm(x, np.inf)) + 0.2 * cos(norm(x, 2))
39    phi2 = phi2 * (4 * phi2**2 - 3)
40
41    phi3 = 0.7 * sin(100 * norm(x, 1)) * cos(100 * norm(x, np.inf)) + 0.3 * cos(norm(x, 2))
42    phi3 = phi3 * (4 * phi3**2 - 3)
43
44    F = np.zeros(3)
45    F[0] = (1 + 1e-1 * phi1) * term1
46    F[1] = (1 + 1e-2 * phi2) * term2
47    F[2] = (1 + 1e-3 * phi3) * term3
48
49    return F

periodic_func

This module contains a periodic test function

periodic_func.func_wrapper(H, persis_info, sim_specs, libE_info)

Wraps an objective function

periodic_func.periodic_func(x)

This function is periodic

borehole

borehole.borehole(H, persis_info, sim_specs, _)

Wraps the borehole function

borehole.borehole_func(x)

This evaluates the Borehole function for n-by-8 input matrix x, and returns the flow rate through the Borehole. (Harper and Gupta, 1983) input:

Parameters:

x (numpy.typing.NDArray) –

x[:,0]: Tu, transmissivity of upper aquifer (m^2/year)
x[:,1]: Tl, transmissivity of lower aquifer (m^2/year)
x[:,2]: Hu, potentiometric head of upper aquifer (m)
x[:,3]: Hl, potentiometric head of lower aquifer (m)
x[:,4]: r, radius of influence (m)
x[:,5]: rw, radius of borehole (m)
x[:,6]: Kw, hydraulic conductivity of borehole (m/year)
x[:,7]: L, length of borehole (m)

Returns:

f – vector of dimension (n, 1): flow rate through the Borehole (m^3/year)

Return type:

numpy.ndarray

borehole.gen_borehole_input(n)

Generates and returns n inputs for the Borehole function, according to distributions outlined in Harper and Gupta (1983).

input:

n: number of input to generate

output:

matrix of (n, 8), input to borehole_func(x) function

executor_hworld

executor_hworld.executor_hworld(H, _, sim_specs, info)

Input Fields: ['x']

Output Datatypes: [('f', <class 'float'>), ('cstat', <class 'int'>)]

Tests launching and polling task and exiting on task finish

executor_hworld.py
  1import numpy as np
  2
  3from libensemble.message_numbers import (
  4    MAN_SIGNAL_FINISH,
  5    TASK_FAILED,
  6    UNSET_TAG,
  7    WORKER_DONE,
  8    WORKER_KILL_ON_ERR,
  9    WORKER_KILL_ON_TIMEOUT,
 10)
 11from libensemble.sim_funcs.six_hump_camel import six_hump_camel_func
 12from libensemble.specs import input_fields, output_data
 13
 14__all__ = ["executor_hworld"]
 15
 16# Alt send values through X
 17sim_ended_count = 0
 18
 19
 20def custom_polling_loop(exctr, task, timeout_sec=5.0, delay=0.3):
 21    import time
 22
 23    calc_status = UNSET_TAG  # Sim func determines status of libensemble calc - returned to worker
 24
 25    while task.runtime < timeout_sec:
 26        time.sleep(delay)
 27
 28        if exctr.manager_kill_received():
 29            exctr.kill(task)
 30            calc_status = MAN_SIGNAL_FINISH  # Worker will pick this up and close down
 31            print(f"Task {task.id} killed by manager on worker {exctr.workerID}")
 32            break
 33
 34        task.poll()
 35        if task.finished:
 36            break
 37        elif task.state == "RUNNING":
 38            print(f"Task {task.id} still running on worker {exctr.workerID} ....")
 39
 40        if task.stdout_exists():
 41            if "Error" in task.read_stdout():
 42                print(
 43                    "Found (deliberate) Error in output file - cancelling " f"task {task.id} on worker {exctr.workerID}"
 44                )
 45                exctr.kill(task)
 46                calc_status = WORKER_KILL_ON_ERR
 47                break
 48
 49    # After exiting loop
 50    if task.finished:
 51        print(f"Task {task.id} done on worker {exctr.workerID}")
 52        # Fill in calc_status if not already
 53        if calc_status == UNSET_TAG:
 54            if task.state == "FINISHED":  # Means finished successfully
 55                calc_status = WORKER_DONE
 56            elif task.state == "FAILED":
 57                calc_status = TASK_FAILED
 58
 59    else:
 60        # assert task.state == 'RUNNING', "task.state expected to be RUNNING. Returned: " + str(task.state)
 61        print(f"Task {task.id} timed out - killing on worker {exctr.workerID}")
 62        exctr.kill(task)
 63        if task.finished:
 64            print(f"Task {task.id} done on worker {exctr.workerID}")
 65        calc_status = WORKER_KILL_ON_TIMEOUT
 66
 67    return task, calc_status
 68
 69
 70@input_fields(["x"])
 71@output_data([("f", float), ("cstat", int)])
 72def executor_hworld(H, _, sim_specs, info):
 73    """
 74    Tests launching and polling task and exiting on task finish
 75    """
 76
 77    exctr = info["executor"]
 78    cores = sim_specs["user"]["cores"]
 79    ELAPSED_TIMEOUT = "elapsed_timeout" in sim_specs["user"]
 80
 81    wait = False
 82    args_for_sim = "sleep 1"
 83    calc_status = UNSET_TAG
 84
 85    batch = len(H["x"])
 86    H_o = np.zeros(batch, dtype=sim_specs["out"])
 87
 88    if "six_hump_camel" not in exctr.default_app("sim").full_path:
 89        global sim_ended_count
 90        sim_ended_count += 1
 91        print("sim_ended_count", sim_ended_count, flush=True)
 92
 93        if ELAPSED_TIMEOUT:
 94            args_for_sim = "sleep 60"  # Manager kill - if signal received else completes
 95            timeout = 65.0
 96
 97        else:
 98            timeout = 6.0
 99            launch_shc = False
100
101            if sim_ended_count == 1:
102                args_for_sim = "sleep 1"  # Should finish
103            elif sim_ended_count == 2:
104                args_for_sim = "sleep 1 Error"  # Worker kill on error
105            elif sim_ended_count == 3:
106                wait = True
107                args_for_sim = "sleep 1"  # Should finish
108                launch_shc = True
109            elif sim_ended_count == 4:
110                args_for_sim = "sleep 8"  # Worker kill on timeout
111                timeout = 1.0
112            elif sim_ended_count == 5:
113                args_for_sim = "sleep 2 Fail"  # Manager kill - if signal received else completes
114
115        task = exctr.submit(calc_type="sim", num_procs=cores, app_args=args_for_sim, hyperthreads=True)
116
117        if wait:
118            task.wait()
119            if not task.finished:
120                calc_status = UNSET_TAG
121            if task.state == "FINISHED":
122                calc_status = WORKER_DONE
123            elif task.state == "FAILED":
124                calc_status = TASK_FAILED
125
126        else:
127            if sim_ended_count >= 2:
128                calc_status = exctr.polling_loop(task, timeout=timeout, delay=0.3, poll_manager=True)
129                if sim_ended_count == 2 and task.stdout_exists() and "Error" in task.read_stdout():
130                    calc_status = WORKER_KILL_ON_ERR
131            else:
132                task, calc_status = custom_polling_loop(exctr, task, timeout)
133
134    else:
135        launch_shc = True
136        calc_status = UNSET_TAG
137
138        # Comparing six_hump_camel output, directly called vs. submitted as app
139        for i, x in enumerate(H["x"]):
140            H_o["f"][i] = six_hump_camel_func(x)
141            if launch_shc:
142                # Test launching a named app.
143                app_args = " ".join(str(val) for val in list(x[:]))
144                task = exctr.submit(app_name="six_hump_camel", num_procs=1, app_args=app_args)
145                task.wait()
146                output = np.float64(task.read_stdout())
147                assert np.isclose(H_o["f"][i], output)
148                calc_status = WORKER_DONE
149
150    # This is just for testing at calling script level - status of each task
151    H_o["cstat"] = calc_status
152
153    return H_o, calc_status