Namespaces | Classes | Functions | Variables
wirecell.sigproc.response Namespace Reference

Namespaces

 persist
 
 plots
 
 schema
 

Classes

class  foo
 
class  PlaneImpactBlocks
 
class  ResponseFunction
 

Functions

def electronics_no_gain_scale (time, gain, shaping=2.0 *units.us)
 
def electronics (time, peak_gain=14 *units.mV/units.fC, shaping=2.0 *units.us)
 
def convolve (f1, f2)
 
def _convolve (f1, f2)
 
def group_by (rflist, field)
 
def by_region (rflist, region=0)
 
def total_charge (rf)
 
def normalize (rflist, plane='w', region=0, impact=None)
 
def _average (fine)
 
def average (fine)
 
def field_response_spectra (rflist)
 
def plane_impact_blocks (rflist, eresp=None)
 
def response_spect_nominal (rflist, gain, shaping, tick=0.5 *units.us)
 
def filter_expower (sig, power, nbins, nyquist)
 
def filters (nticks=9600, tick=0.5 *units.us, npitches=3000, pitch=1.0)
 
def deconvolve (Mct, Rpf, Ff, Fp)
 
def schematorf1d (fr)
 
def rf1dtoschema (rflist, origin=10 *units.cm, speed=1.114 *units.mm/units.us)
 
def write (rflist, outputfile="wire-cell-garfield-response.json.bz2")
 
def line (rflist, normalization=13700 *units.eplus)
 

Variables

 electronics = numpy.vectorize(electronics)
 

Detailed Description

Functions related to responses.

Function Documentation

def wirecell.sigproc.response._average (   fine)
private
Average fine-grained response functions over multiple impact
positions in the same plane and wire region.

Return list of new response.ResponseFunction objects ordered by
plane, region.

Definition at line 220 of file __init__.py.

220 def _average(fine):
221  '''
222  Average fine-grained response functions over multiple impact
223  positions in the same plane and wire region.
224 
225  Return list of new response.ResponseFunction objects ordered by
226  plane, region.
227  '''
228  ret = list()
229  for inplane in group_by(fine, 'plane'):
230  byregion = group_by(inplane, 'region')
231  noigeryb = list(byregion)
232  noigeryb.reverse()
233 
234  regions = [rflist[0].region for rflist in byregion]
235  center = max(regions)
236 
237  # warning: this makes detailed assumptions about where the impact points are!
238  for regp,regm in zip(byregion[center:], noigeryb[center:]):
239  regp.sort(key=lambda x: x.impact)
240  regm.sort(key=lambda x: x.impact)
241 
242  tot = numpy.zeros_like(regp[0].response)
243  count = 0
244  for one in regp + regm: # sums 2 regions!
245  tot += one.response
246  count += 1
247  tot *= 2.0 # reflect across wire region
248  count *= 2
249  tot -= regp[0].response + regm[0].response # share region boundary path
250  count -= 2
251  tot -= regp[-1].response + regm[-1].response # don't double count impact=0
252  count -= 2
253  tot /= count
254  dat = regp[0].dup(response=tot, impact=None)
255  ret.append(dat)
256  continue
257  return ret
258 
static int max(int a, int b)
def group_by(rflist, field)
Definition: __init__.py:162
auto zip(Iterables &&...iterables)
Range-for loop helper iterating across many collections at the same time.
Definition: zip.h:295
def wirecell.sigproc.response._convolve (   f1,
  f2 
)
private
Return the simple convolution of the two arrays using FFT+mult+invFFT method.

Definition at line 79 of file __init__.py.

79 def _convolve(f1, f2):
80  '''
81  Return the simple convolution of the two arrays using FFT+mult+invFFT method.
82  '''
83  from scipy.signal import fftconvolve
84  return fftconvolve(f1, f2, "same")
85 
86 
87 
def _convolve(f1, f2)
Definition: __init__.py:79
def wirecell.sigproc.response.average (   fine)
Average fine-grained response functions over multiple impact
positions in the same plane and wire region.  It assumes an odd
number of regions and a half-populated impact positions per region
such that the first impact is exactly on a wire and the impact is
exactly on a half-way line between neighboring wires.

Return list of new response.ResponseFunction objects ordered by
plane, region which cover the same regions.

Definition at line 259 of file __init__.py.

