minisim.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 '''
3 A simple drift simulation using response functions. No diffusion.
4 '''
5 
6 from .. import units
7 import numpy
8 import collections
9 from math import radians, sin, cos
10 
11 # ie, Geant4 hits.
12 Hit = collections.namedtuple("Hit", "x y z t q")
13 
14 def dir_yz(deg):
15  return (sin(radians(deg)), cos(radians(deg)))
16 
17 class Minisim(object):
18  '''
19  Simulate the response to a distribution of charge.
20 
21  todo:
22 
23  - for each hit, find all rf's for the hits impact, use each
24  region number as offset to hit's wire number, fill frame.
25  '''
26 
27  defaults = dict(
28  nticks=9600,
29  nwires=(2400,2400,3456),
30  pitch=3.0*units.mm,
31  impact=0.3*units.mm,
32  velocity=1.6*units.mm/units.us,
33  tick=0.5*units.us, # digitization tick
34  )
35  def __init__(self, pib, **kwds):
36  '''
37  Create a mini simulation.
38 
39  - pib :: a response.PlaneImpactBlocks object
40 
41  '''
42  self.pib = pib
43  self._cfg = dict(self.defaults, **kwds)
44 
45  self.wire_yz_dir = numpy.asarray((dir_yz(30), dir_yz(150), dir_yz(90)))
46  self.wire_yz_pit = numpy.asarray((dir_yz(-60), dir_yz(60), dir_yz(0)))
47  self.wire_yz_off = numpy.asarray(((0.0, 0.0),
48  (0.0, 0.0),
49  (0.0, 0.5*self.pitch)))
50 
51  self.frame = None # becomes 3-tuple
52  self.clear_frame() # prime
53 
54  def __getattr__(self, key):
55  return self._cfg[key]
56 
57  def wire_space(self, hits):
58  '''
59  Return the location of a hit in terms of (wire number, impact).
60  '''
61  ret = list()
62 
63  hit_yz = hits[:,1:3]
64  for iplane in range(3):
65  yz = hit_yz - self.wire_yz_off[iplane]
66  pit = numpy.dot(yz, self.wire_yz_pit[iplane]) # distance along pitch from center
67  pwidth = self.pitch * self.nwires[iplane]/2
68  pit += pwidth # distance along pitch from wire 0
69  wiredist = pit/self.pitch
70  wire = numpy.asarray(numpy.round(wiredist), dtype=int)
71  impact = numpy.round((wiredist-wire)/self.impact) * self.impact
72  ret.append(numpy.vstack((wire, impact)).T)
73  return ret
74 
75 
76  def apply_block(self, block, iplane, ich, time):
77  '''
78  Apply block array to plane array with ich and itick offsets
79  '''
80  dch = block.shape[0]//2
81  chm = int(max(ich-dch, 0))
82  chp = int(min(ich+dch, self.nwires[iplane]-1))
83  #print 'ch:',dch, chm, chp
84 
85  tfinebin_min = int(time/self.pib.tbin)
86  tfinebin_jmp = int(self.tick/self.pib.tbin)
87  #print 'time:',time,tfinebin_min, tfinebin_jmp
88 
89  sampled = block[:,tfinebin_min::tfinebin_jmp]
90  #print 'sampled:',sampled.shape
91 
92  tsampbin_num = len(sampled[0])
93  tsampbin_min = int(time/self.tick)
94  tsampbin_max = min(tsampbin_min+tsampbin_num, len(self.frame[iplane][0]))
95  print 'samp bin:',tsampbin_num, tsampbin_min, tsampbin_max*self.tick/units.us
96 
97  self.frame[iplane][chm:chp+1, tsampbin_min:tsampbin_max] = sampled
98 
99 
100  def clear_frame(self):
101  '''
102  Initialize a new frame.
103  '''
104  frame = list()
105  for nwires in self.nwires:
106  frame.append(numpy.zeros((nwires, self.nticks)))
107  self.frame = tuple(frame)
108  return
109 
110  def add_hits(self, hits):
111  '''
112  Add response to hits to current frame.
113  '''
114  nearest_chimps = self.wire_space(hits)
115  for iplane, chimps in enumerate(nearest_chimps):
116  for ihit, (ch,imp) in enumerate(chimps):
117  x,y,z,q,t = hit = hits[ihit]
118  block = self.pib.region_block("uvw"[iplane], imp)
119  self.apply_block(block, iplane, ch, (t-self.pib.tmin) + (x-self.pib.xstart)/self.velocity)
120 
121 
122 
def __getattr__(self, key)
Definition: minisim.py:54
def __init__(self, pib, kwds)
Definition: minisim.py:35
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:69
def apply_block(self, block, iplane, ich, time)
Definition: minisim.py:76
static int max(int a, int b)
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
def wire_space(self, hits)
Definition: minisim.py:57