summaryrefslogtreecommitdiff
path: root/sim.py
diff options
context:
space:
mode:
Diffstat (limited to 'sim.py')
-rwxr-xr-xsim.py283
1 files changed, 141 insertions, 142 deletions
diff --git a/sim.py b/sim.py
index 3044f3e..c0df524 100755
--- a/sim.py
+++ b/sim.py
@@ -3,148 +3,147 @@ import sys
import time
import os
import numpy as np
-
-import detectors
-import optics
-import generator
-from generator import constant
import itertools
import threading
-import gpu
-from fileio import root
-from chroma.itertoolset import repeating_iterator
-from tools import profile_if_possible, enable_debug_on_crash
+
+from chroma import detectors
+from chroma import optics
+from chroma import generator
+from chroma import gpu
+from chroma.fileio import root
+from chroma import tools
+from chroma import event
+from chroma.itertoolset import peek, repeat_copy, repeating_iterator
def pick_seed():
- '''Returns a seed for a random number generator selected using
- a mixture of the current time and the current process ID.'''
+ """Returns a seed for a random number generator selected using
+ a mixture of the current time and the current process ID."""
return int(time.time()) ^ (os.getpid() << 16)
class Simulation(object):
- def __init__(self, detector, detector_material,
- seed=None, cuda_device=None, geant4_processes=4, bvh_bits=11,
- use_cache=True):
+ def __init__(self, detector, seed=None, cuda_device=None, geant4_processes=4, bvh_bits=11, use_cache=True, nthreads_per_block=64, max_blocks=1024):
self.detector = detector
+ self.nthreads_per_block = nthreads_per_block
+ self.max_blocks = max_blocks
+
if seed is None:
self.seed = pick_seed()
else:
self.seed = seed
- print >>sys.stderr, 'RNG seed:', self.seed
+
+ print 'RNG seed: %i' % self.seed
# We have three generators to seed: numpy.random, GEANT4, and CURAND.
- # The latter two are done below
+ # The latter two are done below.
np.random.seed(self.seed)
- self.detector_material = detector_material
if geant4_processes > 0:
- self.photon_generator = generator.photon.G4ParallelGenerator(geant4_processes,
- detector_material,
- base_seed=self.seed)
+ self.photon_generator = generator.photon.G4ParallelGenerator(geant4_processes, detector.detector_material, base_seed=self.seed)
else:
self.photon_generator = None
- print >>sys.stderr, 'Creating BVH with %d bits...' % (bvh_bits)
- detector.build(bits=bvh_bits, use_cache=use_cache)
+ if not hasattr(detector, 'mesh'):
+ # need to build geometry
+ print 'Creating BVH with %i bits...' % bvh_bits
+ detector.build(bits=bvh_bits, use_cache=use_cache)
- print >>sys.stderr, 'Initializing GPU...'
- self.gpu_worker = gpu.GPU(cuda_device)
+ self.gpu = gpu.GPU(cuda_device)
+
+ # geometry is loaded onto gpu by default
+ self.gpu_geometry = gpu.GPUGeometry(self.gpu, detector)
- print >>sys.stderr, 'Loading detector onto GPU...'
- self.gpu_worker.load_geometry(detector)
+ self.gpu_daq = gpu.GPUDaq(self.gpu_geometry, max(self.detector.pmtids))
+ self.gpu_pdf = gpu.GPUPDF()
+
+ print 'Initializing random numbers generators...'
+ self.rng_states = gpu.get_rng_states(self.nthreads_per_block*self.max_blocks, seed=self.seed)
- print >>sys.stderr, 'Initializing random numbers generators...'
- self.gpu_worker.setup_propagate(seed=self.seed)
- self.gpu_worker.setup_daq(max(self.detector.pmtids))
self.pdf_config = None
- def simulate(self, nevents, vertex_generator, keep_photon_start=False, keep_photon_stop=False,
- run_daq=True, nreps=1):
- photon_gen = repeating_iterator(self.photon_generator.generate_events(nevents, vertex_generator),
- nreps)
- return self.simulate_photons(nevents*nreps,
- photon_gen,
- keep_photon_start=keep_photon_start, keep_photon_stop=keep_photon_stop,
- run_daq=run_daq)
-
- def simulate_photons(self, nevents, photon_generator, keep_photon_start=False, keep_photon_stop=False,
- run_daq=True):
- for ev in itertools.islice(photon_generator, nevents):
- self.gpu_worker.load_photons(ev.photon_start)
- self.gpu_worker.propagate()
- self.gpu_worker.run_daq()
-
- ev.nphoton = len(ev.photon_start.positions)
-
- if not keep_photon_start:
- ev.photon_start = None
-
- if keep_photon_stop:
- ev.photon_stop = self.gpu_worker.get_photons()
+ def simulate(self, iterable, keep_photons_beg=False, keep_photons_end=False, run_daq=True, max_steps=10):
+ first_element, iterable = peek(iterable)
+
+ if isinstance(first_element, event.Event):
+ iterable = self.photon_generator.generate_events(iterable)
+ elif isinstance(first_element, event.Photons):
+ iterable = (event.Event(photons_beg=x) for x in iterable)
+
+ for ev in iterable:
+ gpu_photons = gpu.GPUPhotons(ev.photons_beg)
+
+ gpu.propagate(self.gpu, gpu_photons, self.rng_states, nthreads_per_block=self.nthreads_per_block, max_blocks=self.max_blocks, max_steps=max_steps)
+
+ ev.nphotons = len(ev.photons_beg.pos)
+
+ if not keep_photons_beg:
+ ev.photons_beg = None
+
+ if keep_photons_end:
+ ev.photons_end = gpu_photons.get()
if run_daq:
- ev.channels = self.gpu_worker.get_hits()
+ gpu_channels = self.gpu_daq.acquire(gpu_photons, self.rng_states, nthreads_per_block=self.nthreads_per_block, max_blocks=self.max_blocks)
+ ev.channels = gpu_channels.get()
yield ev
- def propagate_photons(self, photons, max_steps=10):
- self.gpu_worker.load_photons(photons)
- self.gpu_worker.propagate(max_steps=max_steps)
- return self.gpu_worker.get_photons()
-
- def create_pdf(self, nevents, vertex_generator, tbins, trange,
- qbins, qrange, nreps=1):
- photon_gen = repeating_iterator(self.photon_generator.generate_events(nevents, vertex_generator),
- nreps)
- return self.create_pdf_from_photons(nevents*nreps, photon_gen,
- tbins, trange, qbins, qrange)
-
- def create_pdf_from_photons(self, nevents, photon_generator,
- tbins, trange, qbins, qrange):
- '''Returns tuple: 1D array of channel hit counts, 3D array of (channel, time, charge) pdfs'''
+ def create_pdf(self, iterable, tbins, trange, qbins, qrange, nreps=1):
+ """Returns tuple: 1D array of channel hit counts, 3D array of
+ (channel, time, charge) pdfs."""
+ first_element, iterable = peek(iterable)
+
+ if isinstance(first_element, event.Event):
+ iterable = self.photon_generator.generate_events(iterable)
+
pdf_config = (tbins, trange, qbins, qrange)
if pdf_config != self.pdf_config:
self.pdf_config = pdf_config
- self.gpu_worker.setup_pdf(max(self.detector.pmtids), tbins, trange,
+ self.gpu_pdf.setup_pdf(max(self.detector.pmtids), tbins, trange,
qbins, qrange)
else:
- self.gpu_worker.clear_pdf()
+ self.gpu_pdf.clear_pdf()
- for ev in itertools.islice(photon_generator, nevents):
- self.gpu_worker.load_photons(ev.photon_start)
- self.gpu_worker.propagate()
- self.gpu_worker.run_daq()
- self.gpu_worker.add_hits_to_pdf()
-
- return self.gpu_worker.get_pdfs()
-
-
- def eval_pdf(self, event_channels, nevents, vertex_generator,
- min_twidth, trange, min_qwidth, qrange,
- min_bin_content=20, nreps=1, time_only=True):
- photon_gen = repeating_iterator(self.photon_generator.generate_events(nevents, vertex_generator),
- nreps)
- return self.eval_pdf_from_photons(event_channels, nevents*nreps, photon_gen,
- min_twidth, trange, min_qwidth, qrange,
- min_bin_content=min_bin_content, time_only=time_only)
-
- def eval_pdf_from_photons(self, event_channels, nevents, photon_generator,
- min_twidth, trange, min_qwidth, qrange,
- min_bin_content=20, time_only=True):
- '''Returns tuple: 1D array of channel hit counts, 1D array of PDF probability densities'''
- self.gpu_worker.setup_pdf_eval(event_channels.hit, event_channels.t, event_channels.q,
- min_twidth, trange, min_qwidth, qrange,
- min_bin_content=min_bin_content, time_only=True)
-
- for ev in itertools.islice(photon_generator, nevents):
- self.gpu_worker.load_photons(ev.photon_start)
- self.gpu_worker.propagate()
- self.gpu_worker.run_daq()
- self.gpu_worker.accumulate_pdf_eval()
+ if nreps > 1:
+ iterable = repeating_iterator(iterable)
+
+ for ev in iterable:
+ gpu_photons = gpu.GPUPhotons(ev.photons_beg)
+ gpu.propagate(self.gpu, gpu_photons, self.rng_states, nthreads_per_block=self.nthreads_per_block, max_blocks=self.max_blocks)
+ gpu_channels = self.gpu_daq.acquire(gpu_photons, self.rng_states, nthreads_per_block=self.nthreads_per_block, max_blocks=self.max_blocks)
+ self.gpu_pdf.add_hits_to_pdf(gpu_channels)
- return self.gpu_worker.get_pdf_eval()
+ return self.gpu_pdf.get_pdfs()
+
+ def eval_pdf(self, event_channels, iterable, min_twidth, trange, min_qwidth, qrange, min_bin_content=20, nreps=1, time_only=True):
+ """Returns tuple: 1D array of channel hit counts, 1D array of PDF
+ probability densities."""
+ self.gpu_pdf.setup_pdf_eval(event_channels.hit,
+ event_channels.t,
+ event_channels.q,
+ min_twidth,
+ trange,
+ min_qwidth,
+ qrange,
+ min_bin_content=min_bin_content,
+ time_only=True)
+
+ first_element, iterable = peek(iterable)
+
+ if isinstance(first_element, event.Event):
+ iterable = self.photon_generator.generate_events(iterable)
+
+ if nreps > 1:
+ iterable = repeating_iterator(iterable)
+
+ for ev in iterable:
+ gpu_photons = gpu.GPUPhotons(ev.photons_beg)
+ gpu.propagate(self.gpu, gpu_photons, self.rng_states, nthreads_per_block=self.nthreads_per_block, max_blocks=self.max_blocks)
+ gpu_channels = self.gpu_daq.acquire(gpu_photons, self.rng_states, nthreads_per_block=self.nthreads_per_block, max_blocks=self.max_blocks)
+ self.gpu_pdf.accumulate_pdf_eval(gpu_channels)
+ return self.gpu_pdf.get_pdf_eval()
-@profile_if_possible
+@tools.profile_if_possible
def main():
import optparse
@@ -155,17 +154,22 @@ def main():
help='Set random number generator seed')
parser.add_option('-g', type='int', dest='ngenerators', default=4,
help='Number of GEANT4 generator processes')
- parser.add_option('--detector', type='string', dest='detector', default='microlbne')
+ 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)')
- parser.add_option('--save-photon-start', action='store_true',
- dest='save_photon_start', default=False,
+ parser.add_option('--particle', type='string', dest='particle',
+ help='particle name', default='e-')
+ parser.add_option('--ke', type='float', dest='ke',
+ help='particle kinetic energy in MeV', default=100.0)
+ parser.add_option('--pos', type='string', dest='pos',
+ help='particle vertex origin.', default='(0,0,0)')
+ parser.add_option('--dir', type='string', dest='dir',
+ help='particle vertex direction.', default='(1,0,0)')
+ parser.add_option('--save-photon-beg', action='store_true',
+ dest='save_photons_beg', default=False,
help='Save initial photon vertices to disk')
- parser.add_option('--save-photon-stop', action='store_true',
- dest='save_photon_stop', default=False,
+ parser.add_option('--save-photon-end', action='store_true',
+ dest='save_photons_end', default=False,
help='Save final photon vertices to disk')
options, args = parser.parse_args()
@@ -178,57 +182,52 @@ def main():
if options.nevents <= 0:
sys.exit('--nevents must be greater than 0!')
- position = np.array(eval(options.pos), dtype=float)
- direction = np.array(eval(options.dir), dtype=float)
- print >>sys.stderr, 'Loading detector %s...' % options.detector
+ pos = np.array(eval(options.pos), dtype=float)
+ dir = np.array(eval(options.dir), dtype=float)
+
+ print 'Loading detector %s...' % options.detector
+ sys.stdout.flush()
detector = detectors.find(options.detector)
- print >>sys.stderr, 'Creating generator...'
+ print 'Creating particle vertex generator...'
+ sys.stdout.flush()
if options.particle == 'pi0':
- vertex_generator = generator.vertex.pi0_gun(pi0_position=constant(position),
- pi0_direction=constant(direction),
- pi0_total_energy=constant(options.energy))
+ ev_vertex_iter = itertools.islice(generator.vertex.pi0_gun(itertools.repeat(pos), itertools.repeat(dir), itertools.repeat(options.ke)), options.nevents)
else:
- vertex_generator = generator.vertex.particle_gun(particle_name=constant(options.particle),
- position=constant(position),
- direction=constant(direction),
- total_energy=constant(options.energy))
+ vertex = event.Vertex(options.particle, pos, dir, None, options.ke)
+ ev_vertex_iter = (event.Event(i, vertex, [vertex]) for i, vertex in zip(range(options.nevents), repeat_copy(vertex)))
# Initializing simulation
- print >>sys.stderr, 'WARNING: ASSUMING DETECTOR IS WCSIM WATER!!'
- simulation = Simulation(detector=detector, detector_material=optics.water_wcsim,
- seed=options.seed, cuda_device=options.device,
- geant4_processes=options.ngenerators, bvh_bits=options.nbits)
+ simulation = Simulation(detector=detector, seed=options.seed, cuda_device=options.device, geant4_processes=options.ngenerators, bvh_bits=options.nbits)
# Create output file
writer = root.RootWriter(output_filename)
# Preheat generator
- event_iterator = simulation.simulate(options.nevents, vertex_generator,
- keep_photon_start=options.save_photon_start,
- keep_photon_stop=options.save_photon_stop)
+ ev_iter = simulation.simulate(ev_vertex_iter, keep_photons_beg=options.save_photons_beg, keep_photons_end=options.save_photons_end)
+ print 'Starting simulation...'
- print >>sys.stderr, 'Starting simulation...'
- start_sim = time.time()
nphotons = 0
+ t0 = time.time()
- for i, ev in enumerate(event_iterator):
- assert ev.nphoton > 0, 'GEANT4 generated event with no photons!'
- nphotons += ev.nphoton
+ for i, ev in enumerate(ev_iter):
+ print "\rEvent: %i" % (i+1),
+ sys.stdout.flush()
- writer.write_event(ev)
+ assert ev.nphotons > 0, 'Geant4 generated event with no photons!'
+ nphotons += ev.nphotons
- if i % 10 == 0:
- print >>sys.stderr, "\rEvent:", i,
+ writer.write_event(ev)
+ print
- end_sim = time.time()
- print >>sys.stderr, "\rEvent:", options.nevents - 1
+ elapsed = time.time() - t0
writer.close()
- print >>sys.stderr, 'Done. %1.1f events/sec, %1.0f photons/sec.' % (options.nevents/(end_sim - start_sim), nphotons/(end_sim - start_sim))
+ print '%f elapsed, %1.1f events/sec, %1.0f photons/sec.' % \
+ (elapsed, options.nevents/elapsed, nphotons/elapsed)
if __name__ == '__main__':
- enable_debug_on_crash()
+ tools.enable_debug_on_crash()
main()