SimDriftElectrons_module.cc
Go to the documentation of this file.
1 /**
2  * @file SimDriftElectrons_module.cxx
3  *
4  * @brief Transports energy depositions in the LAr TPC to the TPC
5  * channels.
6  *
7  * author:
8  * This module was prepared by William Seligman (me), based on code
9  * that had been in
10  * `LArG4::LArVoxelReadout::DriftIonizationElectrons`. However, though
11  * I wrote the original LArVoxelReadout code, I have no idea who added
12  * DriftIonizationElectrons. I probably will not be able to answer any
13  * questions about how this code works.
14  *
15  * This module acts on sim::SimEnergyDeposit, the single energy
16  * depositions from the detector simulation (LArG4), and simulates the
17  * transport of the ensuing ionization electrons to the readout
18  * channels:
19  *
20  * 1. the number of ionisation electrons is read from the current
21  * `larg4::IonizationAndScintillation` instance
22  * 2. space charge displacement is optionally applied
23  * 3. lifetime correction is applied
24  * 4. charge is split in small electron clusters
25  * 5. each cluster is subject to longitudinal and transverse diffusion
26  * 6. each cluster is assigned to one TPC channel for each wire plane
27  * 7. optionally, charge is forced to stay on the planes; otherwise charge
28  * drifting outside the plane is lost
29  *
30  * For each energy deposition, entries on the appropriate
31  * `sim::SimChannel` are added, with the information of the position
32  * where the energy deposit happened (in global coordinates,
33  * centimeters), the ID of the track in the detector simulation which
34  * produced the deposition, and the quantized time of arrival to the
35  * channel (in global TDC tick units). At most one entry is added for
36  * each electron cluster, but entries from the same energy deposit can
37  * be compacted if falling on the same TDC tick.
38  *
39  * Options
40  * --------
41  *
42  * A few optional behaviours are supported:
43  *
44  * * lead off-plane charge to the planes: regulated by
45  * `RecoverOffPlaneDeposit()`, if charge which reaches a wire plane
46  * is actually off it by less than the chosen margin, it's accounted for by
47  * that plane; by default the margin is 0 and all the charge off the plane
48  * is lost (with a warning)
49  *
50  * Update:
51  * Christoph Alt, September 2018 (christoph.alt@cern.ch)
52  * Break hardcoded charge drift in x to support charge drift in y and z.
53  */
54 
55 // LArSoft includes
62 
63 #include "larcoreobj/SimpleTypesAndConstants/RawTypes.h" // raw::ChannelID_t
68 
69 // Framework includes
75 #include "fhiclcpp/ParameterSet.h"
77 #include "nurandom/RandomUtils/NuRandomService.h"
78 
79 // External libraries
80 #include "CLHEP/Random/RandGauss.h"
81 #include "TMath.h"
82 
83 // C++ includes
84 #include <algorithm> // std::find
85 #include <cmath>
86 #include <map>
87 
88 // stuff from wes
90 
91 namespace detsim {
92 
93  // Base class for creation of raw signals on wires.
95  public:
96  explicit SimDriftElectrons(fhicl::ParameterSet const& pset);
97 
98  // Methods that that are available for a module derived from
99  // art::EDProducer.
100  void produce(art::Event& evt) override;
101  void beginJob() override;
102 
103  private:
104  // The label of the module that created the sim::SimEnergyDeposit
105  // objects (as of Oct-2017, this is probably "largeant").
107 
108  CLHEP::RandGauss fRandGauss;
109 
115 
117  double fLDiff_const;
118  double fTDiff_const;
119  double fRecipDriftVel[3];
120 
122 
123  // double fOffPlaneMargin;
124 
125  // In order to create the associations, for each channel we create
126  // we have to keep track of its index in the output vector, and the
127  // indexes of all the steps that contributed to it.
129  size_t channelIndex;
130  std::vector<size_t> stepList;
131  };
132 
133  // Define type: channel -> sim::SimChannel's bookkeeping.
134  typedef std::map<raw::ChannelID_t, ChannelBookKeeping> ChannelMap_t;
135 
136  // Array of maps of channel data indexed by [cryostat,tpc]
137  std::vector<ChannelMap_t> fChannelMaps;
138  // The above ensemble may be thought of as a 3D array of
139  // ChannelBookKeepings: e.g., SimChannel[cryostat,tpc,channel ID].
140 
141  // Save the number of cryostats, and the number of TPCs within
142  // each cryostat.
143  size_t fNCryostats;
144  std::vector<size_t> fNTPCs;
145 
146  // Per-cluster information.
147  std::vector<double> fLongDiff;
148  std::vector<double> fTransDiff1;
149  std::vector<double> fTransDiff2;
150  std::vector<double> fnElDiff;
151  std::vector<double> fnEnDiff;
152 
153  double fDriftClusterPos[3];
154 
155  art::ServiceHandle<geo::Geometry const> fGeometry; ///< Handle to the Geometry service
156 
157  // IS calculationg
159 
160  }; // class SimDriftElectrons
161 
162  //-------------------------------------------------
164  : art::EDProducer{pset}
165  , fSimModuleLabel{pset.get<art::InputTag>("SimulationLabel")}
166  // create a default random engine; obtain the random seed from
167  // NuRandomService, unless overridden in configuration with key
168  // "Seed"
169  , fRandGauss{art::ServiceHandle<rndm::NuRandomService>{}->createEngine(*this, pset, "Seed")}
170  , fStoreDriftedElectronClusters{pset.get<bool>("StoreDriftedElectronClusters", false)}
171  {
172  produces<std::vector<sim::SimChannel>>();
173  if (fStoreDriftedElectronClusters) { produces<std::vector<sim::SimDriftedElectronCluster>>(); }
174  }
175 
176  //-------------------------------------------------
177  void
179  {
180  // Define the physical constants we'll use.
181 
182  auto const detProp =
184  fElectronLifetime = detProp.ElectronLifetime(); // Electron lifetime as returned by the
185  // DetectorProperties service assumed to be in us;
186  for (int i = 0; i < 3; ++i) {
187  double driftVelocity = detProp.DriftVelocity(detProp.Efield(i),
188  detProp.Temperature()) *
189  1.e-3; // Drift velocity as returned by the DetectorProperties service
190  // assumed to be in cm/us. Multiply by 1.e-3 to convert into
191  // LArSoft standard velocity units, cm/ns;
192 
193  fRecipDriftVel[i] = 1. / driftVelocity;
194  }
195 
196  // To-do: Move the parameters we fetch from "LArG4" to detector
197  // properties.
199  fElectronClusterSize = paramHandle->ElectronClusterSize();
201  fLongitudinalDiffusion = paramHandle->LongitudinalDiffusion(); // cm^2/ns units
202  fTransverseDiffusion = paramHandle->TransverseDiffusion(); // cm^2/ns units
203 
204  MF_LOG_DEBUG("SimDriftElectrons")
205  << " e lifetime (ns): " << fElectronLifetime
206  << "\n Temperature (K): " << detProp.Temperature()
207  << "\n Drift velocity (cm/ns): " << 1. / fRecipDriftVel[0] << " " << 1. / fRecipDriftVel[1]
208  << " " << 1. / fRecipDriftVel[2];
209 
210  // Opposite of lifetime. Convert from us to standard LArSoft time units, ns;
212  fLDiff_const = std::sqrt(2. * fLongitudinalDiffusion);
213  fTDiff_const = std::sqrt(2. * fTransverseDiffusion);
214 
215  // For this detector's geometry, save the number of cryostats and
216  // the number of TPCs within each cryostat.
218  fNTPCs.resize(fNCryostats);
219  for (size_t n = 0; n < fNCryostats; ++n)
220  fNTPCs[n] = fGeometry->NTPC(n);
221  }
222 
223  //-------------------------------------------------
224  void
226  {
227  // Fetch the SimEnergyDeposit objects for this event.
228  typedef art::Handle<std::vector<sim::SimEnergyDeposit>> energyDepositHandle_t;
229  energyDepositHandle_t energyDepositHandle;
230  // If there aren't any energy deposits for this event, don't
231  // panic. It's possible someone is doing a study with events
232  // outside the TPC, or where there are only non-ionizing
233  // particles, or something like that.
234  if (!event.getByLabel(fSimModuleLabel, energyDepositHandle)) return;
235 
236  // Define the container for the SimChannel objects that will be
237  // transferred to the art::Event after the put statement below.
238  std::unique_ptr<std::vector<sim::SimChannel>> channels(new std::vector<sim::SimChannel>);
239  // Container for the SimDriftedElectronCluster objects
240  std::unique_ptr<std::vector<sim::SimDriftedElectronCluster>>
241  SimDriftedElectronClusterCollection(new std::vector<sim::SimDriftedElectronCluster>);
242 
243  // Clear the channel maps from the last event. Remember,
244  // fChannelMaps is an array[cryo][tpc] of maps.
245  size_t cryo = 0;
246  fChannelMaps.resize(fNCryostats);
247  for (auto& cryoData : fChannelMaps) { // each, a vector of maps
248  cryoData.clear();
249  }
250 
251  auto const clockData =
253  auto const& tpcClock = clockData.TPCClock();
254 
255  auto const detProp =
257  // We're going through the input vector by index, rather than by
258  // iterator, because we need the index number to compute the
259  // associations near the end of this method.
260  auto const& energyDeposits = *energyDepositHandle;
261  auto energyDepositsSize = energyDeposits.size();
262 
263  // For each energy deposit in this event
264  for (size_t edIndex = 0; edIndex < energyDepositsSize; ++edIndex) {
265  auto const& energyDeposit = energyDeposits[edIndex];
266 
267  // "xyz" is the position of the energy deposit in world
268  // coordinates. Note that the units of distance in
269  // sim::SimEnergyDeposit are supposed to be cm.
270  auto const mp = energyDeposit.MidPoint();
271  double const xyz[3] = {mp.X(), mp.Y(), mp.Z()};
272 
273  // From the position in world coordinates, determine the
274  // cryostat and tpc. If somehow the step is outside a tpc
275  // (e.g., cosmic rays in rock) just move on to the next one.
276  unsigned int cryostat = 0;
277  try {
278  fGeometry->PositionToCryostat(xyz, cryostat);
279  }
280  catch (cet::exception& e) {
281  mf::LogWarning("SimDriftElectrons") << "step " // << energyDeposit << "\n"
282  << "cannot be found in a cryostat\n"
283  << e;
284  continue;
285  }
286 
287  unsigned int tpc = 0;
288  try {
289  fGeometry->PositionToTPC(xyz, tpc, cryostat);
290  }
291  catch (cet::exception& e) {
292  mf::LogWarning("SimDriftElectrons") << "step " // << energyDeposit << "\n"
293  << "cannot be found in a TPC\n"
294  << e;
295  continue;
296  }
297 
298  const geo::TPCGeo& tpcGeo = fGeometry->TPC(tpc, cryostat);
299 
300  // The drift direction can be either in the positive
301  // or negative direction in any coordinate x, y or z.
302  // Charge drift in ...
303  // +x: tpcGeo.DetectDriftDirection()==1
304  // -x: tpcGeo.DetectDriftDirection()==-1
305  // +y: tpcGeo.DetectDriftDirection()==2
306  // -y tpcGeo.DetectDriftDirection()==-2
307  // +z: tpcGeo.DetectDriftDirection()==3
308  // -z: tpcGeo.DetectDriftDirection()==-3
309 
310  // Define charge drift direction: driftcoordinate (x, y or z) and
311  // driftsign (positive or negative). Also define coordinates perpendicular
312  // to drift direction.
313  int driftcoordinate = std::abs(tpcGeo.DetectDriftDirection()) - 1; // x:0, y:1, z:2
314 
315  int transversecoordinate1 = 0;
316  int transversecoordinate2 = 0;
317  if (driftcoordinate == 0) {
318  transversecoordinate1 = 1;
319  transversecoordinate2 = 2;
320  }
321  else if (driftcoordinate == 1) {
322  transversecoordinate1 = 0;
323  transversecoordinate2 = 2;
324  }
325  else if (driftcoordinate == 2) {
326  transversecoordinate1 = 0;
327  transversecoordinate2 = 1;
328  }
329 
330  if (transversecoordinate1 == transversecoordinate2)
331  continue; // this is the case when driftcoordinate != 0, 1 or 2
332 
333  int driftsign = 0; // 1: +x, +y or +z, -1: -x, -y or -z
334  if (tpcGeo.DetectDriftDirection() > 0)
335  driftsign = 1;
336  else
337  driftsign = -1;
338 
339  // Check for charge deposits behind charge readout planes
340  if (driftsign == 1 && tpcGeo.PlaneLocation(0)[driftcoordinate] < xyz[driftcoordinate])
341  continue;
342  if (driftsign == -1 && tpcGeo.PlaneLocation(0)[driftcoordinate] > xyz[driftcoordinate])
343  continue;
344 
345  /// \todo think about effects of drift between planes.
346  // Center of plane is also returned in cm units
347  double DriftDistance =
348  std::abs(xyz[driftcoordinate] - tpcGeo.PlaneLocation(0)[driftcoordinate]);
349 
350  // Space-charge effect (SCE): Get SCE {x,y,z} offsets for
351  // particular location in TPC
352  geo::Vector_t posOffsets{0.0, 0.0, 0.0};
353  double posOffsetxyz[3] = {0.0, 0.0, 0.0}; // need this array for the driftcoordinate and
354  // transversecoordinates
355  auto const* SCE = lar::providerFrom<spacecharge::SpaceChargeService>();
356  if (SCE->EnableSimSpatialSCE() == true) {
357  posOffsets = SCE->GetPosOffsets(mp);
358  if (larsim::Utils::SCE::out_of_bounds(posOffsets)) {
359  continue;
360  }
361  posOffsetxyz[0] = posOffsets.X();
362  posOffsetxyz[1] = posOffsets.Y();
363  posOffsetxyz[2] = posOffsets.Z();
364  }
365 
366  double avegagetransversePos1 = 0.;
367  double avegagetransversePos2 = 0.;
368 
369  DriftDistance += -1. * posOffsetxyz[driftcoordinate];
370  avegagetransversePos1 = xyz[transversecoordinate1] + posOffsetxyz[transversecoordinate1];
371  avegagetransversePos2 = xyz[transversecoordinate2] + posOffsetxyz[transversecoordinate2];
372 
373  // Space charge distortion could push the energy deposit beyond the wire
374  // plane (see issue #15131). Given that we don't have any subtlety in the
375  // simulation of this region, bringing the deposit exactly on the plane
376  // should be enough for the time being.
377  if (DriftDistance < 0.) DriftDistance = 0.;
378 
379  // Drift time in ns
380  double TDrift = DriftDistance * fRecipDriftVel[0];
381 
382  if (tpcGeo.Nplanes() == 2 &&
383  driftcoordinate == 0) { // special case for ArgoNeuT (Nplanes = 2 and drift direction =
384  // x): plane 0 is the second wire plane
385  TDrift = ((DriftDistance - tpcGeo.PlanePitch(0, 1)) * fRecipDriftVel[0] +
386  tpcGeo.PlanePitch(0, 1) * fRecipDriftVel[1]);
387  }
388 
389  const int nIonizedElectrons = fISAlg.CalcIonAndScint(detProp, energyDeposit).numElectrons;
390  const double lifetimecorrection = TMath::Exp(TDrift / fLifetimeCorr_const);
391  const double energy = energyDeposit.Energy();
392 
393  // if we have no electrons (too small energy or too large recombination)
394  // we are done already here
395  if (nIonizedElectrons <= 0) {
396  MF_LOG_DEBUG("SimDriftElectrons")
397  << "step " // << energyDeposit << "\n"
398  << "No electrons drifted to readout, " << energy << " MeV lost.";
399  continue;
400  }
401 
402  // includes the effect of lifetime: lifetimecorrection = exp[-tdrift/tau]
403  const double nElectrons = nIonizedElectrons * lifetimecorrection;
404 
405  // Longitudinal & transverse diffusion sigma (cm)
406  double SqrtT = std::sqrt(TDrift);
407  double LDiffSig = SqrtT * fLDiff_const;
408  double TDiffSig = SqrtT * fTDiff_const;
409  double electronclsize = fElectronClusterSize;
410 
411  // Number of electron clusters.
412  int nClus = (int)std::ceil(nElectrons / electronclsize);
413  if (nClus < fMinNumberOfElCluster) {
414  electronclsize = nElectrons / fMinNumberOfElCluster;
415  if (electronclsize < 1.0) { electronclsize = 1.0; }
416  nClus = (int)std::ceil(nElectrons / electronclsize);
417  }
418 
419  // Empty and resize the electron-cluster vectors.
420  fLongDiff.clear();
421  fTransDiff1.clear();
422  fTransDiff2.clear();
423  fnElDiff.clear();
424  fnEnDiff.clear();
425  fLongDiff.resize(nClus);
426  fTransDiff1.resize(nClus);
427  fTransDiff2.resize(nClus);
428  fnElDiff.resize(nClus, electronclsize);
429  fnEnDiff.resize(nClus);
430 
431  // fix the number of electrons in the last cluster, that has a smaller size
432  fnElDiff.back() = nElectrons - (nClus - 1) * electronclsize;
433 
434  for (size_t xx = 0; xx < fnElDiff.size(); ++xx) {
435  if (nElectrons > 0)
436  fnEnDiff[xx] = energy / nElectrons * fnElDiff[xx];
437  else
438  fnEnDiff[xx] = 0.;
439  }
440 
441  // Smear drift times by longitudinal diffusion
442  if (LDiffSig > 0.0)
443  fRandGauss.fireArray(nClus, &fLongDiff[0], 0., LDiffSig);
444  else
445  fLongDiff.assign(nClus, 0.0);
446 
447  if (TDiffSig > 0.0) {
448  // Smear the coordinates in plane perpendicular to drift direction by the transverse diffusion
449  fRandGauss.fireArray(nClus, &fTransDiff1[0], avegagetransversePos1, TDiffSig);
450  fRandGauss.fireArray(nClus, &fTransDiff2[0], avegagetransversePos2, TDiffSig);
451  }
452  else {
453  fTransDiff1.assign(nClus, avegagetransversePos1);
454  fTransDiff2.assign(nClus, avegagetransversePos2);
455  }
456 
457  // make a collection of electrons for each plane
458  for (size_t p = 0; p < tpcGeo.Nplanes(); ++p) {
459 
460  fDriftClusterPos[driftcoordinate] = tpcGeo.PlaneLocation(p)[driftcoordinate];
461 
462  // Drift nClus electron clusters to the induction plane
463  for (int k = 0; k < nClus; ++k) {
464 
465  // Correct drift time for longitudinal diffusion and plane
466  double TDiff = TDrift + fLongDiff[k] * fRecipDriftVel[0];
467 
468  // Take into account different Efields between planes
469  // Also take into account special case for ArgoNeuT (Nplanes = 2 and
470  // drift direction = x): plane 0 is the second wire plane
471  for (size_t ip = 0; ip < p; ++ip) {
472  TDiff +=
473  tpcGeo.PlanePitch(ip+1, ip) *
474  fRecipDriftVel[(tpcGeo.Nplanes() == 2 && driftcoordinate == 0) ? ip + 2 : ip + 1];
475  }
476 
477  fDriftClusterPos[transversecoordinate1] = fTransDiff1[k];
478  fDriftClusterPos[transversecoordinate2] = fTransDiff2[k];
479 
480  /// \todo think about effects of drift between planes
481 
482  // grab the nearest channel to the fDriftClusterPos position
483  try {
485  fGeometry->NearestChannel(fDriftClusterPos, p, tpc, cryostat);
486 
487  /// \todo check on what happens if we allow the tdc value to be
488  /// \todo beyond the end of the expected number of ticks
489  // Add potential decay/capture/etc delay effect, simTime.
490  auto const simTime = energyDeposit.Time();
491  unsigned int tdc = tpcClock.Ticks(clockData.G4ToElecTime(TDiff + simTime));
492 
493  // Find whether we already have this channel in our map.
494  ChannelMap_t& channelDataMap = fChannelMaps[cryostat];
495  auto search = channelDataMap.find(channel);
496 
497  // We will find (or create) the pointer to a
498  // sim::SimChannel.
499  size_t channelIndex = 0;
500 
501  // Have we created the sim::SimChannel corresponding to
502  // channel ID?
503  if (search == channelDataMap.end()) {
504  // We haven't. Initialize the bookkeeping information
505  // for this channel.
506  ChannelBookKeeping bookKeeping;
507 
508  // Add a new channel to the end of the list we'll
509  // write out after we've processed this event.
510  bookKeeping.channelIndex = channels->size();
511  channels->emplace_back(channel);
512  channelIndex = bookKeeping.channelIndex;
513 
514  // Initialize a vector with the index of the step that
515  // created this channel.
516  bookKeeping.stepList.push_back(edIndex);
517 
518  // Save the bookkeeping information for this channel.
519  channelDataMap[channel] = bookKeeping;
520  }
521  else {
522  // We've created this SimChannel for a previous energy
523  // deposit. Get its address.
524 
525  auto& bookKeeping = search->second;
526  channelIndex = bookKeeping.channelIndex;
527 
528  // Has this step contributed to this channel before?
529  auto& stepList = bookKeeping.stepList;
530  auto stepSearch = std::find(stepList.begin(), stepList.end(), edIndex);
531  if (stepSearch == stepList.end()) {
532  // No, so add this step's index to the list.
533  stepList.push_back(edIndex);
534  }
535  }
536 
537  sim::SimChannel* channelPtr = &(channels->at(channelIndex));
538 
539  // Add the electron clusters and energy to the
540  // sim::SimChannel
541  channelPtr->AddIonizationElectrons(
542  energyDeposit.TrackID(), tdc, fnElDiff[k], xyz, fnEnDiff[k]);
543 
545  SimDriftedElectronClusterCollection->emplace_back(
546  fnElDiff[k],
547  TDiff + simTime, // timing
548  geo::Point_t{mp.X(), mp.Y(), mp.Z()}, // mean position of the deposited energy
549  geo::Point_t{fDriftClusterPos[0],
550  fDriftClusterPos[1],
551  fDriftClusterPos[2]}, // final position of the drifted cluster
552  geo::Point_t{
553  LDiffSig, TDiffSig, TDiffSig}, // Longitudinal (X) and transverse (Y,Z) diffusion
554  fnEnDiff[k], // deposited energy that originated this cluster
555  energyDeposit.TrackID());
556  }
557  catch (cet::exception& e) {
558  mf::LogDebug("SimDriftElectrons")
559  << "unable to drift electrons from point (" << xyz[0] << "," << xyz[1] << ","
560  << xyz[2] << ") with exception " << e;
561  } // end try to determine channel
562  } // end loop over clusters
563  } // end loop over planes
564  } // for each sim::SimEnergyDeposit
565 
566  // Write the sim::SimChannel collection.
567  event.put(std::move(channels));
568  if (fStoreDriftedElectronClusters) event.put(std::move(SimDriftedElectronClusterCollection));
569  }
570 
571 } // namespace detsim
572 
Store parameters for running LArG4.
double PlanePitch(unsigned int p1=0, unsigned int p2=1) const
Definition: TPCGeo.cxx:388
Energy deposited on a readout channel by simulated tracks.
Definition: SimChannel.h:140
contains objects relating to SimDriftedElectronCluster
CryostatGeo const & PositionToCryostat(geo::Point_t const &point) const
Returns the cryostat at specified location.
bool out_of_bounds(geo::Vector_t const &offset)
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:165
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
Geometry information for a single TPC.
Definition: TPCGeo.h:38
Detector simulation of raw signals on wires.
ISCalcData CalcIonAndScint(detinfo::DetectorPropertiesData const &detProp, sim::SimEnergyDeposit const &edep) override
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:164
uint8_t channel
Definition: CRTFragment.hh:201
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
art::ServiceHandle< geo::Geometry const > fGeometry
Handle to the Geometry service.
art framework interface to geometry description
geo::TPCGeo const & PositionToTPC(geo::Point_t const &point) const
Returns the TPC at specified location.
double numElectrons
Definition: ISCalc.h:22
T abs(T value)
double TransverseDiffusion() const
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Definition: DataViewImpl.h:633
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
Utility function for testing if Space Charge offsets are out of bounds.
double ElectronClusterSize() const
std::void_t< T > n
def move(depos, offset)
Definition: depos.py:107
p
Definition: test.py:223
void produce(art::Event &evt) override
Definition: search.py:1
std::vector< ChannelMap_t > fChannelMaps
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
void AddIonizationElectrons(TrackID_t trackID, TDC_t tdc, double numberElectrons, double const *xyz, double energy)
Add ionization electrons and energy to this channel.
Definition: SimChannel.cxx:54
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:184
std::map< raw::ChannelID_t, ChannelBookKeeping > ChannelMap_t
int MinNumberOfElCluster() const
short int DetectDriftDirection() const
Returns the expected drift direction based on geometry.
Definition: TPCGeo.cxx:157
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
contains information for a single step in the detector simulation
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
#define MF_LOG_DEBUG(id)
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
double LongitudinalDiffusion() const
TCEvent evt
Definition: DataStructs.cxx:7
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
raw::ChannelID_t NearestChannel(geo::Point_t const &worldLoc, geo::PlaneID const &planeid) const
Returns the ID of the channel nearest to the specified position.
const double * PlaneLocation(unsigned int p) const
Definition: TPCGeo.cxx:382
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
SimDriftElectrons(fhicl::ParameterSet const &pset)
Event finding and building.