259 def average(fine):
260  '''
261  Average fine-grained response functions over multiple impact
262  positions in the same plane and wire region. It assumes an odd
263  number of regions and a half-populated impact positions per region
264  such that the first impact is exactly on a wire and the impact is
265  exactly on a half-way line between neighboring wires.
266 
267  Return list of new response.ResponseFunction objects ordered by
268  plane, region which cover the same regions.
269  '''
270  coarse = list()
271  for inplane in group_by(fine, 'plane'):
272  byregion = group_by(inplane, 'region')
273 
274  # for each region, we need to take impacts from the region on the other
275  # side of center. So march down the reverse while we march up the
276  # original.
277  noigeryb = list(byregion)
278  noigeryb.reverse()
279 
280  for regp, regm in zip(byregion, noigeryb):
281  # Assure each region is sorted so first is impact=0
282  regp.sort(key=lambda x: abs(x.impact))
283  regm.sort(key=lambda x: abs(x.impact))
284 
285  tot = numpy.zeros_like(regp[0].response)
286 
287  nimpacts = len(regp)
288  binsize = [1.0]*nimpacts # unit impact bin size
289  binsize[0] = 0.5; # each center impact only covers 1/2 impact bin
290  binsize[-1] = 0.5; # same for the edge impacts
291 
292  for impact in range(nimpacts):
293  rp = regp[impact]
294  rm = regm[impact]
295  tot += binsize[impact]*(rp.response + rm.response)
296 
297  # normalize by total number of impact bins
298  tot /= 2*(nimpacts-1)
299  dat = regp[0].dup(response=tot, impact=None)
300  coarse.append(dat)
301  continue
302  return coarse
303 
304 
305 
306 
T abs(T value)
def group_by(rflist, field)
Definition: __init__.py:162
auto zip(Iterables &&...iterables)
Range-for loop helper iterating across many collections at the same time.
Definition: zip.h:295
def wirecell.sigproc.response.by_region (   rflist,
  region = 0 
)

Definition at line 172 of file __init__.py.

172 def by_region(rflist, region=0):
173  ret = [rf for rf in rflist if rf.region == region]
174  ret.sort(key=lambda x: x.plane)
175  return ret
176 
177 
def by_region(rflist, region=0)
Definition: __init__.py:172
def wirecell.sigproc.response.convolve (   f1,
  f2 
)
Return the simple convolution of the two arrays using FFT+mult+invFFT method.

Definition at line 66 of file __init__.py.

66 def convolve(f1, f2):
67  '''
68  Return the simple convolution of the two arrays using FFT+mult+invFFT method.
69  '''
70  # fftconvolve adds an unwanted time shift
71  #from scipy.signal import fftconvolve
72  #return fftconvolve(field, elect, "same")
73  s1 = numpy.fft.fft(f1)
74  s2 = numpy.fft.fft(f2)
75  sig = numpy.fft.ifft(s1*s2)
76 
77  return numpy.real(sig)
78 
def convolve(f1, f2)
Definition: __init__.py:66
def wirecell.sigproc.response.deconvolve (   Mct,
  Rpf,
  Ff,
  Fp 
)
Return a matrix like Mct which is deconvolved by Rpf and filtered
with the Ff and Fp.

Indices are c=channel, t=time, p=periodicity, f=frequency.

Mct is the measured ADC in a plane as a matrix of Nchannel rows
and Nticks columns.

Rpf is the wire periodicity and frequency space 2D Fourier
transform of the field response * electronics response.  It is
assumed to contain only the four corners up the time and wire
Nyquist frequencies of Mct.

Ff is a frequency space filter.

Fp is the channel periodicity space filter.

Definition at line 586 of file __init__.py.

