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:
- 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 insim_specs["out"]
and pauses forsim_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 insim_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
See also
test_persistent_fd_param_finder.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/regression_tests/test_persistent_fd_param_finder.py>`_ # noqa
- 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