From 4318ae318aec5f9b576111799be2026afd06b2f2 Mon Sep 17 00:00:00 2001 From: Michele Ceriotti Date: Sat, 30 Nov 2024 10:00:40 +0100 Subject: [PATCH] Implement defining and storing a separate PRNG for the random rotations --- .../random_liquid_water/input.xml | 3 +- ipi/engine/forcefields.py | 43 ++++++++++++------- ipi/inputs/forcefields.py | 12 ++++++ 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/examples/features/o3_averaging/random_liquid_water/input.xml b/examples/features/o3_averaging/random_liquid_water/input.xml index 4a782ce2a..e8b196b7e 100644 --- a/examples/features/o3_averaging/random_liquid_water/input.xml +++ b/examples/features/o3_averaging/random_liquid_water/input.xml @@ -16,7 +16,8 @@
h2o-noo3
- True + True + 54321 diff --git a/ipi/engine/forcefields.py b/ipi/engine/forcefields.py index 3abaa2648..f74e06831 100644 --- a/ipi/engine/forcefields.py +++ b/ipi/engine/forcefields.py @@ -231,7 +231,10 @@ def _poll_loop(self): finished. """ - info(f" @ForceField ({self.name}): Starting the polling thread main loop.", verbosity.low) + info( + f" @ForceField ({self.name}): Starting the polling thread main loop.", + verbosity.low, + ) while self._doloop[0]: time.sleep(self.latency) if len(self.requests) > 0: @@ -242,7 +245,7 @@ def release(self, request, lock=True): Args: request: The id of the job to release. - lock: whether we should apply a threadlock here + lock: whether we should apply a threadlock here """ """Frees up a request.""" @@ -429,7 +432,7 @@ def __init__( super().__init__(latency, offset, name, pars, dopbc, active, threaded) if pars is None: - pars = {} # defaults no pars + pars = {} # defaults no pars self.pes = pes try: self.driver = __drivers__[self.pes](verbose=verbosity.high, **pars) @@ -1170,7 +1173,7 @@ def __init__( pars=pars, dopbc=dopbc, active=active, - threaded=True, # hardcoded, otherwise won't work! + threaded=True, # hardcoded, otherwise won't work! ) if len(fflist) == 0: raise ValueError( @@ -1467,30 +1470,40 @@ def __init__( dopbc=True, active=np.array([-1]), threaded=True, - ffsocket = None, - ffdirect = None, + prng=None, + ffsocket=None, + ffdirect=None, random=False, inversion=False, grid_order=1, grid_mode="lebedev", ): - super(FFRotations, self).__init__( # force threaded execution to handle sub-ffield - latency, offset, name, pars, dopbc, active, threaded=True + super( + FFRotations, self + ).__init__( # force threaded execution to handle sub-ffield + latency, offset, name, pars, dopbc, active, threaded=True ) - # TODO: initialize and save (probably better to use different PRNG than the one from the simulation) - self.prng = Random() + if prng is None: + warning("No PRNG provided, will initialize one", verbosity.low) + self.prng = Random() + else: + self.prng = prng self.ffsocket = ffsocket self.ffdirect = ffdirect if ffsocket is None or self.ffsocket.name == "__DUMMY__": if ffdirect is None or self.ffdirect.name == "__DUMMY__": - raise ValueError("Must specify a non-default value for either `ffsocket` or `ffdirect` into `ffrotations`") + raise ValueError( + "Must specify a non-default value for either `ffsocket` or `ffdirect` into `ffrotations`" + ) else: - self.ff=self.ffdirect + self.ff = self.ffdirect elif ffdirect is None or self.ffdirect.name == "__DUMMY__": self.ff = self.ffsocket else: - raise ValueError("Cannot specify both `ffsocket` and `ffdirect` into `ffrotations`") + raise ValueError( + "Cannot specify both `ffsocket` and `ffdirect` into `ffrotations`" + ) self.random = random self.inversion = inversion @@ -1632,12 +1645,12 @@ def gather(self, r): for ff_r in r["ff_handles"]: self.ff.release(ff_r) - + def poll(self): """Polls the forcefield object to check if it has finished.""" with self._threadlock: - for r in self.requests: + for r in self.requests: if "ff_handles" in r and r["status"] != "Done" and self.check_finish(r): r["t_finished"] = time.time() self.gather(r) diff --git a/ipi/inputs/forcefields.py b/ipi/inputs/forcefields.py index f2b205b8a..a9a8956a7 100644 --- a/ipi/inputs/forcefields.py +++ b/ipi/inputs/forcefields.py @@ -28,6 +28,8 @@ from ipi.inputs.initializer import * from ipi.utils.inputvalue import * from ipi.utils.messages import verbosity, warning +from ipi.utils.prng import Random +from ipi.inputs.prng import InputRandom __all__ = [ "InputFFSocket", @@ -980,6 +982,14 @@ class InputFFRotations(InputForceField): }, ) + fields["prng"] = ( + InputRandom, + { + "help": InputRandom.default_help, + "default": input_default(factory=Random), + }, + ) + fields["ffsocket"] = ( InputFFSocket, { @@ -1004,6 +1014,7 @@ def store(self, ff): self.grid_order.store(ff.grid_order) self.grid_mode.store(ff.grid_mode) self.random.store(ff.random) + self.prng.store(ff.prng) self.ffsocket.store(ff.ffsocket) self.ffdirect.store(ff.ffdirect) @@ -1018,6 +1029,7 @@ def fetch(self): dopbc=self.pbc.fetch(), active=self.activelist.fetch(), threaded=self.threaded.fetch(), + prng=self.prng.fetch(), ffsocket=self.ffsocket.fetch(), ffdirect=self.ffdirect.fetch(), grid_order=self.grid_order.fetch(),