586 def deconvolve(Mct, Rpf, Ff, Fp):
587  '''
588  Return a matrix like Mct which is deconvolved by Rpf and filtered
589  with the Ff and Fp.
590 
591  Indices are c=channel, t=time, p=periodicity, f=frequency.
592 
593  Mct is the measured ADC in a plane as a matrix of Nchannel rows
594  and Nticks columns.
595 
596  Rpf is the wire periodicity and frequency space 2D Fourier
597  transform of the field response * electronics response. It is
598  assumed to contain only the four corners up the time and wire
599  Nyquist frequencies of Mct.
600 
601  Ff is a frequency space filter.
602 
603  Fp is the channel periodicity space filter.
604  '''
605 
606  nchan,ntick = Mct.shape
607  nperi,nfreq = Rpf.shape
608 
609  Mpf = numpy.fft.fft2(Mct, axes=(0,1))
610  Mpf = numpy.delete(Mpf, range(nperi/2, nchan-nperi/2), axis=0)
611  Mpf = numpy.delete(Mpf, range(nfreq/2, ntick-nfreq/2), axis=1)
612 
613  Spf = Mpf/Rpf * Fp[:nperi].reshape(1,nperi).T
614  Scf = numpy.fft.ifft2(Spf, axes=(1,))
615  Scf = Scf * Ff[:nfreq]
616  Sct = numpy.fft.ifft2(Scf, axes=(0,))
617  return Sct
618 
619 
def deconvolve(Mct, Rpf, Ff, Fp)
Definition: __init__.py:586
def wirecell.sigproc.response.electronics (   time,
  peak_gain = 14*units.mV/units.fC,
  shaping = 2.0*units.us 
)
Electronics response function.

    - gain :: the peak gain value in [voltage]/[charge]

    - shaping :: the shaping time in Wire Cell system of units

    - domain :: outside this pair, the response is identically zero

Definition at line 43 of file __init__.py.

43 def electronics(time, peak_gain=14*units.mV/units.fC, shaping=2.0*units.us):
44  '''
45  Electronics response function.
46 
47  - gain :: the peak gain value in [voltage]/[charge]
48 
49  - shaping :: the shaping time in Wire Cell system of units
50 
51  - domain :: outside this pair, the response is identically zero
52  '''
53  # see wirecell.sigproc.plots.electronics() for these magic numbers.
54  if shaping <= 0.5*units.us:
55  gain = peak_gain*10.146826
56  elif shaping <= 1.0*units.us:
57  gain = peak_gain*10.146828
58  elif shaping <= 2.0*units.us:
59  gain = peak_gain*10.122374
60  else:
61  gain = peak_gain*10.120179
62  return electronics_no_gain_scale(time, gain, shaping)
63 
def electronics_no_gain_scale(time, gain, shaping=2.0 *units.us)
Definition: __init__.py:14
def wirecell.sigproc.response.electronics_no_gain_scale (   time,
  gain,
  shaping = 2.0*units.us 
)
This version takes gain parameter already scaled such that the
gain actually desired is obtained.  

Definition at line 14 of file __init__.py.

14 def electronics_no_gain_scale(time, gain, shaping=2.0*units.us):
15  '''
16  This version takes gain parameter already scaled such that the
17  gain actually desired is obtained.
18  '''
19  domain=(0, 10*units.us)
20  if time <= domain[0] or time >= domain[1]:
21  return 0.0
22 
23  time = time/units.us
24  st = shaping/units.us
25 
26  from math import sin, cos, exp
27  ret = 4.31054*exp(-2.94809*time/st) \
28  -2.6202*exp(-2.82833*time/st)*cos(1.19361*time/st) \
29  -2.6202*exp(-2.82833*time/st)*cos(1.19361*time/st)*cos(2.38722*time/st) \
30  +0.464924*exp(-2.40318*time/st)*cos(2.5928*time/st) \
31  +0.464924*exp(-2.40318*time/st)*cos(2.5928*time/st)*cos(5.18561*time/st) \
32  +0.762456*exp(-2.82833*time/st)*sin(1.19361*time/st) \
33  -0.762456*exp(-2.82833*time/st)*cos(2.38722*time/st)*sin(1.19361*time/st) \
34  +0.762456*exp(-2.82833*time/st)*cos(1.19361*time/st)*sin(2.38722*time/st) \
35  -2.6202*exp(-2.82833*time/st)*sin(1.19361*time/st)*sin(2.38722*time/st) \
36  -0.327684*exp(-2.40318*time/st)*sin(2.5928*time/st) + \
37  +0.327684*exp(-2.40318*time/st)*cos(5.18561*time/st)*sin(2.5928*time/st) \
38  -0.327684*exp(-2.40318*time/st)*cos(2.5928*time/st)*sin(5.18561*time/st) \
39  +0.464924*exp(-2.40318*time/st)*sin(2.5928*time/st)*sin(5.18561*time/st)
40  ret *= gain
41  return ret
42 
def electronics_no_gain_scale(time, gain, shaping=2.0 *units.us)
Definition: __init__.py:14
def wirecell.sigproc.response.field_response_spectra (   rflist)
Return a tuple of response spectra as collection of per-plane
matrices in channel periodicity vs frequency.  The rflist is both
averaged over impacts (if needed) and normalized.

