def _extract_photons_from_tracking_action(self, sort=True): n = self.tracking_action.GetNumPhotons() pos = np.zeros(shape=(n, 3), dtype=np.float32) pos[:, 0] = self.tracking_action.GetX() pos[:, 1] = self.tracking_action.GetY() pos[:, 2] = self.tracking_action.GetZ() dir = np.zeros(shape=(n, 3), dtype=np.float32) dir[:, 0] = self.tracking_action.GetDirX() dir[:, 1] = self.tracking_action.GetDirY() dir[:, 2] = self.tracking_action.GetDirZ() pol = np.zeros(shape=(n, 3), dtype=np.float32) pol[:, 0] = self.tracking_action.GetPolX() pol[:, 1] = self.tracking_action.GetPolY() pol[:, 2] = self.tracking_action.GetPolZ() wavelengths = self.tracking_action.GetWavelength().astype(np.float32) t0 = self.tracking_action.GetT0().astype(np.float32) if sort: reorder = argsort_direction(dir) pos = pos[reorder] dir = dir[reorder] pol = pol[reorder] wavelengths = wavelengths[reorder] t0 = t0[reorder] return Photons(pos, dir, pol, wavelengths, t0)
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)
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)
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)
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
def GenScintPhotons(protoString): nsphotons = 0 for i, sData in enumerate(protoString.stepdata): nsphotons += sData.nphotons print "NSPHOTONS: ", nsphotons pos = np.zeros((nsphotons, 3), dtype=np.float32) pol = np.zeros_like(pos) t = np.zeros(nsphotons, dtype=np.float32) wavelengths = np.empty(nsphotons, np.float32) wavelengths.fill(128.0) dphi = np.random.uniform(0, 2.0 * np.pi, nsphotons) dcos = np.random.uniform(-1.0, 1.0, nsphotons) dir = np.array(zip( np.sqrt(1 - dcos[:] * dcos[:]) * np.cos(dphi[:]), np.sqrt(1 - dcos[:] * dcos[:]) * np.sin(dphi[:]), dcos[:]), dtype=np.float32) stepPhotons = 0 for i, sData in enumerate(protoString.stepdata): #instead of appending to array every loop, the full size (nsphotons x 3) is allocated to begin, then #values are filled properly by incrementing stepPhotons. for j in xrange(stepPhotons, (stepPhotons + sData.nphotons)): pos[j, 0] = np.random.uniform(sData.step_start_x, sData.step_end_x) pos[j, 1] = np.random.uniform(sData.step_start_y, sData.step_end_y) pos[j, 2] = np.random.uniform(sData.step_start_z, sData.step_end_z) for j in xrange(stepPhotons, (stepPhotons + sData.nphotons)): pol[j, 0] = np.random.uniform(0, ((1 / 3.0)**.5)) pol[j, 1] = np.random.uniform(0, ((1 / 3.0)**.5)) pol[j, 2] = ((1 - pol[j, 0]**2 - pol[j, 1]**2)**.5) for j in xrange(stepPhotons, (stepPhotons + sData.nphotons)): t[j] = (np.random.exponential(1 / 45.0) + (sData.step_end_t - sData.step_start_t)) stepPhotons += sData.nphotons return Photons(pos=pos, pol=pol, t=t, dir=dir, wavelengths=wavelengths)
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 constant_photons(pos, n): #constructs photons at one location with random propagation directions points = np.empty((n, 3)) points[:] = pos pos = points dir = uniform_sphere(n) pol = np.cross(dir, uniform_sphere(n)) #300 nm is roughly the pseudocumene scintillation wavelength wavelengths = np.repeat(300.0, n) return Photons(pos, dir, pol, wavelengths)
def gaussian_sphere(pos, sigma, n): points = np.empty((n, 3)) points[:, 0] = np.random.normal(0.0, sigma, n) + pos[0] points[:, 1] = np.random.normal(0.0, sigma, n) + pos[1] points[:, 2] = np.random.normal(0.0, sigma, n) + pos[2] pos = points dir = uniform_sphere(n) pol = np.cross(dir, uniform_sphere(n)) #300 nm is roughly the pseudocumene scintillation wavelength wavelengths = np.repeat(300.0, n) return Photons(pos, dir, pol, wavelengths)
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)
def photon_angle(rep, pos=[0, 0, 0]): off = 200 photon_pos = np.zeros((rep, 3)) upshift = 800 for i in range(5): photon_pos[i, :] = [ pos[0] - i * 100 + off - 100, pos[1] + off + 400, pos[2] + upshift ] photon_pos[5, :] = [-800, 600, 800] photon_dir = np.tile(np.array([0.2, -0.55, -1]), (rep, 1)) pol = np.cross(photon_dir, uniform_sphere(rep)) wavelength = np.repeat(300.0, rep) return Photons(photon_pos, photon_dir, pol, wavelength), photon_pos
def uniform_photons(inscribed_radius, n): #constructs photons uniformly throughout the detector inside of the inscribed sphere. radius_root = inscribed_radius * np.power(np.random.rand(n), 1.0 / 3.0) theta = np.arccos(np.random.uniform(-1.0, 1.0, n)) phi = np.random.uniform(0.0, 2 * np.pi, n) points = np.empty((n, 3)) points[:, 0] = radius_root * np.sin(theta) * np.cos(phi) points[:, 1] = radius_root * np.sin(theta) * np.sin(phi) points[:, 2] = radius_root * np.cos(theta) pos = points dir = uniform_sphere(n) pol = np.cross(dir, uniform_sphere(n)) #300 nm is roughly the pseudocumene scintillation wavelength wavelengths = np.repeat(300.0, n) return Photons(pos, dir, pol, wavelengths)
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 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 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)
def gen_test(n, r, det_res): pos = np.random.normal(0, 0.01, (n * det_res.n_lens_sys, 3)) if r == 0.0: lns_dir = config_stat.normalize(det_res.lens_centers, 1) drct = np.repeat(lns_dir, n, axis=0) + np.random.normal( 0.0, 0.001, (n * det_res.n_lens_sys, 3)) else: u_proj = config_stat.normalize( np.cross(det_res.lens_centers, [0, 0, 1]), 1) v_proj = config_stat.normalize(np.cross(det_res.lens_centers, u_proj), 1) angle = 2 * np.pi * np.random.rand(n * det_res.n_lens_sys) drct = np.repeat(det_res.lens_centers, n, axis=0) + r * np.einsum( 'i,ij->ij', np.sin(angle), np.repeat( u_proj, n, axis=0)) + r * np.einsum( 'i,ij->ij', np.cos(angle), np.repeat(v_proj, n, axis=0)) pol = np.cross(drct, np.random.rand(n * det_res.n_lens_sys, 3)) wavelengths = np.repeat(300.0, n * det_res.n_lens_sys) return Photons(pos, drct, pol, wavelengths)
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)
sample = 15 off_center = np.einsum( 'ij,i->ij', np.tile(u_vers, sample).reshape(sample, 3), np.linspace(0, np.linalg.norm(det_res.lens_centers[0]), sample)) for alpha in off_center: off_axis = np.random.rand(amount, 3) * 2 - 1 drc = np.tile((l_c + alpha) / np.linalg.norm(l_c + alpha), amount).reshape(amount, 3) pos = np.einsum( 'ij,i->ij', np.einsum('ij,i->ij', off_axis, 1 / np.linalg.norm(off_axis, axis=1)), np.linspace(0, det_res.lens_rad, amount)) * 0.5 - alpha pol = np.cross(drc, np.random.rand(amount, 3)) wavelengths = np.repeat(300.0, amount) gun = Photons(pos, drc, pol, wavelengths) for ev in sim.simulate(gun, keep_photons_beg=True, keep_photons_end=True, run_daq=False, max_steps=100): #b_pos = ev.photons_beg.pos e_pos = ev.photons_end.pos _, _, detected = analyzer.generate_tracks(ev, heat_map=True, detec=True) e_pos = e_pos[detected] msk = np.einsum('ij,j->i', e_pos, l_c) > 0 e_pos = e_pos[msk]
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()
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)
def calibrate(self, simname, directory=".", nevents=-1, fast_calibration=False): # Use with a simulation file 'simname' to calibrate the detector # Creates a list of mean angles and their uncertainties (sigma for # a cone of unit length), one for each PMT # There are 1000 events in a typical simulation. # Uses all photons hitting a given PMT at once (better estimate of sigma, # but may run out of memory in some cases). # Will not calibrate PMTs with <n_min hits logger.info('Fast calibration: %s' % str(fast_calibration)) self.is_calibrated = True start_time = time.time() base_hits_file_name = self.configname + '-hits' pickle_name = base_hits_file_name + '.pickle' hit_file_exists = False n_min = 10 # Do not calibrate a PMT if <n_min photons hit it try: logger.info('Attempting to load pickle hits file: %s%s' % (directory, pickle_name)) # TODO: This generally won't do anything because we no longer write this file with open(directory + pickle_name, 'rb') as inf: pmt_hits = pickle.load(inf) logger.info('Hit map pickle file loaded: ' + pickle_name) pmt_bins = pmt_hits['pmt_bins'] end_direction_array = pmt_hits['end_direction_array'] n_det = len(pmt_bins) hit_file_exists = True except IOError as error: # Assume file not found logger.info('Hit map pickle file not found. Creating: ' + base_hits_file_name) using_h5 = False if simname.endswith('.h5'): using_h5 = True ev_file = dd.io.load(simname) # TODO: Check the UUID!! events_in_file = len(ev_file['photons_start']) else: from ShortIO.root_short import GaussAngleRootWriter, GaussAngleRootReader, ShortRootReader reader = ShortRootReader(simname) events_in_file = len(reader) logger.info('Loaded simulation file: %s' % simname) logger.info('Simulation event count: %d' % events_in_file) if nevents < 1: nevents = events_in_file max_storage = min( nevents * 1000000, 120000000 ) #600M is too much, 400M is OK (for np.float32; using 300M) end_direction_array = np.empty((max_storage, 3), dtype=np.float32) pmt_bins = np.empty(max_storage, dtype=np.int) n_det = 0 # Loop through events, store for each photon the index of the PMT it hit (pmt_bins) # and the direction pointing back to its origin (end_direction_array) loops = 0 event_source = ev_file['photons_start'] if using_h5 else reader for index, ev_proxy in enumerate( event_source): # Not sure if we can enumerate a reader???? # TODO: This needs to be cleaned up if (using_h5): photons_beg = Photons(ev_proxy, [], [], []) photons_end = Photons(ev_file['photons_stop'][index], [], [], [], flags=ev_file['photon_flags'][index]) else: photons_beg = ev_proxy.photons_beg photons_end = ev_proxy.photons_end loops += 1 if loops > nevents: break if loops % 100 == 0: logger.info("Event " + str(loops) + " of " + str(nevents)) logger.handlers[0].flush() detected = (photons_end.flags & (0x1 << 2)).astype(bool) ''' reflected_diffuse = (ev.photons_end.flags & (0x1 << 5)).astype(bool) reflected_specular = (ev.photons_end.flags & (0x1 << 6)).astype(bool) logger.info("Total detected: " + str(sum(detected * 1))) logger.info("Total reflected: " + str(sum(reflected_diffuse * 1) + sum(reflected_specular * 1))) good_photons = detected & np.logical_not(reflected_diffuse) & np.logical_not(reflected_specular) logger.info("Total detected and not reflected: " + str(sum(good_photons * 1))) ''' if fast_calibration: ending_photons, length = self._find_photons_for_pmt( photons_beg.pos, photons_end.pos, detected, end_direction_array, n_det, max_storage) pmt_b = self.find_pmt_bin_array(ending_photons) if length is None: break else: beginning_photons = photons_beg.pos[ detected] # Include reflected photons ending_photons = photons_end.pos[detected] length = np.shape(ending_photons)[0] pmt_b = self.find_pmt_bin_array(ending_photons) end_point = self.lens_centers[pmt_b / self.n_pmts_per_surf] end_dir = normalize(end_point - beginning_photons) # if end_direction_array is None: # end_direction_array = end_dir # else: # end_direction_array = np.vstack((end_direction_array, end_dir)) #end_direction_array.append(end_dir) if n_det + length > max_storage: logger.info( 'Too many photons to store in memory; not reading any further events.' ) break end_direction_array[n_det:(n_det + length), :] = end_dir # if pmt_bins is None: # pmt_bins = pmt_b # else: # pmt_bins = np.hstack((pmt_bins, pmt_b)) #pmt_bins.append(pmt_b) pmt_bins[n_det:(n_det + length)] = pmt_b n_det += length if loops % 100 == 0: logger.info('Photons detected so far: ' + str(n_det + length)) # logger.info('Sample pmt bins: ' + str(pmt_bins[n_det:(n_det+length)])) logger.info("Time: " + str(time.time() - start_time)) total_means = np.zeros((self.npmt_bins, 3)) total_variances = np.zeros((self.npmt_bins)) total_u_minus_v = np.zeros((self.npmt_bins)) amount_of_hits = np.zeros((self.npmt_bins)) end_direction_array.resize((n_det, 3)) logger.info("Time: " + str(time.time() - start_time)) pmt_bins.resize(n_det) if not hit_file_exists: # TODO: No longer writing the pickle file # Write the pickle hits file regardless of whether using fast_calibration or not #pmt_hits = {'pmt_bins': pmt_bins, 'end_direction_array': end_direction_array} #with open(directory+pickle_name, 'wb') as outf: # pickle.dump(pmt_hits, outf) with h5py.File(directory + base_hits_file_name + '.h5', 'w') as h5file: _ = h5file.create_dataset( 'pmt_bins', data=pmt_bins, chunks=True) # TODO: Should we assign max shape? _ = h5file.create_dataset( 'end_direction_array', data=end_direction_array, chunks=True) # TODO: Should we assign max shape? logger.info('Hit map file created: ' + pickle_name) logger.info( "Finished collecting photons (or loading photon hit list). Time: " + str(time.time() - start_time)) if fast_calibration: bins_base_file_name = self.configname + '-pmt-bins' bins_pickle_file = bins_base_file_name + '.pickle' try: with open( directory + bins_pickle_file, 'rb' ) as inf: # TODO: This generally won't do anything because we no longer write this file pmt_photons = pickle.load(inf) logger.info('PMT photon list pickle file loaded: ' + bins_pickle_file) except IOError as error: start_assign = time.time() pmt_photons = assign_photons(self.npmt_bins, n_det, pmt_bins) logger.info("assign_photons took: " + str(time.time() - start_assign)) # TODO: No longer writing the pickle file #with open(directory + bins_pickle_file, 'wb') as outf: # pickle.dump(pmt_photons, outf) # TODO: Pure H5 does not work. (Because?) #with h5py.File(directory + bins_file + '.h5', 'w') as h5file: # _ = h5file.create_dataset('photon_pmts', data=pmt_photons, chunks=True) # Should we assign max shape? #logger.info('Type: ' + str(type(pmt_photons)) + ' ' + str(type(pmt_photons[0]))) dd.io.save(directory + bins_base_file_name + '.h5', pmt_photons) logger.info('PMT photon list file created: ' + bins_base_file_name + '.h5') logger.info("Finished listing photons by pmt. Time: " + str(time.time() - start_time)) draw_pmt_ind = -1 # looping through each pmt in order to save a mean_angle and a variance for i in range(self.npmt_bins): if i % 10000 == 0: logger.info( str(i) + ' out of ' + str(self.npmt_bins) + ' PMTs') logger.handlers[0].flush() logger.info("Time: " + str(time.time() - start_time)) if fast_calibration: photon_list = pmt_photons[i] angles_for_pmt = end_direction_array[photon_list] n_angles = len(angles_for_pmt) # np.shape(angles_for_pmt)[0] # skipping pmts with <2 photon hits (in which case the variance will be undefined with ddof=1) # also skipping if <n_min photon hits if n_angles < 2 or n_angles < n_min: logger.warning('Not enough angles for PMT: %d, %d' % (i, n_angles)) continue mean_angle, variance, uvvar = compute_pmt_calibration( angles_for_pmt, n_min) else: pmt_indices = np.where(pmt_bins == i)[0] if np.shape(pmt_indices)[0] == 0: continue angles_for_pmt = end_direction_array[pmt_indices] n_angles = np.shape(angles_for_pmt)[0] #skipping pmts with <2 photon hits (in which case the variance will be undefined with ddof=1) #also skipping if <n_min photon hits if n_angles < 2 or n_angles < n_min: continue mean_angle = normalize(np.mean(angles_for_pmt, axis=0)) # For each PMT, get a pair of axes which form an # orthonormal coordinate system with the PMT mean direction u_dir = np.cross(mean_angle, np.array([0, 0, 1])) if not (np.dot(u_dir, u_dir) > 0): # In case mean_angle = [0,0,1] u_dir = np.cross(mean_angle, np.array([0, 1, 0])) u_dir = normalize(u_dir) v_dir = np.cross(mean_angle, u_dir) u_proj = np.dot(angles_for_pmt, u_dir) u_var = np.var(u_proj, ddof=1) v_proj = np.dot(angles_for_pmt, v_dir) v_var = np.var(v_proj, ddof=1) variance = (u_var + v_var) / 2. # Old method, which calculated variance of projected norma, even though # the mean of the projections wasn't 0 due to the solid angle factor norms = np.repeat(1.0, n_angles) projection_norms = np.dot(angles_for_pmt, mean_angle) orthogonal_complements = np.sqrt( np.maximum(norms**2 - projection_norms**2, 0.)) #variance = np.var(orthogonal_complements, ddof=1) uvvar = u_var - v_var try: #draw_pmt_ind = None draw_pmt_ind = int(draw_pmt_ind) ''' if i == draw_pmt_ind or draw_pmt_ind<0: # Temporary, to visualize histogram of angles, distances #angles = np.arccos(projection_norms) #ang_variance = np.var(angles, ddof=1) #fig1 = plt.figure(figsize=(7.8, 6)) #plt.hist(angles, bins=20) #plt.xlabel('Angular Separation to Mean Angle') #plt.ylabel('Counts per bin') #plt.title('Angles Histogram for PMT ' + str(i)) ##plt.show() # #fig2 = plt.figure(figsize=(7.8, 6)) #plt.hist(angles, bins=20, weights=1./np.sin(angles)) #plt.xlabel('Angular Separation to Mean Angle') #plt.ylabel('Counts per solid angle') #plt.title('Angles Histogram for PMT ' + str(i)) fig3 = plt.figure(figsize=(7.8, 6)) plt.hist(orthogonal_complements, bins=20) plt.xlabel('Normalized Distance to Mean Angle') plt.ylabel('Counts per bin') plt.title('Distances Histogram for PMT ' + str(i)) fig4 = plt.figure(figsize=(7.8, 6)) plt.hist(u_proj, bins=20) plt.xlabel('U Distance to Mean Angle') plt.ylabel('Counts per bin') plt.title('U Distances Histogram for PMT ' + str(i)) fig5 = plt.figure(figsize=(7.8, 6)) plt.hist(v_proj, bins=20) plt.xlabel('V Distance to Mean Angle') plt.ylabel('Counts per bin') plt.title('V Distances Histogram for PMT ' + str(i)) plt.show() #print "Average projected variance: ", variance #print "Variance of projected 2D norms: ", np.var(orthogonal_complements, ddof=1) draw_pmt_ind = raw_input("Enter index of next PMT to draw; will stop drawing if not a valid PMT index.\n") ''' except ValueError: pass except TypeError: pass total_means[i] = mean_angle total_variances[i] = variance total_u_minus_v[i] = np.abs(uvvar) amount_of_hits[i] = n_angles if np.isnan(variance): print "Nan for PMT " + str(i) # nan_ind = np.where(np.isnan(orthogonal_complements)) # print nan_ind # print projection_norms # print orthogonal_complements # print angles_for_pmt # print variance # print mean_angle # temporary, for debugging: n_hits = np.sum(amount_of_hits, axis=0) print "Total hits for calibrated PMTs: " + str(n_hits) print "PMTs w/ < n_events hits: " + str( len(np.where(amount_of_hits < nevents)[0]) * 1.0 / self.npmt_bins) print "PMTs w/ < n_min hits: " + str( len(np.where(amount_of_hits < n_min)[0]) * 1.0 / self.npmt_bins) print "PMTs w/ < 100 hits: " + str( len(np.where(amount_of_hits < 100)[0]) * 1.0 / self.npmt_bins) print "Mean U-V variance (abs): " + str(np.mean(total_u_minus_v)) # Store final calibrated values self.means = -total_means.astype(np.float32).T self.sigmas = np.sqrt(total_variances.astype(np.float32))
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()
def generate_photons(self, vertices, mute=False, tracking=False): """Use GEANT4 to generate photons produced by propagating `vertices`. Args: vertices: list of event.Vertex objects List of initial particle vertices. mute: bool Disable GEANT4 output to console during generation. (GEANT4 can be quite chatty.) Returns: photons: event.Photons Photon vertices generated by the propagation of `vertices`. """ if mute: pass #g4mute() self.stepping_action.EnableTracking(tracking) photons = Photons() if tracking: photon_parent_tracks = [] try: tracked_vertices = [] for vertex in vertices: self.particle_gun.SetParticleByName(vertex.particle_name) #Geant4 seems to call 'ParticleEnergy' KineticEnergy - see G4ParticleGun kinetic_energy = vertex.ke * MeV self.particle_gun.SetParticleEnergy(kinetic_energy) # Must be float type to call GEANT4 code pos = np.asarray(vertex.pos, dtype=np.float64) dir = np.asarray(vertex.dir, dtype=np.float64) self.particle_gun.SetParticlePosition(G4ThreeVector(*pos) * mm) self.particle_gun.SetParticleMomentumDirection( G4ThreeVector(*dir).unit()) self.particle_gun.SetParticleTime(vertex.t0 * ns) if vertex.pol is not None: self.particle_gun.SetParticlePolarization( G4ThreeVector(*vertex.pol).unit()) self.tracking_action.Clear() self.stepping_action.ClearTracking() gRunManager.BeamOn(1) if tracking: vertex = self._extract_vertex_from_stepping_action() photon_parent_tracks.append( self.tracking_action.GetParentTrackID().astype( np.int32)) tracked_vertices.append(vertex) photons += self._extract_photons_from_tracking_action() if tracking: photon_parent_tracks = [ track for track in photon_parent_tracks if len(track) > 0 ] photon_parent_tracks = np.concatenate( photon_parent_tracks ) if len(photon_parent_tracks) > 0 else [] finally: if mute: pass #g4unmute() if tracking: return (tracked_vertices, photons, photon_parent_tracks) else: return (tracked_vertices, photons)
pos = np.tile([1200, 0, 1000], (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) print "photons generated" events = sim.simulate(photons, keep_photons_end=True, max_steps=2000) photon_endpos = None photon_colors = None colordict = { chroma.event.SURFACE_DETECT: (1.0, 0.0, 0.0, 1.0), chroma.event.BULK_ABSORB: (0.0, 1.0, 0.0, 1.0), chroma.event.WIREPLANE_ABSORB: (1.0, 1.0, 0.0, 0.5), chroma.event.SURFACE_ABSORB: (14.0 / 255.0, 26.0 / 255.0, 191.0 / 255.0, 0.5), 0: (0.0, 0.0, 0.0, 0.1) } for ev in events:
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)