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.persistent_six_hump_camel(H, persis_info, sim_specs, libE_info)

Similar to six_hump_camel, but runs in persistent mode.

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

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.

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

Launches an app setting GPU resources

The standard test apps do not run on GPU, but demonstrates accessing resource information to set CUDA_VISIBLE_DEVICES, and typical run configuration.

six_hump_camel.six_hump_camel_simple(x, persis_info, sim_specs, _)

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

See also

test_fast_alloc.py # noqa

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

Evaluates the six hump camel for a collection of points given in H['x'] via the executor, supporting variable sized simulations/resources, as determined by the generator.

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__all__ = [
  9    "six_hump_camel",
 10    "six_hump_camel_simple",
 11    "six_hump_camel_with_variable_resources",
 12    "six_hump_camel_CUDA_variable_resources",
 13    "persistent_six_hump_camel",
 14]
 15
 16import os
 17import sys
 18import numpy as np
 19import time
 20from libensemble.executors.executor import Executor
 21from libensemble.message_numbers import UNSET_TAG, WORKER_DONE, TASK_FAILED
 22from libensemble.resources.resources import Resources
 23from libensemble.tools.persistent_support import PersistentSupport
 24from libensemble.message_numbers import STOP_TAG, PERSIS_STOP, EVAL_SIM_TAG, FINISHED_PERSISTENT_SIM_TAG
 25
 26
 27def six_hump_camel(H, persis_info, sim_specs, _):
 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_old_aposmm_with_gradients.py  <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_old_aposmm_with_gradients.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
 53def six_hump_camel_simple(x, persis_info, sim_specs, _):
 54    """
 55    Evaluates the six hump camel function for a single point ``x``.
 56
 57    .. seealso::
 58        `test_fast_alloc.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_fast_alloc.py>`_ # noqa
 59    """
 60
 61    H_o = np.zeros(1, dtype=sim_specs["out"])
 62
 63    H_o["f"] = six_hump_camel_func(x[0][0])
 64
 65    if "pause_time" in sim_specs["user"]:
 66        time.sleep(sim_specs["user"]["pause_time"])
 67
 68    return H_o, persis_info
 69
 70
 71def six_hump_camel_with_variable_resources(H, persis_info, sim_specs, libE_info):
 72    """
 73    Evaluates the six hump camel for a collection of points given in ``H['x']``
 74    via the executor, supporting variable sized simulations/resources, as
 75    determined by the generator.
 76
 77    .. seealso::
 78        `test_uniform_sampling_with_variable_resources.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_uniform_sampling_with_variable_resources.py>`_ # noqa
 79    """
 80
 81    batch = len(H["x"])
 82    H_o = np.zeros(batch, dtype=sim_specs["out"])
 83    app = sim_specs["user"].get("app", "helloworld")
 84    dry_run = sim_specs["user"].get("dry_run", False)  # dry_run only prints run lines in ensemble.log
 85    set_cores_by_rsets = True  # If True use rset count to set num procs, else use all available to this worker.
 86    core_multiplier = 1  # Only used with set_cores_by_rsets as a multiplier.
 87
 88    exctr = Executor.executor  # Get Executor
 89    task_states = []
 90    for i, x in enumerate(H["x"]):
 91        nprocs = None  # Will be as if argument is not present
 92        if set_cores_by_rsets:
 93            resources = Resources.resources.worker_resources
 94            nprocs = resources.num_rsets * core_multiplier
 95
 96        inpt = None  # Will be as if argument is not present
 97        if app == "six_hump_camel":
 98            inpt = " ".join(map(str, H["x"][i]))
 99
