summaryrefslogtreecommitdiff
path: root/test/test_detector.py
diff options
context:
space:
mode:
authorStan Seibert <stan@mtrr.org>2011-10-07 12:08:12 -0400
committerStan Seibert <stan@mtrr.org>2011-10-07 12:08:12 -0400
commitb264fdd62fc2e641973774dfef99e36d90f21a27 (patch)
tree95a9ecfa1c6661df5e019494f5921c60b36e2bff /test/test_detector.py
parent8c57794e94f9a9321f76946b33dbff6ab1b4d964 (diff)
downloadchroma-b264fdd62fc2e641973774dfef99e36d90f21a27.tar.gz
chroma-b264fdd62fc2e641973774dfef99e36d90f21a27.tar.bz2
chroma-b264fdd62fc2e641973774dfef99e36d90f21a27.zip
Create a Detector class to hold information about the PMTs in a
geometry, like the mapping from solid IDs to channels, and the time and charge distributions. Detector is a subclass of Geometry, so that a Detector can be used wherever a Geometry is used. Only code (like the DAQ stuff) that needs to know how PMT solids map to channels should look for a Detector object. There is a corresponding GPUDetector class as well, with its own device side struct to hold PMT channel information. The GPU code now can sample an arbitrary time and charge PDF, but on the host side, the only interface exposed right now creates a Gaussian distribution.
Diffstat (limited to 'test/test_detector.py')
-rw-r--r--test/test_detector.py76
1 files changed, 76 insertions, 0 deletions
diff --git a/test/test_detector.py b/test/test_detector.py
new file mode 100644
index 0000000..9660e59
--- /dev/null
+++ b/test/test_detector.py
@@ -0,0 +1,76 @@
+import unittest
+import numpy as np
+
+from chroma.geometry import Solid, Geometry, vacuum
+from chroma.detector import Detector
+from chroma.make import box
+from chroma.sim import Simulation
+from chroma.event import Photons
+
+from chroma.demo.optics import r7081hqe_photocathode
+
+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)
+
+ cube.build(use_cache=False)
+
+ self.cube = cube
+ self.sim = Simulation(cube, 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(10000)):
+ 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)