diff --git a/docs/source/pythonapi/capi.rst b/docs/source/pythonapi/capi.rst index 67eca009471..102bb3ad78b 100644 --- a/docs/source/pythonapi/capi.rst +++ b/docs/source/pythonapi/capi.rst @@ -35,6 +35,7 @@ Functions next_batch num_realizations plot_geometry + prn property_map reset reset_timers diff --git a/include/openmc/random_lcg.h b/include/openmc/random_lcg.h index 5aecafed3cb..4a9dc8057bf 100644 --- a/include/openmc/random_lcg.h +++ b/include/openmc/random_lcg.h @@ -112,5 +112,13 @@ extern "C" uint64_t openmc_get_stride(); extern "C" void openmc_set_stride(uint64_t new_stride); +//============================================================================== +//! Generate a pseudo-random number using OpenMC's RNG. +//! @param seed Pseudorandom number seed pointer +//! @return A random number between 0 and 1 +//============================================================================== + +extern "C" double openmc_prn(uint64_t* seed); + } // namespace openmc #endif // OPENMC_RANDOM_LCG_H diff --git a/openmc/lib/__init__.py b/openmc/lib/__init__.py index d2a794eb158..3da7fb0d4a5 100644 --- a/openmc/lib/__init__.py +++ b/openmc/lib/__init__.py @@ -58,7 +58,7 @@ def _uwuw_enabled(): from .mesh import * from .filter import * from .tally import * -from .settings import settings +from .settings import settings, prn from .math import * from .plot import * from .weight_windows import * diff --git a/openmc/lib/settings.py b/openmc/lib/settings.py index 4fba8d48b6e..c7f83e6405b 100644 --- a/openmc/lib/settings.py +++ b/openmc/lib/settings.py @@ -1,4 +1,4 @@ -from ctypes import c_int, c_int32, c_int64, c_double, c_char_p, c_bool, POINTER +from ctypes import c_int, c_int32, c_int64, c_uint64, c_double, c_char_p, c_bool, POINTER, byref from . import _dll from .core import _DLLGlobal @@ -14,6 +14,8 @@ _dll.openmc_get_seed.restype = c_int64 _dll.openmc_set_stride.argtypes = [c_int64] _dll.openmc_get_stride.restype = c_int64 +_dll.openmc_prn.argtypes = [POINTER(c_uint64)] +_dll.openmc_prn.restype = c_double _dll.openmc_get_n_batches.argtypes = [POINTER(c_int), c_bool] _dll.openmc_get_n_batches.restype = c_int _dll.openmc_get_n_batches.errcheck = _error_handler @@ -116,4 +118,23 @@ def get_batches(self, get_max_batches=True): return n_batches.value +def prn(seed): + """Generate a pseudo-random number using OpenMC's RNG + + Parameters + ---------- + seed : int + Pseudorandom number seed (will be modified in place) + + Returns + ------- + tuple of (float, int) + Random number between 0 and 1, and the updated seed + + """ + c_seed = c_uint64(seed) + random_value = _dll.openmc_prn(byref(c_seed)) + return random_value, c_seed.value + + settings = _Settings() diff --git a/src/random_lcg.cpp b/src/random_lcg.cpp index 29457569b94..a91e760bb8f 100644 --- a/src/random_lcg.cpp +++ b/src/random_lcg.cpp @@ -143,4 +143,9 @@ extern "C" void openmc_set_stride(uint64_t new_stride) prn_stride = new_stride; } +extern "C" double openmc_prn(uint64_t* seed) +{ + return prn(seed); +} + } // namespace openmc diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index eb4dc3dce66..a8107acafa8 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -1045,3 +1045,26 @@ def test_sample_external_source(run_in_tmpdir, mpi_intracomm): openmc.lib.init(["-c"]) openmc.lib.sample_external_source(100) openmc.lib.finalize() + + +def test_prn(pincell_model, mpi_intracomm): + openmc.lib.init() + + seed = 12345 + random_numbers = [] + for _ in range(10): + random_value, seed = openmc.lib.prn(seed) + random_numbers.append(random_value) + # Check that random values are in [0, 1) + assert 0.0 <= random_value < 1.0 + + # Check that we got different values (not all the same) + assert len(set(random_numbers)) > 1 + + # Check that using the same initial seed produces the same sequence + seed2 = 12345 + for expected_value in random_numbers: + random_value, seed2 = openmc.lib.prn(seed2) + assert random_value == pytest.approx(expected_value) + + openmc.lib.finalize()