def testAbort(self): '''Photons that hit a triangle at normal incidence should not abort. Photons that hit a triangle at exactly normal incidence can sometimes produce a dot product that is outside the range allowed by acos(). Trigger these with axis aligned photons in a box. ''' # Setup geometry cube = Geometry(vacuum) cube.add_solid(Solid(box(100, 100, 100), vacuum, vacuum)) geo = create_geometry_from_obj(cube, update_bvh_cache=False) # Initialize simulation (without geant4) sim = Simulation(geo, geant4_processes=0) # Create initial photons nphotons = 5 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([0, 0, 1], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) # First make one step to check for strangeness photons_end = sim.simulate([photons], keep_photons_end=True, max_steps=1).next().photons_end print "FIRST STEP" print photons_end.pos[0:10] self.assertFalse(np.isnan(photons_end.pos).any()) self.assertFalse(np.isnan(photons_end.dir).any()) self.assertFalse(np.isnan(photons_end.pol).any()) self.assertFalse(np.isnan(photons_end.t).any()) self.assertFalse(np.isnan(photons_end.wavelengths).any()) # Now let it run the usual ten steps photons_end = sim.simulate([photons], keep_photons_end=True, max_steps=10).next().photons_end aborted = (photons_end.flags & (1 << 31)) > 0 print 'aborted photon fracttion: %1.1f' % ( float(count_nonzero(aborted)) / nphotons) self.assertFalse(aborted.any()) print "LAST STEPS" print photons_end.pos[0:10]
def testAbort(self): '''Photons that hit a triangle at normal incidence should not abort. Photons that hit a triangle at exactly normal incidence can sometimes produce a dot product that is outside the range allowed by acos(). Trigger these with axis aligned photons in a box. ''' # Setup geometry cube = Geometry(vacuum) cube.add_solid(Solid(box(100,100,100), vacuum, vacuum)) geo = create_geometry_from_obj(cube, update_bvh_cache=False) sim = Simulation(geo, geant4_processes=0) # Create initial photons nphotons = 10000 pos = np.tile([0,0,0], (nphotons,1)).astype(np.float32) dir = np.tile([0,0,1], (nphotons,1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2*np.pi, nphotons).astype(np.float32) pol[:,0] = np.cos(phi) pol[:,1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) # First make one step to check for strangeness photons_end = sim.simulate([photons], keep_photons_end=True, max_steps=1).next().photons_end self.assertFalse(np.isnan(photons_end.pos).any()) self.assertFalse(np.isnan(photons_end.dir).any()) self.assertFalse(np.isnan(photons_end.pol).any()) self.assertFalse(np.isnan(photons_end.t).any()) self.assertFalse(np.isnan(photons_end.wavelengths).any()) # Now let it run the usual ten steps photons_end = sim.simulate([photons], keep_photons_end=True, max_steps=10).next().photons_end aborted = (photons_end.flags & (1 << 31)) > 0 print 'aborted photons: %1.1f' % \ (float(count_nonzero(aborted)) / nphotons) self.assertFalse(aborted.any())
class TestRayleigh(unittest.TestCase): def setUp(self): self.cube = Geometry(water) self.cube.add_solid(Solid(box(100, 100, 100), water, water)) self.geo = create_geometry_from_obj(self.cube, update_bvh_cache=False) self.sim = Simulation(self.geo, geant4_processes=0) nphotons = 100000 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([0, 0, 1], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) self.photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) def testAngularDistributionPolarized(self): # Fully polarized photons self.photons.pol[:] = [1.0, 0.0, 0.0] photons_end = self.sim.simulate([self.photons], keep_photons_end=True, max_steps=1).next().photons_end aborted = (photons_end.flags & (1 << 31)) > 0 self.assertFalse(aborted.any()) # Compute the dot product between initial and final dir rayleigh_scatters = (photons_end.flags & (1 << 4)) > 0 cos_scatter = (self.photons.dir[rayleigh_scatters] * photons_end.dir[rayleigh_scatters]).sum(axis=1) theta_scatter = np.arccos(cos_scatter) h = Histogram(bins=100, range=(0, np.pi)) h.fill(theta_scatter) h = rootify(h) # The functional form for polarized light should be # (1 + \cos^2 \theta)\sin \theta according to GEANT4 physics # reference manual. f = ROOT.TF1("pol_func", "[0]*(1+cos(x)**2)*sin(x)", 0, np.pi) h.Fit(f, 'NQ') self.assertGreater(f.GetProb(), 1e-3)
class TestRayleigh(unittest.TestCase): def setUp(self): self.cube = Geometry(water) self.cube.add_solid(Solid(box(100,100,100), water, water)) self.geo = create_geometry_from_obj(self.cube, update_bvh_cache=False) self.sim = Simulation(self.geo, geant4_processes=0) nphotons = 100000 pos = np.tile([0,0,0], (nphotons,1)).astype(np.float32) dir = np.tile([0,0,1], (nphotons,1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2*np.pi, nphotons).astype(np.float32) pol[:,0] = np.cos(phi) pol[:,1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) self.photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) def testAngularDistributionPolarized(self): # Fully polarized photons self.photons.pol[:] = [1.0, 0.0, 0.0] photons_end = self.sim.simulate([self.photons], keep_photons_end=True, max_steps=1).next().photons_end aborted = (photons_end.flags & (1 << 31)) > 0 self.assertFalse(aborted.any()) # Compute the dot product between initial and final dir rayleigh_scatters = (photons_end.flags & (1 << 4)) > 0 cos_scatter = (self.photons.dir[rayleigh_scatters] * photons_end.dir[rayleigh_scatters]).sum(axis=1) theta_scatter = np.arccos(cos_scatter) h = Histogram(bins=100, range=(0, np.pi)) h.fill(theta_scatter) h = rootify(h) # The functional form for polarized light should be # (1 + \cos^2 \theta)\sin \theta according to GEANT4 physics # reference manual. f = ROOT.TF1("pol_func", "[0]*(1+cos(x)**2)*sin(x)", 0, np.pi) h.Fit(f, 'NQ') self.assertGreater(f.GetProb(), 1e-3)
def _full_detector_simulation(config, kabamland, amount, simname, datadir=""): # simulates 1000*amount photons uniformly spread throughout a sphere whose radius is the inscribed radius of the icosahedron. # Note that viewing may crash if there are too many lenses. (try using configview) from chroma.sim import Simulation # Require CUDA, so only import when necessary config_name = config.config_name file_name_base = datadir + simname if USE_ROOT: from ShortIO.root_short import ShortRootWriter f = ShortRootWrite(file_name_base + '.root') # SHERLOCK: Have to set the seed because Sherlock compute machines blow up if we use chroma's algorithm!!!! # sim = Simulation(kabamland, geant4_processes=0, seed=65432) # For now, does not take advantage of multiple cores # TODO: use sim_setup()? sim = Simulation( kabamland, geant4_processes=0 ) # For now, does not take advantage of multiple cores # TODO: use sim_setup()? with h5py.File(file_name_base + '.h5', 'w') as h5_file: # Total photons will be LOOP_COUNT * EVENT_COUNT * amount LOOP_COUNT = 100 EVENT_COUNT = 10 # Setup to write the hdf5 file incrementally # Can't use deepdish as it seems to require a single write which takes up too much memory start_pos = h5_file.create_dataset('photons_start', shape=(LOOP_COUNT * EVENT_COUNT, amount, 3), dtype=np.float32, chunks=True) end_pos = h5_file.create_dataset('photons_stop', shape=(LOOP_COUNT * EVENT_COUNT, amount, 3), dtype=np.float32, chunks=True) photon_flags = h5_file.create_dataset('photon_flags', shape=( LOOP_COUNT * EVENT_COUNT, amount, ), dtype=np.uint32, chunks=True) # Store the UUID and name to enable matching of the configuration, calibration, and simulation files h5_file.attrs['config_name'] = config_name h5_file.attrs['config_UUID'] = str(config.uuid) process = psutil.Process(os.getpid()) logger.info('Memory size: %d MB' % (process.memory_info().rss // 1000000)) for j in range(LOOP_COUNT): logger.info('%d of %d event sets' % (j, LOOP_COUNT)) ev_index = 0 sim_events = [ kb.uniform_photons(config.detector_radius, amount) for i in range(EVENT_COUNT) ] for ev in sim.simulate(sim_events, keep_photons_beg=True, keep_photons_end=True, run_daq=False, max_steps=100): start_pos[(j * EVENT_COUNT) + ev_index] = ev.photons_beg.pos end_pos[(j * EVENT_COUNT) + ev_index] = ev.photons_end.pos photon_flags[(j * EVENT_COUNT) + ev_index] = ev.photons_end.flags ev_index += 1 if USE_ROOT: # In this case, write both hdf5 and ROOT simulation files f.write_event(ev) logger.info('Memory size: %d MB' % (process.memory_info().rss // 1000000)) if USE_ROOT: f.close()
#view(g) ys.exit() sim = Simulation(g) n=1 gun = vertex.particle_gun(['mu-']*n, vertex.constant((0,10000,10000)), vertex.constant([1,0,-1]), vertex.constant(1000), vertex.constant(0)) i = 0 for ev in sim.simulate(gun,keep_detected_photons=True, max_steps=100): i +=1 if i%10 == 0: print i photons = ev.photons_end #print 'pos', photons.pos.ravel() #print 'dir', photons.dir.ravel() #print 'pol', photons.pol.ravel() #print 'wavelength', photons.wavelengths[0] #print 'time', photons.t[0] #print 'last hit', photons.last_hit_triangles[0] #print 'flag', photons.flags[0] pmt_hits = 0 for t_id in photons.last_hit_triangles: if g.solid_id[int(t_id.get())] == 0: pmt_hits += 1
def main(n, wavelength, width, beamsize, regen=False): config_path = open('config/vars.txt', 'rb') test = config_path.readline() config_path.close() if not (abs(float(test) - width) < 0.1 / 25400): regen = True if os.path.exists('config/geometry.pickle') and regen == False: geometry_path = open('config/geometry.pickle', 'rb') world = cPickle.load(geometry_path) geometry_path.close() else: world = build(width) world.flatten() world.bvh = load_bvh(world) #Create bounding volume hierarchy sim = Simulation(world) def init_source(n, wavelength, width, beamsize): """Generates laser profile of n photons, with wavelength, emanating from position pos_offset with direction 'direction'.""" pos, direction = mfunctions.get_source(n, width, beamsize, wavelength / 25400000.0) #Note: Chroma only natively handles integer wavelengths, so we convert to inches here instead of earlier in the code. source_center = mfunctions.get_center('161') + np.array( (0, -0.1, 0)) #Position source just in front of slits pos = pos + np.tile(source_center, (n, 1)) pol = np.cross(direction, (0, 0, 1)) #Polarisation wavelengths = np.repeat(wavelength, n) return Photons(pos, direction, pol, wavelengths) start = [] end = [] print 'Simulating photons...' for ev in sim.simulate([init_source(n, wavelength, width, beamsize)], keep_photons_beg=True, keep_photons_end=True, run_daq=False, max_steps=100): #print ev.photons_end.flags start.append(ev.photons_beg.pos) end.append(ev.photons_end.pos) print 'Saving data to file...' photon_id = list(range(n)) flags = ev.photons_end.flags wavs = ev.photons_end.wavelengths ##### Saving data to file ##### current = dt.datetime.now() filename = 'results/' + current.strftime( '%Y-%m-%d_%H:%M') + '_%d:%d:%.2f:%.2f.dat' % (n, wavelength, width * 25400, beamsize * 25400) out_file = open(filename, 'w') out_file.write('\t'.join([ 'ID', 'xi', 'yi', 'zi', 'xf', 'yf', 'zf', 'wavelength (nm)', 'flag\n' ])) for i in range(n): output = [photon_id[i]] + [item for item in start[0][i]] + [ item for item in end[0][i] ] + [int(wavs[i]), flags[i]] out_file.write('\t'.join([str(item) for item in output]) + '\n') out_file.close() print 'Generating seed file...' seed = np.random.uniform( size=n) #This is the seed file for the analysis script np.savetxt('config/seed.dat', seed, delimiter=',') print 'Done.'
def testBulkReemission(self): '''Test bulk reemission Start a bunch of monoenergetic photons at the center of a wavelength- shifting sphere, forcing reemission, and check that the final wavelength distribution matches the wls spectrum. ''' import scipy.stats nphotons = 1e5 # set up detector -- a sphere of 'scintillator' surrounded by a # detecting sphere scint = Material('scint') scint.set('refractive_index', 1) scint.set('absorption_length', 1.0) scint.set('scattering_length', 1e7) scint.set('reemission_prob', 1) x = np.arange(0,1000,10) norm = scipy.stats.norm(scale=50, loc=600) pdf = 10 * norm.pdf(x) cdf = norm.cdf(x) scint.reemission_cdf = np.array(zip(x, cdf)) detector = Surface('detector') detector.set('detect', 1) world = Geometry(vacuum) world.add_solid(Solid(sphere(1000), vacuum, vacuum, surface=detector)) world.add_solid(Solid(sphere(500), scint, vacuum)) w = create_geometry_from_obj(world, update_bvh_cache=False) sim = Simulation(w, geant4_processes=0) # initial photons -- isotropic 250 nm at the origin pos = np.tile([0,0,0], (nphotons,1)).astype(np.float32) dir = np.random.rand(nphotons, 3).astype(np.float32) * 2 - 1 dir /= np.sqrt(dir[:,0]**2 + dir[:,1]**2 + dir[:,2]**2)[:,np.newaxis] pol = np.zeros_like(pos) t = np.zeros(nphotons, dtype=np.float32) wavelengths = np.ones(nphotons).astype(np.float32) * 250 photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) # run simulation and extract final wavelengths event = sim.simulate([photons], keep_photons_end=True).next() mask = (event.photons_end.flags & SURFACE_DETECT) > 0 final_wavelengths = event.photons_end.wavelengths[mask] # compare wavelength distribution to scintillator's reemission pdf hist, edges = np.histogram(final_wavelengths, bins=x) print 'detected', hist.sum(), 'of', nphotons, 'photons' hist_norm = 1.0 * hist / (1.0 * hist.sum() / 1000) pdf /= (1.0 * pdf.sum() / 1000) chi2 = scipy.stats.chisquare(hist_norm, pdf[:-1])[1] print 'chi2 =', chi2 # show histogram comparison #plt.figure(1) #width = edges[1] - edges[0] #plt.bar(left=edges, height=pdf, width=width, color='red') #plt.bar(left=edges[:-1], height=hist_norm, width=width) #plt.show() self.assertTrue(chi2 > 0.75)
class TestUbooneDetector(unittest.TestCase): def setUp(self): daefile = "dae/lar1nd_lightguides_nowires_chroma.dae" # without wires #daefile = "dae/lar1nd_chroma.dae" # with wires self.geo = ubooneDet(daefile, detector_volumes=["vollightguidedetector"], wireplane_volumes=[ ('volTPCPlaneVert_PV0x7fdcd2728c70', add_wireplane_surface) ], acrylic_detect=True, acrylic_wls=False, read_bvh_cache=True, cache_dir="./lar1nd_cache", dump_node_info=False) self.sim = Simulation(self.geo, geant4_processes=0, nthreads_per_block=192, max_blocks=1024, user_daq=GPUDaqUBooNE) @unittest.skip('skipping testDet') def testDet(self): # Run only one photon at a time nphotons = 100000 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([0, 0, 1], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(128.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_charges = [] for ev in self.sim.simulate( (photons for i in xrange(1)), keep_photons_end=True, keep_photons_beg=False, ): ev.photons_end.dump_history() lht = ev.photons_end[0].last_hit_triangles print "LHT: ", lht def testPhotonBomb(self): # Run only one photon at a time nphotons_test = 256 * 1000 #nphotons = 7200000 if has_root: root_file = root_open("output_test_lar1nd_scanx_high_stats.root", "recreate") root_tree = Tree("PhotonData", model=PhotonData) root_tree.reset() root_channels = Tree("OpDet", model=OpDet) root_opmap = Tree("OpMap", model=OpMap) channelmap = self.sim.gpu_geometry.solid_id_to_channel_index_gpu.get( ) channels = np.argwhere(channelmap > -1) nchannels = NCHANNELS channeldict = dict( zip(range(0, nchannels), channels.ravel().tolist())) for ich in range(0, nchannels): root_opmap.opid = ich solid = self.sim.detector.solids[channeldict[ich]] root_opmap.x = np.sum(solid.mesh.vertices[:, 0]) / len( solid.mesh.vertices) root_opmap.y = np.sum(solid.mesh.vertices[:, 1]) / len( solid.mesh.vertices) root_opmap.z = np.sum(solid.mesh.vertices[:, 2]) / len( solid.mesh.vertices) root_opmap.fill() root_opmap.write() for eventid in xrange(0, 102): print "Event: ", eventid if eventid < 101: nphotons = nphotons_test * 20 z = -200 + 4 * eventid else: # reference nphotons = nphotons_test z = 0 t_photon_start = time.time() dphi = np.random.uniform(0, 2.0 * np.pi, nphotons) dcos = np.random.uniform(-1.0, 1.0, nphotons) dir = np.array(zip( np.sqrt(1 - dcos[:] * dcos[:]) * np.cos(dphi[:]), np.sqrt(1 - dcos[:] * dcos[:]) * np.sin(dphi[:]), dcos[:]), dtype=np.float32) pos = np.tile([-1000 + z, 0, 0], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros( nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(128.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) t_end_start = time.time() print "define photon time: ", t_end_start - t_photon_start, "sec" for ev in self.sim.simulate( (photons for i in xrange(1)), keep_photons_end=True, keep_photons_beg=False, ): #ev.photons_end.dump_history() #print ev.channels.t if (eventid % 10 == 0): print "Event: ", eventid #print "nchannels: ",len(ev.channels.hit) #print nhits #print ev.channels.q #print ev.channels.t if False: # Fill Tree #print "save info for ",len(ev.photons_end) for photon in ev.photons_end: root_tree.end_x = photon.pos[0] root_tree.end_y = photon.pos[1] root_tree.end_z = photon.pos[2] root_tree.reflect_diffuse = int(event.REFLECT_DIFFUSE & photon.flags) root_tree.reflect_specular = int(event.REFLECT_SPECULAR & photon.flags) root_tree.bulk_scatter = int(event.RAYLEIGH_SCATTER & photon.flags) root_tree.bulk_absorb = int(event.BULK_ABSORB & photon.flags) root_tree.surface_detect = int(event.SURFACE_DETECT & photon.flags) root_tree.surface_absorb = int(event.SURFACE_ABSORB & photon.flags) root_tree.surface_reemit = int(event.SURFACE_REEMIT & photon.flags) root_tree.fill() if True: root_channels.eventid = eventid t_root_start = time.time() for ichannel in xrange(0, NCHANNELS): root_channels.id = ichannel root_channels.NTDC = GPUDaqUBooNE.NTDC root_channels.NS_PER_TDC = GPUDaqUBooNE.NS_PER_TDC channeladc = ev.channels.q[GPUDaqUBooNE.NTDC * ichannel:(ichannel + 1) * GPUDaqUBooNE.NTDC] root_channels.adc[:] = array.array( 'f', channeladc[:].ravel().tolist())[:] root_channels.q = np.sum(channeladc) #if root_channels.q>0: # print channeladc[ np.where( channeladc>0.0 ) ] root_channels.t = ev.channels.t[ichannel] root_channels.fill() t_root_end = time.time() print "ROOT Fill time: ", t_root_end - t_root_start, " sec" if has_root: root_tree.write() root_channels.write()
if __name__ == '__main__': from chroma.demo import detector as build_detector from chroma.sim import Simulation from chroma.generator import constant_particle_gun from chroma import tools import time tools.enable_debug_on_crash() detector = build_detector() sim = Simulation(detector, seed=0) event = sim.simulate( islice(constant_particle_gun('e-', (0, 0, 0), (1, 0, 0), 100.0), 1)).next() print 'nhit = %i' % count_nonzero(event.channels.hit) likelihood = Likelihood(sim, event) x = np.linspace(-10.0, 10.0, 100) l = [] for pos in izip(x, repeat(0), repeat(0)): t0 = time.time() ev_vertex_iter = constant_particle_gun('e-', pos, (1, 0, 0), 100.0) l.append(likelihood.eval(ev_vertex_iter, 1000)) elapsed = time.time() - t0
class TestDetector(unittest.TestCase): def setUp(self): # Setup geometry cube = Detector(vacuum) cube.add_pmt( Solid(box(10.0, 10.0, 10.0), vacuum, vacuum, surface=r7081hqe_photocathode)) cube.set_time_dist_gaussian(1.2, -6.0, 6.0) cube.set_charge_dist_gaussian(1.0, 0.1, 0.5, 1.5) geo = create_geometry_from_obj(cube, update_bvh_cache=True, read_bvh_cache=False) print "Number of channels in detector: ", geo.num_channels() self.geo = geo self.sim = Simulation(self.geo, geant4_processes=0, nthreads_per_block=1, max_blocks=1) self.rfile = rt.TFile("output_test_detector.root", "recreate") self.htime = rt.TH1D("htime", "Time;ns", 120, 80, 120) self.hcharge = rt.TH1D("hcharge", "Charge;pe", 100, 0.5, 1.5) @unittest.skip('Skipping time test') def testTime(self): '''Test PMT time distribution''' # Run only one photon at a time nphotons = 1 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([0, 0, 1], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_times = [] for ev in self.sim.simulate((photons for i in xrange(1)), keep_photons_end=True, keep_photons_beg=False): for n, hit in enumerate(ev.channels.hit): if hit: hit_times.append(ev.channels.t[n]) print "Hits from photon %d: " % (n), ev.photons_end[0].pos[ n], " with t=", ev.channels.t[n], " q=", ev.channels.q[ n], " Hit=", ev.channels.hit[n] self.htime.Fill(ev.channels.t[n]) self.hcharge.Fill(ev.channels.q[n]) hit_times = np.array(hit_times) self.assertAlmostEqual(hit_times.std(), 1.2, delta=1e-1) #@unittest.skip('Ray data file needs to be updated') def testCharge(self): '''Test PMT charge distribution''' # Run only one photon at a time phi = 1.0 theta = 1.0 nphotons = 100 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([ np.sin(theta * np.pi / 180.0) * np.cos(phi * np.pi / 180.0), np.sin(theta * np.pi / 180.0) * np.sin(phi * np.pi / 180.0), np.cos(theta * np.pi / 180.0) ], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) + 100.0 wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_charges = [] for ev in self.sim.simulate((photons for i in xrange(1)), keep_photons_end=True, keep_photons_beg=False): if ev.channels.hit[0]: hit_charges.append(ev.channels.q[0]) self.hcharge.Fill(ev.channels.q[0]) self.htime.Fill(ev.channels.t[0]) #print "Hits: with q=",ev.channels.q[0],". Hit=",ev.channels.hit[0] ev.photons_end.dump_history() hit_charges = np.array(hit_charges) self.assertAlmostEqual(hit_charges.mean() / float(hit_charges.size), 1.0, delta=1e-1) self.assertAlmostEqual(hit_charges.std() / float(hist_chargs.size), 0.1, delta=1e-1) def tearDown(self): self.rfile.Write()
# Don't forget to return a negative log likelihood return ufloat((-avg_like, rms_like/sqrt(mom0))) if __name__ == '__main__': from chroma.demo import detector as build_detector from chroma.sim import Simulation from chroma.generator import constant_particle_gun from chroma import tools import time tools.enable_debug_on_crash() detector = build_detector() sim = Simulation(detector, seed=0) event = sim.simulate(islice(constant_particle_gun('e-',(0,0,0),(1,0,0),100.0), 1)).next() print 'nhit = %i' % count_nonzero(event.channels.hit) likelihood = Likelihood(sim, event) x = np.linspace(-10.0, 10.0, 100) l = [] for pos in izip(x, repeat(0), repeat(0)): t0 = time.time() ev_vertex_iter = constant_particle_gun('e-',pos,(1,0,0),100.0) l.append(likelihood.eval(ev_vertex_iter, 1000)) elapsed = time.time() - t0 print '(%.1f, %.1f, %.1f), %s (%1.1f sec)' % \
display = PyQtDisplay( det ) except: pass print "[ Start Sim. ]" start = time.time() sim = Simulation(det, geant4_processes=0, nthreads_per_block=nthreads_per_block, max_blocks=1024) print "[ TIME ] push geometry data to GPU: ",time.time()-start,"secs" nphotons = 1000000 start = time.time() #photons = gen_photons( nphotons ) photons = gen_stepdata_photons( sim.context ).get() print "[ TIME ] generate photons ",time.time()-start,"secs" start = time.time() events = sim.simulate( photons, keep_photons_end=True, max_steps=2000) print "[ TIME ] propagate photons ",time.time()-start,"secs" for ev in events: nhits = ev.channels.hit[ np.arange(0,36)[:] ] print "Channels with Hits: " print nhits print "Photoelectrons in each channel: " print ev.channels.q detected_photons = ev.photons_end.flags[:] & chroma.event.SURFACE_DETECT # bit-wise AND. if detected bit set, then value >0, otherwise 0. print "Detected photons: ",np.count_nonzero( detected_photons )," frac: ",np.count_nonzero( detected_photons )/len(photons.pos) print "hit prep: ",len( ev.photons_end.last_hit_triangles ),len(det.solid_id_to_channel_index),len(det.solid_id) ev.photons_end.dump_history() channelhit = np.zeros( len(detected_photons), dtype=np.int ) channelhit[:] = det.solid_id_to_channel_index[ det.solid_id[ ev.photons_end.last_hit_triangles[:] ] ] #for n,f in enumerate(detected_photons):
def photon_bomb(n, wavelength, pos): pos = np.tile(pos, (n, 1)) dir = uniform_sphere(n) pol = np.cross(dir, uniform_sphere(n)) wavelengths = np.repeat(wavelength, n) return Photons(pos, dir, pol, wavelengths) # write it to a root file from chroma.io.root import RootWriter f = RootWriter('test.root') # sim.simulate() always returns an iterator even if we just pass # a single photon bomb for ev in sim.simulate([photon_bomb(1000, 400, (0, 0, 0))], keep_photons_beg=True, keep_photons_end=True, run_daq=False, max_steps=100): # write the python event to a root file f.write_event(ev) # simulate some electrons! gun = vertex.particle_gun(['e-'] * 10, vertex.constant((0, 0, 0)), vertex.isotropic(), vertex.flat(500, 1000)) for ev in sim.simulate(gun, keep_photons_beg=True, keep_photons_end=True, run_daq=False, max_steps=100): f.write_event(ev)
class TestDetector(unittest.TestCase): def setUp(self): # Setup geometry cube = Detector(vacuum) cube.add_pmt( Solid(box(10.0, 10, 10), vacuum, vacuum, surface=r7081hqe_photocathode)) cube.set_time_dist_gaussian(1.2, -6.0, 6.0) cube.set_charge_dist_gaussian(1.0, 0.1, 0.5, 1.5) geo = create_geometry_from_obj(cube, update_bvh_cache=False) self.geo = geo self.sim = Simulation(self.geo, geant4_processes=0) def testTime(self): '''Test PMT time distribution''' # Run only one photon at a time nphotons = 1 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([0, 0, 1], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_times = [] for ev in self.sim.simulate(photons for i in xrange(1000)): if ev.channels.hit[0]: hit_times.append(ev.channels.t[0]) hit_times = np.array(hit_times) self.assertAlmostEqual(hit_times.std(), 1.2, delta=1e-1) def testCharge(self): '''Test PMT charge distribution''' # Run only one photon at a time nphotons = 1 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([0, 0, 1], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_charges = [] for ev in self.sim.simulate(photons for i in xrange(1000)): if ev.channels.hit[0]: hit_charges.append(ev.channels.q[0]) hit_charges = np.array(hit_charges) self.assertAlmostEqual(hit_charges.mean(), 1.0, delta=1e-1) self.assertAlmostEqual(hit_charges.std(), 0.1, delta=1e-1)
from chroma.io.root import RootWriter f = RootWriter('muon.root') n = 0 m = 0 n_prime = 0.0 m_prime = 0.0 gun = vertex.particle_gun(['mu-'], vertex.constant((n,m, get_tube_height())), # vertex.constant((n_prime, m_prime, -1)), # vertex.constant(1000)) # for ev in sim.simulate(gun, keep_photons_beg=True,keep_photons_end=True, run_daq=False,max_steps=1000): f.write_event(ev) detected = (ev.photons_end.flags & (0x1 << 2)).astype(bool) print "photons, generated: ", len(ev.photons_beg.t), " ..detected: ", len(ev.photons_end.t[detected]) f.close() if(plot_last_event): fig1 = plt.figure(1) plt.plot(ev.photons_end.t[detected], ev.photons_end.pos[:,2][detected],'p') plt.xlabel('time [ns]') plt.ylabel('z [mm]') fig2 = plt.figure(2)
# photon bomb from center def photon_bomb(n,wavelength,pos): pos = np.tile(pos,(n,1)) dir = uniform_sphere(n) pol = np.cross(dir,uniform_sphere(n)) wavelengths = np.repeat(wavelength,n) return Photons(pos,dir,pol,wavelengths) # write it to a root file from chroma.io.root import RootWriter f = RootWriter('test.root') # sim.simulate() always returns an iterator even if we just pass # a single photon bomb for ev in sim.simulate([photon_bomb(1000,400,(0,0,0))], keep_photons_beg=True,keep_photons_end=True, run_daq=False,max_steps=100): # write the python event to a root file f.write_event(ev) # simulate some electrons! gun = vertex.particle_gun(['e-']*10, vertex.constant((0,0,0)), vertex.isotropic(), vertex.flat(500,1000)) for ev in sim.simulate(gun,keep_photons_beg=True,keep_photons_end=True, run_daq=False,max_steps=100): f.write_event(ev) detected = (ev.photons_end.flags & (0x1 << 2)).astype(bool)
class TestUbooneDetector(unittest.TestCase): def setUp(self): #self.geo = ubooneDet( "../gdml/microboone_nowires_chroma_simplified.dae", acrylic_detect=False, acrylic_wls=True ) self.geo = ubooneDet( "../gdml/microboone_nowires_chroma_simplified.dae", detector_volumes=["vol_PMT_AcrylicPlate"], acrylic_detect=True, acrylic_wls=False, read_bvh_cache=False, cache_dir="./uboone_bvh_nowires", bvh_method='grid') self.sim = Simulation(self.geo, geant4_processes=0) @unittest.skip('skipping testDet') def testDet(self): # Run only one photon at a time nphotons = 1000000 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([0, 0, 1], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(128.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_charges = [] for ev in self.sim.simulate( (photons for i in xrange(1)), keep_photons_end=True, keep_photons_beg=False, ): ev.photons_end.dump_history() lht = ev.photons_end[0].last_hit_triangles print "LHT: ", lht def testPhotonBomb(self): # Run only one photon at a time nphotons = 1000 #nphotons = 7200000 dphi = np.random.uniform(0, 2.0 * np.pi, nphotons) dcos = np.random.uniform(-1.0, 1.0, nphotons) dir = np.array(zip( np.sqrt(1 - dcos[:] * dcos[:]) * np.cos(dphi[:]), np.sqrt(1 - dcos[:] * dcos[:]) * np.sin(dphi[:]), dcos[:]), dtype=np.float32) pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(128.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_charges = [] if has_root: root_file = root_open("output_test_uboone.root", "recreate") root_tree = Tree("PhotonData", model=PhotonData) root_tree.reset() for ev in self.sim.simulate( (photons for i in xrange(1)), keep_photons_end=True, keep_photons_beg=False, ): ev.photons_end.dump_history() lht = ev.photons_end[0].last_hit_triangles nhits = ev.channels.hit[np.arange(0, 30)[:]] print "nchannels: ", len(ev.channels.hit) print nhits print ev.channels.q print ev.channels.t if has_root: # Fill Tree print "save info for ", len(ev.photons_end) for photon in ev.photons_end: root_tree.end_x = photon.pos[0] root_tree.end_y = photon.pos[1] root_tree.end_z = photon.pos[2] root_tree.reflect_diffuse = int(event.REFLECT_DIFFUSE & photon.flags) root_tree.reflect_specular = int(event.REFLECT_SPECULAR & photon.flags) root_tree.bulk_scatter = int(event.RAYLEIGH_SCATTER & photon.flags) root_tree.bulk_absorb = int(event.BULK_ABSORB & photon.flags) root_tree.surface_detect = int(event.SURFACE_DETECT & photon.flags) root_tree.surface_absorb = int(event.SURFACE_ABSORB & photon.flags) root_tree.surface_reemit = int(event.SURFACE_REEMIT & photon.flags) root_tree.fill() if has_root: root_tree.write()
class TestDetector(unittest.TestCase): def setUp(self): # Setup geometry cube = Detector(vacuum) cube.add_pmt( Solid(box(10.0, 10, 10), vacuum, vacuum, surface=r7081hqe_photocathode)) cube.set_time_dist_gaussian(1.2, -6.0, 6.0) cube.set_charge_dist_gaussian(1.0, 0.1, 0.5, 1.5) geo = create_geometry_from_obj(cube, update_bvh_cache=True) print "Number of channels in detector: ", geo.num_channels() self.geo = geo self.sim = Simulation(self.geo, geant4_processes=0) #@unittest.skip('Skip timing distribution test') def testTime(self): '''Test PMT time distribution''' # Run only one photon at a time nphotons = 1 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([0, 0, 1], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_times = [] for ev in self.sim.simulate((photons for i in xrange(500)), keep_photons_end=True, keep_photons_beg=True): #for ev in self.sim.simulate(photons for i in xrange(5)): if ev.channels.hit[0]: hit_times.append(ev.channels.t[0]) print "Hits: ", ev.photons_end.pos, " with t=", ev.channels.t[ 0], ". starting from ", ev.photons_beg.pos, " Hit=", ev.channels.hit[ 0] hit_times = np.array(hit_times) self.assertAlmostEqual(hit_times.std(), 1.2, delta=1e-1) #@unittest.skip('Ray data file needs to be updated') def testCharge(self): '''Test PMT charge distribution''' # Run only one photon at a time phi = 1.0 theta = 1.0 nphotons = 1 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([ np.sin(theta * np.pi / 180.0) * np.cos(phi * np.pi / 180.0), np.sin(theta * np.pi / 180.0) * np.sin(phi * np.pi / 180.0), np.cos(theta * np.pi / 180.0) ], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_charges = [] for ev in self.sim.simulate((photons for i in xrange(100)), keep_photons_end=True, keep_photons_beg=True): if ev.channels.hit[0]: hit_charges.append(ev.channels.q[0]) traveled = 0 for v in range(0, 3): traveled += ev.photons_end.pos[0][v] * ev.photons_end.pos[0][v] traveled = np.sqrt(traveled) print "Hits: ", ev.photons_end.pos, " with q=", ev.channels.q[ 0], ". starting from ", ev.photons_beg.pos, " Hit=", ev.channels.hit[ 0], " dist traveled=", traveled hit_charges = np.array(hit_charges) self.assertAlmostEqual(hit_charges.mean(), 1.0, delta=1e-1) self.assertAlmostEqual(hit_charges.std(), 0.1, delta=1e-1)
class TestUbooneDetector(unittest.TestCase): def setUp(self): # UBOONE daefile = "lbne35t4apa_v3_nowires_test.dae" self.geo = ubooneDet(daefile, detector_volumes=[ "volOpDetSensitive_Fiber", "volOpDetSensitive_Bar", "volOpDetSensitive_Plank" ], acrylic_detect=True, acrylic_wls=False, read_bvh_cache=True, cache_dir="./lbne35t_cache", dump_node_info=True) self.sim = Simulation(self.geo, geant4_processes=0) self.origin = self.geo.bvh.world_coords.world_origin @unittest.skip('skipping testDet') def testDet(self): # Run only one photon at a time nphotons = 1000000 pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) dir = np.tile([0, 0, 1], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol = np.cross((np.cos(phi), np.sin(phi), 0), dir) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) pol = np.cross(pol, dir) for n, p in enumerate(pol): norm = np.sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]) p /= norm #print pol t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(128.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_charges = [] for ev in self.sim.simulate( (photons for i in xrange(1)), keep_photons_end=True, keep_photons_beg=False, ): ev.photons_end.dump_history() lht = ev.photons_end[0].last_hit_triangles #@unittest.skip('skipping testDet') def testPhotonBomb(self): # Run only one photon at a time #nphotons = 7200000 #nphotons = 256*10000 nphotons = 256 * 1000 dphi = np.random.uniform(0, 2.0 * np.pi, nphotons) dcos = np.random.uniform(-1.0, 1.0, nphotons) dir = np.array(zip( np.sqrt(1 - dcos[:] * dcos[:]) * np.cos(dphi[:]), np.sqrt(1 - dcos[:] * dcos[:]) * np.sin(dphi[:]), dcos[:]), dtype=np.float32) pos = np.tile([-200.0, -400.0, -500.0], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) pol = np.cross(pol, dir) for n, p in enumerate(pol): norm = np.sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]) p /= norm t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(128.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_charges = [] if has_root: root_file = root_open("output_test_lbne35t_nowires.root", "recreate") root_tree = Tree("PhotonData", model=PhotonData) root_tree.reset() for ev in self.sim.simulate((photons for i in xrange(1)), keep_photons_end=True, keep_photons_beg=False): ev.photons_end.dump_history() # lht = ev.photons_end[0].last_hit_triangles # nhits = ev.channels.hit[ np.arange(0,30)[:] ] # # print "nchannels: ",len(ev.channels.hit) # print nhits # print ev.channels.q # print ev.channels.t if True: # Fill Tree #print "save info for ",len(ev.photons_end) for photon in ev.photons_end: root_tree.end_x = photon.pos[0] root_tree.end_y = photon.pos[1] root_tree.end_z = photon.pos[2] root_tree.reflect_diffuse = int(event.REFLECT_DIFFUSE & photon.flags) root_tree.reflect_specular = int(event.REFLECT_SPECULAR & photon.flags) root_tree.bulk_scatter = int(event.RAYLEIGH_SCATTER & photon.flags) root_tree.bulk_absorb = int(event.BULK_ABSORB & photon.flags) root_tree.surface_detect = int(event.SURFACE_DETECT & photon.flags) root_tree.surface_absorb = int(event.SURFACE_ABSORB & photon.flags) root_tree.surface_reemit = int(event.SURFACE_REEMIT & photon.flags) root_tree.fill() if has_root: root_tree.write() @unittest.skip('skipping testDet') def testWorkQueue(self): # Run only one photon at a time nphotons = 32 * 12 dphi = np.random.uniform(0, 2.0 * np.pi, nphotons) dcos = np.random.uniform(-1.0, 1.0, nphotons) dir = np.array(zip( np.sqrt(1 - dcos[:] * dcos[:]) * np.cos(dphi[:]), np.sqrt(1 - dcos[:] * dcos[:]) * np.sin(dphi[:]), dcos[:]), dtype=np.float32) pos = np.tile([0, 0, 0], (nphotons, 1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2 * np.pi, nphotons).astype(np.float32) pol[:, 0] = np.cos(phi) pol[:, 1] = np.sin(phi) pol = np.cross(pol, dir) for n, p in enumerate(pol): norm = np.sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]) p /= norm t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(128.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths)
class TestDetector(unittest.TestCase): def setUp(self): # Setup geometry cube = Detector(vacuum) cube.add_pmt(Solid(box(10.0,10,10), vacuum, vacuum, surface=r7081hqe_photocathode)) cube.set_time_dist_gaussian(1.2, -6.0, 6.0) cube.set_charge_dist_gaussian(1.0, 0.1, 0.5, 1.5) geo = create_geometry_from_obj(cube, update_bvh_cache=False) self.geo = geo self.sim = Simulation(self.geo, geant4_processes=0) def testTime(self): '''Test PMT time distribution''' # Run only one photon at a time nphotons = 1 pos = np.tile([0,0,0], (nphotons,1)).astype(np.float32) dir = np.tile([0,0,1], (nphotons,1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2*np.pi, nphotons).astype(np.float32) pol[:,0] = np.cos(phi) pol[:,1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) + 100.0 # Avoid negative photon times wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_times = [] for ev in self.sim.simulate(photons for i in xrange(1000)): if ev.channels.hit[0]: hit_times.append(ev.channels.t[0]) hit_times = np.array(hit_times) self.assertAlmostEqual(hit_times.std(), 1.2, delta=1e-1) def testCharge(self): '''Test PMT charge distribution''' # Run only one photon at a time nphotons = 1 pos = np.tile([0,0,0], (nphotons,1)).astype(np.float32) dir = np.tile([0,0,1], (nphotons,1)).astype(np.float32) pol = np.zeros_like(pos) phi = np.random.uniform(0, 2*np.pi, nphotons).astype(np.float32) pol[:,0] = np.cos(phi) pol[:,1] = np.sin(phi) t = np.zeros(nphotons, dtype=np.float32) wavelengths = np.empty(nphotons, np.float32) wavelengths.fill(400.0) photons = Photons(pos=pos, dir=dir, pol=pol, t=t, wavelengths=wavelengths) hit_charges = [] for ev in self.sim.simulate(photons for i in xrange(1000)): if ev.channels.hit[0]: hit_charges.append(ev.channels.q[0]) hit_charges = np.array(hit_charges) self.assertAlmostEqual(hit_charges.mean(), 1.0, delta=1e-1) self.assertAlmostEqual(hit_charges.std(), 0.1, delta=1e-1)