100        task = exctr.submit(
101            app_name=app,
102            app_args=inpt,
103            num_procs=nprocs,
104            stdout="out.txt",
105            stderr="err.txt",
106            dry_run=dry_run,
107        )
108        task.wait()
109        # while(not task.finished):
110        #     time.sleep(0.1)
111        #     task.poll()
112
113        task_states.append(task.state)
114
115        if app == "six_hump_camel":
116            # H_o['f'][i] = float(task.read_stdout())  # Reads whole file
117            with open("out.txt") as f:
118                H_o["f"][i] = float(f.readline().strip())  # Read just first line
119        else:
120            # To return something in test
121            H_o["f"][i] = six_hump_camel_func(x)
122
123    calc_status = UNSET_TAG  # Returns to worker
124    if all(t == "FINISHED" for t in task_states):
125        calc_status = WORKER_DONE
126    elif any(t == "FAILED" for t in task_states):
127        calc_status = TASK_FAILED
128
129    return H_o, persis_info, calc_status
130
131
132def six_hump_camel_CUDA_variable_resources(H, persis_info, sim_specs, libE_info):
133    """Launches an app setting GPU resources
134
135    The standard test apps do not run on GPU, but demonstrates accessing resource
136    information to set ``CUDA_VISIBLE_DEVICES``, and typical run configuration.
137    """
138    x = H["x"][0]
139    H_o = np.zeros(1, dtype=sim_specs["out"])
140
141    # Interrogate resources available to this worker
142    resources = Resources.resources.worker_resources
143    slots = resources.slots
144
145    assert resources.matching_slots, "Error: Cannot set CUDA_VISIBLE_DEVICES when unmatching slots on nodes {}".format(
146        slots
147    )
148
149    resources.set_env_to_slots("CUDA_VISIBLE_DEVICES")
150    num_nodes = resources.local_node_count
151    cores_per_node = resources.slot_count  # One CPU per GPU
152
153    print(
154        "Worker {}: CUDA_VISIBLE_DEVICES={}  \tnodes {} ppn {}  slots {}".format(
155            libE_info["workerID"], os.environ["CUDA_VISIBLE_DEVICES"], num_nodes, cores_per_node, slots
156        )
157    )
158
159    # Create application input file
160    inpt = " ".join(map(str, x))
161    exctr = Executor.executor  # Get Executor
162
163    # Launch application via system MPI runner, using assigned resources.
164    task = exctr.submit(
165        app_name="six_hump_camel",
166        app_args=inpt,
167        num_nodes=num_nodes,
168        procs_per_node=cores_per_node,
169        stdout="out.txt",
170        stderr="err.txt",
171    )
172
173    task.wait()  # Wait for run to complete
174
175    # Access app output
176    with open("out.txt") as f:
177        H_o["f"] = float(f.readline().strip())  # Read just first line
178
179    calc_status = WORKER_DONE if task.state == "FINISHED" else "FAILED"
180    return H_o, persis_info, calc_status
181
182
183def persistent_six_hump_camel(H, persis_info, sim_specs, libE_info):
184    """
185    Similar to ``six_hump_camel``, but runs in persistent mode.
186    """
187
188    ps = PersistentSupport(libE_info, EVAL_SIM_TAG)
189
190    # Either start with a work item to process - or just start and wait for data
191    if H.size > 0:
192        tag = None
193        Work = None
194        calc_in = H
195    else:
196        tag, Work, calc_in = ps.recv()
197
198    while tag not in [STOP_TAG, PERSIS_STOP]:
199
200        # calc_in: This should either be a function (unpack_work ?) or included/unpacked in ps.recv/ps.send_recv.
201        if Work is not None:
202            persis_info = Work.get("persis_info", persis_info)
203            libE_info = Work.get("libE_info", libE_info)
204
205        # Call standard six_hump_camel sim
206        H_o, persis_info = six_hump_camel(calc_in, persis_info, sim_specs, libE_info)
207
208        tag, Work, calc_in = ps.send_recv(H_o)
209
210    final_return = None
211
212    # Overwrite final point - for testing only
213    if sim_specs["user"].get("replace_final_fields", 0):
214        calc_in = np.ones(1, dtype=[("x", float, (2,))])
215        H_o, persis_info = six_hump_camel(calc_in, persis_info, sim_specs, libE_info)
216        final_return = H_o
217
218    return final_return, persis_info, FINISHED_PERSISTENT_SIM_TAG
219
220
221def six_hump_camel_func(x):
222    """
223    Definition of the six-hump camel
224    """
225    x1 = x[0]
226    x2 = x[1]
227    term1 = (4 - 2.1 * x1**2 + (x1**4) / 3) * x1**2
228    term2 = x1 * x2
229    term3 = (-4 + 4 * x2**2) * x2**2
230
231    return term1 + term2 + term3
232
233
234def six_hump_camel_grad(x):
235    """
236    Definition of the six-hump camel gradient
237    """
238
239    x1 = x[0]
240    x2 = x[1]
241    grad = np.zeros(2)
242
243    grad[0] = 2.0 * (x1**5 - 4.2 * x1**3 + 4.0 * x1 + 0.5 * x2)
244    grad[1] = x1 + 16 * x2**3 - 8 * x2
245
246    return grad
247
248
249if __name__ == "__main__":
250    x = (float(sys.argv[1]), float(sys.argv[2]))
251    result = six_hump_camel_func(x)
252    print(result)

