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.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 insim_specs['out']
and pauses forsim_specs['user']['pause_time']]
if defined.See also
- 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.See also
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 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_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
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.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