Definition at line 307 of file __init__.py.

308  '''
309  Return a tuple of response spectra as collection of per-plane
310  matrices in channel periodicity vs frequency. The rflist is both
311  averaged over impacts (if needed) and normalized.
312  '''
313  impacts = set([rf.impact for rf in rflist])
314  if len(impacts) > 1:
315  rflist = average(rflist)
316  rflist = normalize(rflist)
317 
318  ret = list()
319 
320  byplane = group_by(rflist, 'plane')
321  for inplane in byplane:
322  inplane.sort(key=lambda x: x.region)
323  responses = [rf.response for rf in inplane]
324  rows = list(responses)
325  rows.reverse() # mirror
326  rows += responses[1:] # don't double add region==0
327  mat = numpy.asarray(rows)
328  spect = numpy.fft.fft2(mat, axes=(0,1))
329  ret.append(spect)
330  return tuple(ret)
331 
def field_response_spectra(rflist)
Definition: __init__.py:307
def group_by(rflist, field)
Definition: __init__.py:162
def normalize(rflist, plane='w', region=0, impact=None)
Definition: __init__.py:188
def wirecell.sigproc.response.filter_expower (   sig,
  power,
  nbins,
  nyquist 
)
Return a Fourier space filter function:

filter = exp(-(freq/sig)^(power))

The filter function is returned as an array `nbins` long covering
the low half of the Fourier domain up to the given `nyquist`
"frequency".

The `sig` and `nyquist` parameters are in units of the relevant
"frequency" for the given Fourier domain.  For time-domain Fourier
this is likely Hz.  For channel-domain this is likely in units of
per pitch (unitless).  Caller assures this consistency.

Definition at line 533 of file __init__.py.

533 def filter_expower(sig, power, nbins, nyquist):
534  '''
535  Return a Fourier space filter function:
536 
537  filter = exp(-(freq/sig)^(power))
538 
539  The filter function is returned as an array `nbins` long covering
540  the low half of the Fourier domain up to the given `nyquist`
541  "frequency".
542 
543  The `sig` and `nyquist` parameters are in units of the relevant
544  "frequency" for the given Fourier domain. For time-domain Fourier
545  this is likely Hz. For channel-domain this is likely in units of
546  per pitch (unitless). Caller assures this consistency.
547  '''
548  freqs = numpy.linspace(0, nyquist, nbins)
549  def filt(f):
550  return math.exp(-0.5*((f/sig)**power))
551  filt = numpy.vectorize(filt)
552  return filt(freqs)
553 
554 
def filter_expower(sig, power, nbins, nyquist)
Definition: __init__.py:533
def wirecell.sigproc.response.filters (   nticks = 9600,
  tick = 0.5*units.us,
  npitches = 3000,
  pitch = 1.0 
)
Return (fu,fv,fw,fc) filters.

See `filter_expower()` for details.

Definition at line 555 of file __init__.py.

555 def filters(nticks=9600, tick=0.5*units.us, npitches=3000, pitch=1.0):
556  '''
557  Return (fu,fv,fw,fc) filters.
558 
559  See `filter_expower()` for details.
560  '''
561  tick_seconds = tick/units.s
562  nyquist_hz = 1.0/(2*tick_seconds)
563 
564  # note, these parameters are scaled from what is in the prototype
565  # to be implicitly in Hz instead of MHz.
566  #
567  # These parameters were found by applying a Weiner-inspired filter
568  # to a toy simulation using 2D microboone response and electronics
569  # functions and noise model. They may need to be re-evaluated for
570  # other detectors.
571  fu = filter_expower(2*1.43555e+07/200.0, 4.95096e+00, nticks, nyquist_hz)
572  fv = filter_expower(2*1.47404e+07/200.0, 4.97667e+00, nticks, nyquist_hz)
573  fw = filter_expower(2*1.45874e+07/200.0, 5.02219e+00, nticks, nyquist_hz)
574 
575  nyquist_pp = 1.0/(2*pitch) # pp = per pitch
576 
577  # note, this parameter is scaled to move the somewhat bogus 0.5
578  # (us) number that was used in the prototype out of the "freq" and
579  # into the "sig". In microboone, this filter appears to be only
580  # needed for simulation.
581  fc = filter_expower((1.4*0.5)/math.sqrt(math.pi), 2.0, npitches, nyquist_pp)
582 
583  return (fu, fv, fw, fc)
584 
585 
def filter_expower(sig, power, nbins, nyquist)
Definition: __init__.py:533
def filters(nticks=9600, tick=0.5 *units.us, npitches=3000, pitch=1.0)
Definition: __init__.py:555
def wirecell.sigproc.response.group_by (   rflist,
  field 
)
Return a list of lists grouping by like values of the field.

