#!/usr/bin/env python import sys import optparse import time import multiprocessing import detectors import optics import gpu import g4gen from io import root import numpy as np import math import ROOT def info(type, value, tb): if hasattr(sys, 'ps1') or not sys.stderr.isatty(): # we are in interactive mode or we don't have a tty-like # device, so we call the default hook sys.__excepthook__(type, value, tb) else: import traceback, pdb # we are NOT in interactive mode, print the exception... traceback.print_exception(type, value, tb) print # ...then start the debugger in post-mortem mode. pdb.pm() sys.excepthook = info class GeneratorThread(multiprocessing.Process): def __init__(self, particle, energy, position, direction, nevents, material): multiprocessing.Process.__init__(self) self.particle = particle self.energy = energy self.position = position self.direction = direction self.nevents = nevents self.material = material self.queue = multiprocessing.Queue() def run(self): print >>sys.stderr, 'Starting generator thread...' generator = g4gen.G4Generator(self.material) for i in xrange(self.nevents): photons = generator.generate_photons(particle_name=self.particle, total_energy=self.energy, position=self.position, direction=self.direction) self.queue.put(photons) def main(): parser = optparse.OptionParser('%prog') parser.add_option('-b', type='int', dest='nbits', default=10) parser.add_option('-j', type='int', dest='device', default=None) parser.add_option('-n', type='int', dest='nblocks', default=64) parser.add_option('--detector', type='string', dest='detector', default='microlbne') parser.add_option('--nevents', type='int', dest='nevents', default=100) parser.add_option('--particle', type='string', dest='particle', default='e-') parser.add_option('--energy', type='float', dest='energy', default=100.0) parser.add_option('--pos', type='string', dest='pos', default='(0,0,0)') parser.add_option('--dir', type='string', dest='dir', default='(1,0,0)') options, args = parser.parse_args() if len(args) != 1: print 'Must specify output filename!' sys.exit(1) else: output_filename = args[0] if options.nevents <= 0: print '--nevents must be greater than 0!' sys.exit(1) position = np.array(eval(options.pos), dtype=float) direction = np.array(eval(options.dir), dtype=float) detector = detectors.find(options.detector) print >>sys.stderr, 'Creating detector...' detector.build(bits=options.nbits) print >>sys.stderr, 'Creating generator...' detector_material = optics.water generator_thread = GeneratorThread(particle=options.particle, energy=options.energy, position=position, direction=direction, nevents=options.nevents, material=detector_material) print >>sys.stderr, 'WARNING: ASSUMING DETECTOR IS WATER!!' # Do this now so we can get ahead of the photon propagation print >>sys.stderr, 'Starting GEANT4 generator...' generator_thread.start() print >>sys.stderr, 'Initializing GPU...' gpu_worker = gpu.GPU(options.device) print >>sys.stderr, 'Loading detector onto GPU...' gpu_worker.load_geometry(detector) print >>sys.stderr, 'Initializing random numbers generators...' gpu_worker.setup_propagate() gpu_worker.setup_daq(max(detector.pmtids)) # Create output file f = ROOT.TFile(output_filename, 'RECREATE') ev, T = root.make_tree('T') print >>sys.stderr, 'Starting simulation...' start_sim = time.time() nphotons = 0 for i in xrange(options.nevents): photons = generator_thread.queue.get() assert len(photons['pos']) > 0, 'GEANT4 generated event with no photons!' nphotons += len(photons['pos']) gpu_worker.load_photons(**photons) gpu_worker.propagate() gpu_worker.run_daq() hit_times = gpu_worker.get_hits() root.fill_event(T, ev, i-1, position, len(hit_times), hit_times) if i % 10 == 0: print >>sys.stderr, "\rEvent:", i, end_sim = time.time() print >>sys.stderr, "\rEvent:", options.nevents - 1 T.Write() f.Close() print >>sys.stderr, 'Done. %1.1f events/sec, %1.0f photons/sec.' % (options.nevents/(end_sim - start_sim), nphotons/(end_sim - start_sim)) gpu_worker.shutdown() if __name__ == '__main__': main()