chwirut

chwirut1.chwirut_eval(H, persis_info, 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_old_aposmm_pounders.py for an example where the entire fvec is computed each call.

See also

test_old_aposmm_one_residual_at_a_time.py 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.linalg import norm
 7from numpy import cos, sin
 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
30    x1 = x[0]
31    x2 = x[1]
32    term1 = (4 - 2.1 * x1**2 + (x1**4) / 3) * x1**2
33    term2 = x1 * x2
34    term3 = (-4 + 4 * x2**2) * x2**2
35
36    phi1 = 0.9 * sin(100 * norm(x, 1)) * cos(100 * norm(x, np.inf)) + 0.1 * cos(norm(x, 2))
37    phi1 = phi1 * (4 * phi1**2 - 3)
38
39    phi2 = 0.8 * sin(100 * norm(x, 1)) * cos(100 * norm(x, np.inf)) + 0.2 * cos(norm(x, 2))
40    phi2 = phi2 * (4 * phi2**2 - 3)
41
42    phi3 = 0.7 * sin(100 * norm(x, 1)) * cos(100 * norm(x, np.inf)) + 0.3 * cos(norm(x, 2))
43    phi3 = phi3 * (4 * phi3**2 - 3)
44
45    F = np.zeros(3)
46    F[0] = (1 + 1e-1 * phi1) * term1
47    F[1] = (1 + 1e-2 * phi2) * term2
48    F[2] = (1 + 1e-3 * phi3) * term3
49
50    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 (matrix of dimension (n, 8), where n is the number of input configurations:) –

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

flow rate through the Borehole (m^3/year)

Return type

vector of dimension (n, 1)

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, persis_info, sim_specs, libE_info)

Tests launching and polling task and exiting on task finish