Definition at line 162 of file __init__.py.

162 def group_by(rflist, field):
163  '''
164  Return a list of lists grouping by like values of the field.
165  '''
166  ret = list()
167  for thing in sorted(set(getattr(d, field) for d in rflist)):
168  bything = [d for d in rflist if getattr(d, field) == thing]
169  ret.append(bything)
170  return ret
171 
def group_by(rflist, field)
Definition: __init__.py:162
def wirecell.sigproc.response.line (   rflist,
  normalization = 13700*units.eplus 
)
Assuming an infinite track of `normalization` ionization electrons
per pitch which runs along the starting points of the response
function paths, calculate the average response on the central wire
of each plane.  The returned responses will be normalized such
that the collection response integrates to the given normalization
value if nonzero.

Definition at line 701 of file __init__.py.

701 def line(rflist, normalization=13700*units.eplus):
702  '''
703  Assuming an infinite track of `normalization` ionization electrons
704  per pitch which runs along the starting points of the response
705  function paths, calculate the average response on the central wire
706  of each plane. The returned responses will be normalized such
707  that the collection response integrates to the given normalization
708  value if nonzero.
709  '''
710 
711  impacts = set([rf.impact for rf in rflist])
712  if len(impacts) > 1:
713  rflist = average(rflist)
714  byplane = group_by(rflist, 'plane')
715 
716  # sum across all impact positions assuming a single point source is
717  # equivalent to summing across a perpendicular line source for a single,
718  # central wire.
719  ret = list()
720  for inplane in byplane:
721  first = inplane[0]
722  tot = numpy.zeros_like(first.response)
723  for rf in inplane:
724  tot += rf.response
725  dat = first.dup(response=tot, impact=None, region=None)
726  ret.append(dat)
727 
728  # normalize to user's amount of charge
729  if normalization > 0.0:
730  for rf in ret:
731  rf.response *= normalization
732 
733  return ret
734 
735 
def line(rflist, normalization=13700 *units.eplus)
Definition: __init__.py:701
def group_by(rflist, field)
Definition: __init__.py:162
def wirecell.sigproc.response.normalize (   rflist,
  plane = 'w',
  region = 0,
  impact = None 
)
Return new rflist with all responses normalized to be in Ampere
and assuming a single electron was drifting.

The collection signal on the given plane and region is used to
normalize.  If impact is an impact distance, or a list of them
then the average collection signal is used.  If not given, all
impacts for the given plane/region are used.

Definition at line 188 of file __init__.py.

188 def normalize(rflist, plane='w', region=0, impact=None):
189  '''
190  Return new rflist with all responses normalized to be in Ampere
191  and assuming a single electron was drifting.
192 
193  The collection signal on the given plane and region is used to
194  normalize. If impact is an impact distance, or a list of them
195  then the average collection signal is used. If not given, all
196  impacts for the given plane/region are used.
197  '''
198  toaverage = [rf for rf in rflist if rf.plane == plane and rf.region == region]
199  if impact is not None:
200  if not isinstance(impact, collections.Sequence):
201  impact = [impact]
202  toaverage = [rf for rf in toaverage if rf.impact in impact]
203 
204  num = len(toaverage)
205  if 0 == num:
206  msg = "No fields to average out of %d for nomalize(%s, %d, %s)" % (len(rflist), plane, region, impact)
207  raise ValueError(msg)
208 
209  qtot = sum([total_charge(rf) for rf in toaverage])
210  qavg = qtot/num
211  scale = -units.eplus/qavg
212 
213  out = list()
214  for rf in rflist:
215  newrf = rf.dup(response = rf.response*scale)
216  out.append(newrf)
217  return out
218 
219 
def normalize(rflist, plane='w', region=0, impact=None)
Definition: __init__.py:188
def wirecell.sigproc.response.plane_impact_blocks (   rflist,
  eresp = None 
)
Return a field responses as a number of matrices blocked by impacts.

