persis_info

Holds persistent information that can be updated during the ensemble.

An initialized persis_info dictionary can be provided to the libE() call or as an attribute of the Ensemble class.

Dictionary keys that have an integer value contain entries that are passed to and from the corresponding workers. These are received in the persis_info argument of user functions, and returned as the optional second return value.

A typical example is a random number generator stream to be used in consecutive calls to a generator (see add_unique_random_streams())

All other entries persist on the manager and can be updated in the calling script between ensemble invocations, or in the allocation function.

Examples:

libensemble/libensemble/gen_funcs/sampling.py
 1def uniform_random_sample(_, persis_info, gen_specs):
 2    """
 3    Generates ``gen_specs["user"]["gen_batch_size"]`` points uniformly over the domain
 4    defined by ``gen_specs["user"]["ub"]`` and ``gen_specs["user"]["lb"]``.
 5
 6    .. seealso::
 7        `test_uniform_sampling.py <https://github.com/Libensemble/libensemble/blob/develop/libensemble/tests/functionality_tests/test_uniform_sampling.py>`_ # noqa
 8    """
 9    ub = gen_specs["user"]["ub"]
10    lb = gen_specs["user"]["lb"]
11
12    n = len(lb)
13    b = gen_specs["user"]["gen_batch_size"]
14
15    H_o = np.zeros(b, dtype=gen_specs["out"])
16
17    H_o["x"] = persis_info["rand_stream"].uniform(lb, ub, (b, n))
18
19    return H_o, persis_info
20
21
libensemble/alloc_funcs/fast_alloc.py
1    for wid in support.avail_worker_ids(gen_workers=False):
2        persis_info = support.skip_canceled_points(H, persis_info)
3        if persis_info["next_to_give"] < len(H):
4            try:
5                Work[wid] = support.sim_work(wid, H, sim_specs["in"], [persis_info["next_to_give"]], [])
6            except InsufficientFreeResources:
7                break
8            persis_info["next_to_give"] += 1
9
libensemble/alloc_funcs/start_only_persistent.py
 1        avail_workers = support.avail_worker_ids(persistent=False, zero_resource_workers=True, gen_workers=True)
 2
 3        for wid in avail_workers:
 4            if gen_count < user.get("num_active_gens", 1):
 5                # Finally, start a persistent generator as there is nothing else to do.
 6                try:
 7                    Work[wid] = support.gen_work(
 8                        wid,
 9                        gen_specs.get("in", []),
10                        range(len(H)),
11                        persis_info.get(wid),
12                        persistent=True,
13                        active_recv=active_recv_gen,
14                    )
15                except InsufficientFreeResources:
16                    break
17
18                persis_info["num_gens_started"] = persis_info.get("num_gens_started", 0) + 1
19                gen_count += 1
20
libensemble/alloc_funcs/start_only_persistent.py
1    if gen_count < persis_info.get("num_gens_started", 0):
2        # When a persistent worker is done, trigger a shutdown (returning exit condition of 1)
3        return Work, persis_info, 1
4

When there are repeated calls to libE() or ensemble.run(), users may need to modify or reset the contents of persis_info in some cases.

See also

From: support.py

persis_info_1 = {
    "total_gen_calls": 0,  # Counts gen calls in alloc_f
    "last_worker": 0,  # Remembers last gen worker in alloc_f
    "next_to_give": 0,  # Remembers next H row to give in alloc_f
}

persis_info_1[0] = {
    "run_order": {},  # Used by manager to remember run order
    "total_runs": 0,  # Used by manager to count total runs
    "rand_stream": np.random.default_rng(1),
}