diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICBrainProcess.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICBrainProcess.py index 76034327179229fe37d07a3a4e80777a415a9e95..221e7d7ca7ed329f6b40369b492495e3433847b1 100644 --- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICBrainProcess.py +++ b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICBrainProcess.py @@ -24,6 +24,7 @@ """ A distributed brain process that can be launched standalone on remote hosts. """ +from hbp_nrp_cle.brainsim import config from hbp_nrp_cle.brainsim.pynn import simulator as sim from hbp_nrp_cle.brainsim.pynn.PyNNControlAdapter import PyNNControlAdapter import hbp_nrp_cle.tf_framework.config as tf_config @@ -51,7 +52,7 @@ class MUSICBrainProcess(object): # tag to listen for MPI configuration/command messages MPI_MSG_TAG = 100 - def __init__(self, bibi_file): + def __init__(self, bibi_file, rng_seed): """ Load the distributed brain and construct MUSIC proxies for communication to/from the CLE. Nest will automatically allocate the brain in a round-robin @@ -74,6 +75,9 @@ class MUSICBrainProcess(object): "defined on target node!") brain_file = os.path.join(models_path, self._bibi.brainModel.file) + # set the RNG seed before initializing any PyNN interfaces in the brain controller + config.rng_seed = int(rng_seed) + # spawn CLE components that will handle loading the brain file and interfaces self._brain_controller = PyNNControlAdapter() self._brain_controller.initialize() @@ -192,10 +196,12 @@ if __name__ == '__main__': # pragma: no cover parser = argparse.ArgumentParser() parser.add_argument('--bibi-file', dest='bibi_file', help='the bibi file path to load', required=True) + parser.add_argument('--rng-seed', dest='rng_seed', + help='the global experiment RNG seed', required=True) args = parser.parse_args() # construct brain and proxies (expand environment variables in paths) - brain = MUSICBrainProcess(os.path.expandvars(args.bibi_file)) + brain = MUSICBrainProcess(os.path.expandvars(args.bibi_file), args.rng_seed) # run the brain until terminated, this is a blocking call brain.run() diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICLauncher.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICLauncher.py index 4714ac87a7417238bcffe2b8c8c732c5f94fd10d..2558bf09b1be521492a090e584175b769eac4327 100644 --- a/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICLauncher.py +++ b/hbp_nrp_music_interface/hbp_nrp_music_interface/launch/MUSICLauncher.py @@ -31,6 +31,8 @@ from hbp_nrp_music_interface.launch.host.LocalLauncher import LocalLauncher from hbp_nrp_music_interface.launch.host.LuganoLauncher import LuganoLauncher import os +import random +import sys class MUSICLauncher(object): @@ -78,20 +80,22 @@ class MUSICLauncher(object): # the MPI process launcher for the CLE and brain processes self.cle_server = None - def init(self, bibi, brain_processes): + def init(self, bibi, exd): """ Construct the MUSIC launch configuration that will spawn CLE + brain processes on distributed hosts. :param bibi The BIBI configuration to launch brain processes with. - :param brain_processes The number of brain processses (does not include CLE process). + :param exd The parsed ExDConf configuration to launch brain processes with. """ # create a host specific launcher if self._server_host == 'local': self._launcher = LocalLauncher() elif self._server_host == 'lugano': - self._launcher = LuganoLauncher(brain_processes + 1, self._timeout, self._reservation) + self._launcher = LuganoLauncher(exd.bibiConf.processes + 1, + self._timeout, + self._reservation) else: raise Exception('Unknown server host {}, cannot configure and launch MUSIC!' .format(self._server_host)) @@ -104,6 +108,9 @@ class MUSICLauncher(object): reservation_str = self._reservation if self._reservation else '' timeout_str = str(self._timeout).replace(' ', '_') + # extract the multiprocess RNG seed to use or generate one if needed + rng_seed = exd.rngSeed if exd.rngSeed is not None else random.randint(1, sys.maxint) + # build a MUSIC configuration script with correct brain ports, launchers and arugments # save it to the host launcher temp directory, this is the same for every host music_conf = bibi_music_config.MUSICConfiguration(bibi) @@ -116,12 +123,14 @@ class MUSICLauncher(object): '--reservation={}'.format(reservation_str), '--sim-id={}'.format(self._sim_id), '--timeout={}'.format(timeout_str), + '--rng-seed={}'.format(rng_seed), '--music'], 1) music_conf.add_application('BRAIN', brain_launcher, - ['--bibi-file={}'.format(self._bibi_file)], - brain_processes) + ['--bibi-file={}'.format(self._bibi_file), + '--rng-seed={}'.format(rng_seed)], + exd.bibiConf.processes) music_conf.save(self._launcher.local_tmpdir) # deploy the generated configuration files / launch scripts to the target host @@ -132,7 +141,7 @@ class MUSICLauncher(object): self.cle_server = MUSICMPILauncher() self.cle_server.add_host(self._launcher.hostname, self._launcher.host_tmpdir, - brain_processes + 1) + exd.bibiConf.processes + 1) # construct the mpi command line with the above host/launch information self.cle_server.build() diff --git a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_music_launcher.py b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_music_launcher.py index a051d9a34214d53c2ed0d8e0f846c4f725b7ff94..ae7945af936acac92a34b1847d25a95318cd6dfc 100644 --- a/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_music_launcher.py +++ b/hbp_nrp_music_interface/hbp_nrp_music_interface/tests/launch/test_music_launcher.py @@ -59,8 +59,13 @@ class TestMUSICLauncher(unittest.TestCase): @patch('hbp_nrp_music_interface.launch.MUSICLauncher.MUSICMPILauncher') def test_init(self, mock_mpi, mock_conf): + # mock the ExDConf and parameters + exd = Mock() + exd.rngSeed = 123456 + exd.bibiConf.processes = 10 + # mock all of the local launcher functionality - self.__launcher.init('bibi', 10) + self.__launcher.init('bibi', exd) # call to generate launch scripts self.__launcher._launcher.deploy.assert_called_once()