executor_hworld.py

  1from libensemble.executors.mpi_executor import MPIExecutor
  2from libensemble.message_numbers import (
  3    UNSET_TAG,
  4    WORKER_KILL_ON_ERR,
  5    MAN_SIGNAL_FINISH,
  6    WORKER_DONE,
  7    TASK_FAILED,
  8    WORKER_KILL_ON_TIMEOUT,
  9)
 10import numpy as np
 11import os
 12
 13__all__ = ["executor_hworld"]
 14
 15# Alt send values through X
 16sim_ended_count = 0
 17
 18
 19def custom_polling_loop(exctr, task, timeout_sec=5.0, delay=0.3):
 20    import time
 21
 22    calc_status = UNSET_TAG  # Sim func determines status of libensemble calc - returned to worker
 23
 24    while task.runtime < timeout_sec:
 25        time.sleep(delay)
 26
 27        exctr.manager_poll()
 28        if exctr.manager_signal == "finish":
 29            exctr.kill(task)
 30            calc_status = MAN_SIGNAL_FINISH  # Worker will pick this up and close down
 31            print("Task {} killed by manager on worker {}".format(task.id, exctr.workerID))
 32            break
 33
 34        task.poll()
 35        if task.finished:
 36            break
 37        elif task.state == "RUNNING":
 38            print("Task {} still running on worker {} ....".format(task.id, 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 "
 44                    "task {} on worker {}".format(task.id, exctr.workerID)
 45                )
 46                exctr.kill(task)
 47                calc_status = WORKER_KILL_ON_ERR
 48                break
 49
 50    # After exiting loop
 51    if task.finished:
 52        print("Task {} done on worker {}".format(task.id, exctr.workerID))
 53        # Fill in calc_status if not already
 54        if calc_status == UNSET_TAG:
 55            if task.state == "FINISHED":  # Means finished successfully
 56                calc_status = WORKER_DONE
 57            elif task.state == "FAILED":
 58                calc_status = TASK_FAILED
 59
 60    else:
 61        # assert task.state == 'RUNNING', "task.state expected to be RUNNING. Returned: " + str(task.state)
 62        print("Task {} timed out - killing on worker {}".format(task.id, exctr.workerID))
 63        exctr.kill(task)
 64        if task.finished:
 65            print("Task {} done on worker {}".format(task.id, exctr.workerID))
 66        calc_status = WORKER_KILL_ON_TIMEOUT
 67
 68    return task, calc_status
 69
 70
 71def executor_hworld(H, persis_info, sim_specs, libE_info):
 72    """Tests launching and polling task and exiting on task finish"""
 73    exctr = MPIExecutor.executor
 74    cores = sim_specs["user"]["cores"]
 75    USE_BALSAM = "balsam_test" in sim_specs["user"]
 76    ELAPSED_TIMEOUT = "elapsed_timeout" in sim_specs["user"]
 77
 78    wait = False
 79    args_for_sim = "sleep 1"
 80
 81    if ELAPSED_TIMEOUT:
 82        args_for_sim = "sleep 60"  # Manager kill - if signal received else completes
 83        timeout = 65.0
 84
 85    else:
 86        global sim_ended_count
 87        sim_ended_count += 1
 88        timeout = 6.0
 89        launch_shc = False
 90        print(sim_ended_count)
 91
 92        if sim_ended_count == 1:
 93            args_for_sim = "sleep 1"  # Should finish
 94        elif sim_ended_count == 2:
 95            args_for_sim = "sleep 1 Error"  # Worker kill on error
 96        elif sim_ended_count == 3:
 97            wait = True
 98            args_for_sim = "sleep 1"  # Should finish
 99            launch_shc = True
100        elif sim_ended_count == 4:
101            args_for_sim = "sleep 8"  # Worker kill on timeout
102            timeout = 1.0
103        elif sim_ended_count == 5:
104            args_for_sim = "sleep 2 Fail"  # Manager kill - if signal received else completes
105
106    if USE_BALSAM:
107        task = exctr.submit(
108            calc_type="sim",
109            num_procs=cores,
110            app_args=args_for_sim,
111            hyperthreads=True,
112            machinefile="notused",
113            stdout="notused",
114            wait_on_start=True,
115        )
116    else:
117        task = exctr.submit(calc_type="sim", num_procs=cores, app_args=args_for_sim, hyperthreads=True)
118
119    if wait:
120        task.wait()
121        if not task.finished:
122            calc_status = UNSET_TAG
123        if task.state == "FINISHED":
124            calc_status = WORKER_DONE
125        elif task.state == "FAILED":
126            calc_status = TASK_FAILED
127
128    else:
129        if not ELAPSED_TIMEOUT:
130            if sim_ended_count >= 2 and not USE_BALSAM:
131                calc_status = exctr.polling_loop(task, timeout=timeout, delay=0.3, poll_manager=True)
132                if sim_ended_count == 2 and task.stdout_exists() and "Error" in task.read_stdout():
133                    calc_status = WORKER_KILL_ON_ERR
134
135            else:
136                task, calc_status = custom_polling_loop(exctr, task, timeout)
137
138        else:
139            calc_status = exctr.polling_loop(task, timeout=timeout, delay=0.3, poll_manager=True)
140
141    if USE_BALSAM:
142        task.read_file_in_workdir("ensemble.log")
143        try:
144            task.read_stderr()
145        except ValueError:
146            pass
147
148        task = exctr.submit(
149            app_name="sim_hump_camel_dry_run",
150            num_procs=cores,
151            app_args=args_for_sim,
152            hyperthreads=True,
153            machinefile="notused",
154            stdout="notused",
155            wait_on_start=True,
156            dry_run=True,
157            stage_inout=os.getcwd(),
158        )
159
160        task.poll()
161        task.wait()
162
163    # This is temp - return something - so doing six_hump_camel_func again...
164    batch = len(H["x"])
165    H_o = np.zeros(batch, dtype=sim_specs["out"])
166    for i, x in enumerate(H["x"]):
167        H_o["f"][i] = six_hump_camel_func(x)
168        if launch_shc:
169            # Test launching a named app.
170            app_args = " ".join(str(val) for val in list(x[:]))
171            task = exctr.submit(app_name="six_hump_camel", num_procs=1, app_args=app_args)
172            task.wait()
173            output = np.float64(task.read_stdout())
174            assert np.isclose(H_o["f"][i], output)
175
176    # This is just for testing at calling script level - status of each task
177    H_o["cstat"] = calc_status
178
179    return H_o, persis_info, calc_status
180
181
182def six_hump_camel_func(x):
183    """
184    Definition of the six-hump camel
185    """
186    x1 = x[0]
187    x2 = x[1]
188    term1 = (4 - 2.1 * x1**2 + (x1**4) / 3) * x1**2
189    term2 = x1 * x2
190    term3 = (-4 + 4 * x2**2) * x2**2
191
192    return term1 + term2 + term3