Returns a triple of arrays of shape (Nimpacts, Nregion, Ntbins).

If eresp is given, it is convolved with each response function.

Definition at line 332 of file __init__.py.

332 def plane_impact_blocks(rflist, eresp = None):
333  '''
334  Return a field responses as a number of matrices blocked by impacts.
335 
336  Returns a triple of arrays of shape (Nimpacts, Nregion, Ntbins).
337 
338  If eresp is given, it is convolved with each response function.
339  '''
340 
341  # symmetry: Response on wire 0 due to path at wire region i,
342  # impact j is same as Response on wire 0 due to path at wire
343  # region -i, impact -j.
344 
345  # symmetry: Response on Wire 0 due to path at wire region i,
346  # impact j is same as response on wire i, due to path at wire
347  # region 0, impact j.
348 
349  ret = list()
350  byplane = group_by(rflist, 'plane')
351  for inplane in byplane:
352  byimpact = group_by(inplane, 'impact')
353  impacts = [d[0].impact for d in byimpact]
354  nimpacts = len(impacts)
355  regions = list(set([rf.region for rf in inplane]))
356  regions.sort()
357  nregions = len(regions)
358  ntbins = len(inplane[0].response)
359  pib_shape = (nimpacts, nregions, ntbins)
360 
361  pib = numpy.zeros(pib_shape)
362  for inimpact in byimpact:
363  impact_index = impacts.index(inimpact[0].impact)
364  for inregion in inimpact:
365  region_index = regions.index(inregion.region)
366  pib[impact_index, region_index] = inregion.response
367  ret.append(pib)
368  return ret
369 
370 
371 # pibs
def plane_impact_blocks(rflist, eresp=None)
Definition: __init__.py:332
def group_by(rflist, field)
Definition: __init__.py:162
def wirecell.sigproc.response.response_spect_nominal (   rflist,
  gain,
  shaping,
  tick = 0.5*units.us 
)
Return the a response matrix such as passed to `deconvolve()`.

Only the frequencies corresponding to a sampling period of `tick`
are retained.  

Definition at line 508 of file __init__.py.

508 def response_spect_nominal(rflist, gain, shaping, tick=0.5*units.us):
509  '''
510  Return the a response matrix such as passed to `deconvolve()`.
511 
512  Only the frequencies corresponding to a sampling period of `tick`
513  are retained.
514  '''
515  first = rflist[0]
516  frm = field_response_spectra(rflist)
517 
518  elect = electronics(first.times, gain, shaping)
519  elesp = numpy.fft.fft(elect)
520 
521  # number of frequencies to keep to correspond to downsampled tick
522  Nhave = first.nbins
523  Nkeep = int(round(first.nbins/(2.0*tick/(first.times[1]-first.times[0]))))
524 
525  # chop out the "middle" frequencies around the nominal Nyquist freq.
526  frm_chopped = [numpy.delete(f, range(Nkeep, Nhave-Nkeep), axis=1) for f in frm]
527  ele_chopped = numpy.delete(elesp, range(Nkeep, Nhave-Nkeep))
528 
529  resp = [ele_chopped*f for f in frm_chopped]
530  return resp
531 
532 
def field_response_spectra(rflist)
Definition: __init__.py:307
def response_spect_nominal(rflist, gain, shaping, tick=0.5 *units.us)
Definition: __init__.py:508
def wirecell.sigproc.response.rf1dtoschema (   rflist,
  origin = 10*units.cm,
  speed = 1.114*units.mm/units.us 
)
Convert the list of 1D ResponseFunction objects into
response.schema objects.

The "1D" refers to the drift paths starting on a line in 2D space.

Because it is 1D, all the pitch and wire directions are the same.

Definition at line 640 of file __init__.py.

