import g4gen import multiprocessing import numpy as np import itertools class G4GeneratorProcess(multiprocessing.Process): def __init__(self, idnum, material, input_queue, output_queue, seed=None): multiprocessing.Process.__init__(self) self.idnum = idnum self.material = material self.input_queue = input_queue self.output_queue = output_queue self.seed = seed self.daemon = True def run(self): gen = g4gen.G4Generator(self.material, seed=self.seed) while True: ev = self.input_queue.get() ev.photon_start = gen.generate_photons(ev) self.output_queue.put(ev) def partition(num, partitions): '''Generator that returns num//partitions, with the last item including the remainder. Useful for partitioning a number into mostly equal parts while preserving the sum. >>> list(partition(800, 3)) [266, 266, 268] >>> sum(list(partition(800, 3))) 800 ''' step = num // partitions for i in xrange(partitions): if i < partitions - 1: yield step else: yield step + (num % partitions) def queue_iterator(nelements, queue): for i in xrange(nelements): yield queue.get() class G4ParallelGenerator(object): def __init__(self, nprocesses, material, base_seed=None): self.material = material self.vertex_queue = multiprocessing.Queue() self.photon_queue = multiprocessing.Queue() self.processes = [ G4GeneratorProcess(i, material, self.vertex_queue, self.photon_queue, seed=base_seed + i) for i in xrange(nprocesses) ] for p in self.processes: p.start() def generate_events(self, nevents, vertex_iterator): # Doing this to avoid a deadlock caused by putting to one queue while getting from another for ev in itertools.islice(vertex_iterator, nevents): self.vertex_queue.put(ev) return queue_iterator(nevents, self.photon_queue)