640 def rf1dtoschema(rflist, origin=10*units.cm, speed = 1.114*units.mm/units.us):
641  '''
642  Convert the list of 1D ResponseFunction objects into
643  response.schema objects.
644 
645  The "1D" refers to the drift paths starting on a line in 2D space.
646 
647  Because it is 1D, all the pitch and wire directions are the same.
648  '''
649  #rflist = normalize(rflist)
650 
651  anti_drift_axis = (1.0, 0.0, 0.0)
652  one = rflist[0] # get sample times
653  period = (one.times[1] - one.times[0])
654  tstart = one.times[0]
655 
656  planes = list()
657  byplane = group_by(rflist, 'plane')
658  for inplane in byplane:
659  letter = inplane[0].plane
660  planeid = "uvw".index(letter)
661  onetwo = [rf for rf in inplane if rf.impact == 0.0 and (rf.region == 0 or rf.region==1)]
662  pitch = abs(onetwo[0].pos[0] - onetwo[1].pos[0])
663  location = inplane[0].pos[1]
664  inplane.sort(key=lambda x: x.region*10000+x.impact)
665 
666  paths = list()
667  for rf in inplane:
668  pitchpos = (rf.region*pitch + rf.impact)
669  wirepos = 0.0
670  par = schema.PathResponse(rf.response, pitchpos, wirepos)
671  paths.append(par)
672 
673  plr = schema.PlaneResponse(paths, planeid, location, pitch)
674  planes.append(plr)
675  return schema.FieldResponse(planes, anti_drift_axis, origin, tstart, period, speed)
676 
677 
678 
679 
680 
def rf1dtoschema(rflist, origin=10 *units.cm, speed=1.114 *units.mm/units.us)
Definition: __init__.py:640
T abs(T value)
def group_by(rflist, field)
Definition: __init__.py:162
def wirecell.sigproc.response.schematorf1d (   fr)
Convert response.schema objects to 1D ResponseFunction objects.

Fixme: this has not yet been validated.

Definition at line 620 of file __init__.py.

620 def schematorf1d(fr):
621  '''
622  Convert response.schema objects to 1D ResponseFunction objects.
623 
624  Fixme: this has not yet been validated.
625  '''
626  ret = list()
627  for pr in fr.planes:
628  for path in pr.paths:
629  region = int(round(path.pitchpos/pr.pitch))
630  pos = (pr.wirepos, pr.pitchpos)
631  nsamples = len(path.current)
632  times = (fr.tstart, nsamples*fr.period, nsamples)
633  impact = pathc.pitchpos - region*pr.pitch
634  rf = ResponseFunction(pr.planeid, region, pos, times, path.current, impact)
635  ret.append(rf)
636  return ret
637 
638 
639 
def wirecell.sigproc.response.total_charge (   rf)
Integrate total charge in a current response.

Definition at line 178 of file __init__.py.

178 def total_charge(rf):
179  '''
180  Integrate total charge in a current response.
181  '''
182  dt = (rf.times[1] - rf.times[0])
183  if dt == 0.0:
184  raise ValueError("Corrupt response function for plane %s, region %d" % (rf.plane, rf.region))
185  itot = numpy.sum(rf.response)
186  return dt*itot
187 
def wirecell.sigproc.response.write (   rflist,
  outputfile = "wire-cell-garfield-response.json.bz2" 
)
Write a list of response functions to file.

Definition at line 681 of file __init__.py.

681 def write(rflist, outputfile = "wire-cell-garfield-response.json.bz2"):
682  '''
683  Write a list of response functions to file.
684  '''
685  import json
686  text = json.dumps([rf.asdict for rf in rflist])
687  if outputfile.endswith(".json"):
688  open(outputfile,'w').write(text)
689  return
690  if outputfile.endswith(".json.bz2"):
691  import bz2
692  bz2.BZ2File(outputfile, 'w').write(text)
693  return
694  if outputfile.endswith(".json.gz"):
695  import gzip
696  gzip.open(outputfile, "wb").write(text)
697  return
698  raise ValueError("unknown file format: %s" % outputfile)
699 # fixme: implement read()
700 
int open(const char *, int)
Opens a file descriptor.
def write(rflist, outputfile="wire-cell-garfield-response.json.bz2")
Definition: __init__.py:681

Variable Documentation

wirecell.sigproc.response.electronics = numpy.vectorize(electronics)

Definition at line 64 of file __init__.py.