All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
LArVoxelReadout.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file LArVoxelReadout.cxx
3 /// \brief A Geant4 sensitive detector that accumulates voxel information.
4 ///
5 /// \author seligman@nevis.columbia.edu
6 ////////////////////////////////////////////////////////////////////////
7 
8 // C/C++ standard library
9 #include <cassert>
10 #include <cmath> // std::ceil()
11 #include <cstdio> // std::sscanf()
12 #include <map>
13 #include <string>
14 #include <utility> // std::move()
15 
16 // GEANT
17 #include "Geant4/G4Step.hh"
18 #include "Geant4/G4StepPoint.hh"
19 #include "Geant4/G4ThreeVector.hh"
20 #include "Geant4/G4VPhysicalVolume.hh"
21 
22 // framework libraries
23 #include "cetlib_except/exception.h"
24 #include "messagefacility/MessageLogger/MessageLogger.h"
25 
26 // LArSoft code
28 #include "larcoreobj/SimpleTypesAndConstants/RawTypes.h" // raw::ChannelID_t
40 
41 // CLHEP
42 #include "CLHEP/Random/RandGauss.h"
43 
44 namespace larg4 {
45 
46  //---------------------------------------------------------------------------------------
47  // Constructor. Note that we force the name of this sensitive
48  // detector to be the value expected by LArVoxelListAction.
49  LArVoxelReadout::LArVoxelReadout(std::string const& name) : G4VSensitiveDetector(name)
50  {
51  // Initialize values for the electron-cluster calculation.
53 
54  // the standard name contains cryostat and TPC;
55  // if we don't find it, we will detect the TPC at each Geant hit
56  unsigned int cryostat, tpc;
57  if (std::sscanf(name.c_str(), "%*19s%1u%*4s%u", &cryostat, &tpc) == 2)
58  SetSingleTPC(cryostat, tpc);
59  else
61 
62  } // LArVoxelReadout::LArVoxelReadout()
63 
64  //---------------------------------------------------------------------------------------
65  // Constructor. Note that we force the name of this sensitive
66  // detector to be the value expected by LArVoxelListAction.
67  LArVoxelReadout::LArVoxelReadout(std::string const& name, unsigned int cryostat, unsigned int tpc)
68  : LArVoxelReadout(name)
69  {
70  SetSingleTPC(cryostat, tpc);
71  }
72 
73  //---------------------------------------------------------------------------------------
74  void
75  LArVoxelReadout::Setup(Setup_t const& setupData)
76  {
78  SetRandomEngines(setupData.propGen);
79  }
80 
81  //---------------------------------------------------------------------------------------
82  void
83  LArVoxelReadout::SetSingleTPC(unsigned int cryostat, unsigned int tpc)
84  {
85  bSingleTPC = true;
86  fCstat = cryostat;
87  fTPC = tpc;
88  MF_LOG_DEBUG("LArVoxelReadout") << GetName() << "covers C=" << fCstat << " T=" << fTPC;
89  }
90 
91  void
93  {
94  bSingleTPC = false;
95  fCstat = 0;
96  fTPC = 0;
97  MF_LOG_DEBUG("LArVoxelReadout") << GetName() << " autodetects TPC";
98  }
99 
100  //---------------------------------------------------------------------------------------
101  // Called at the start of each event.
102  void
103  LArVoxelReadout::Initialize(G4HCofThisEvent*)
104  {
105  assert(fClockData != nullptr &&
106  "You must use set the clock data pointer at the beginning "
107  "of each module's event-level call. This might be done through the "
108  "LArVoxelReadoutGeometry::Sentry class.");
109  assert(fDetProp != nullptr &&
110  "You must use set the detector-properties data pointer at the beginning "
111  "of each module's event-level call. This might be done through the "
112  "LArVoxelReadoutGeometry::Sentry class.");
113 
115  for (int i = 0; i < 3; ++i)
116  fDriftVelocity[i] =
118 
119  fElectronClusterSize = fLgpHandle->ElectronClusterSize();
120  fMinNumberOfElCluster = fLgpHandle->MinNumberOfElCluster();
121  fLongitudinalDiffusion = fLgpHandle->LongitudinalDiffusion();
122  fTransverseDiffusion = fLgpHandle->TransverseDiffusion();
123  fDontDriftThem = fLgpHandle->DisableWireplanes();
124  fSkipWireSignalInTPCs = fLgpHandle->SkipWireSignalInTPCs();
125 
126  MF_LOG_DEBUG("LArVoxelReadout")
127  << " e lifetime: " << fElectronLifetime << "\n Temperature: " << fDetProp->Temperature()
128  << "\n Drift velocity: " << fDriftVelocity[0] << " " << fDriftVelocity[1] << " "
129  << fDriftVelocity[2];
130 
131  fDontDriftThem = (fDontDriftThem || fLgpHandle->NoElectronPropagation());
132 
133  fNSteps = 0;
134  }
135 
136  //---------------------------------------------------------------------------------------
137  // Called at the end of each event.
138  void
139  LArVoxelReadout::EndOfEvent(G4HCofThisEvent*)
140  {
141  MF_LOG_DEBUG("LArVoxelReadout") << "Total number of steps was " << fNSteps << std::endl;
142  }
143 
144  //---------------------------------------------------------------------------------------
145  void
147  {}
148 
149  //--------------------------------------------------------------------------------------
150  void
152  {
153  fChannelMaps.resize(fGeoHandle->Ncryostats());
154  size_t cryo = 0;
155  for (auto& cryoData : fChannelMaps) { // each, a vector of maps
156  cryoData.resize(fGeoHandle->NTPC(cryo++));
157  for (auto& channelsMap : cryoData)
158  channelsMap.clear(); // each, a map
159  } // for cryostats
160  } // LArVoxelReadout::ClearSimChannels()
161 
164  {
165  if (bSingleTPC) return GetSimChannelMap(fCstat, fTPC);
166  throw cet::exception("LArVoxelReadout") << "TPC not specified";
167  }
168 
171  {
172  if (bSingleTPC) return GetSimChannelMap(fCstat, fTPC);
173  throw cet::exception("LArVoxelReadout") << "TPC not specified";
174  }
175 
177  LArVoxelReadout::GetSimChannelMap(unsigned short cryo, unsigned short tpc) const
178  {
179  return fChannelMaps.at(cryo).at(tpc);
180  }
181 
183  LArVoxelReadout::GetSimChannelMap(unsigned short cryo, unsigned short tpc)
184  {
185  return fChannelMaps.at(cryo).at(tpc);
186  }
187 
188  std::vector<sim::SimChannel>
190  {
191  if (bSingleTPC) return GetSimChannels(fCstat, fTPC);
192  throw cet::exception("LArVoxelReadout") << "TPC not specified";
193  }
194 
195  std::vector<sim::SimChannel>
196  LArVoxelReadout::GetSimChannels(unsigned short cryo, unsigned short tpc) const
197  {
198  std::vector<sim::SimChannel> channels;
199  const ChannelMap_t& chmap = fChannelMaps.at(cryo).at(tpc);
200  channels.reserve(chmap.size());
201  for (const auto& chpair : chmap)
202  channels.push_back(chpair.second);
203  return channels;
204  }
205 
206  //---------------------------------------------------------------------------------------
207  // Called for each step.
208  G4bool
209  LArVoxelReadout::ProcessHits(G4Step* step, G4TouchableHistory* pHistory)
210  {
211  // All work done for the "parallel world" "box of voxels" in
212  // LArVoxelReadoutGeometry makes this a fairly simple routine.
213  // First, the usual check for non-zero energy:
214 
215  // Only process the hit if the step is inside the active volume and
216  // it has deposited energy. The hit being inside the active volume
217  // is virtually sure to happen because the LArVoxelReadoutGeometry
218  // that this class makes use of only has voxels for inside the TPC.
219 
220  // The step can be no bigger than the size of the voxel,
221  // because of the geometry set up in LArVoxelGeometry and the
222  // transportation set up in PhysicsList. Find the mid-point
223  // of the step.
224 
225  if (step->GetTotalEnergyDeposit() > 0) {
226 
227  // Make sure we have the IonizationAndScintillation singleton
228  // reset to this step
230  fNSteps++;
231  if (!fDontDriftThem) {
232 
233  G4ThreeVector midPoint =
234  0.5 * (step->GetPreStepPoint()->GetPosition() + step->GetPostStepPoint()->GetPosition());
235  double g4time = step->GetPreStepPoint()->GetGlobalTime();
236 
237  // Find the Geant4 track ID for the particle responsible for depositing the
238  // energy. if we are only storing primary EM shower particles, and this energy
239  // is from a secondary etc EM shower particle, the ID returned is the primary
240  const int trackID = ParticleListAction::GetCurrentTrackID();
241  // For all particles but shower daughters, origTrackID is the same as trackID.
242  // For shower daughters it contains their original trackID instead of the
243  // shower primary's trackID.
244  const int origTrackID = ParticleListAction::GetCurrentOrigTrackID();
245 
246  // Find out which TPC we are in.
247  // If this readout object covers just one, we already know it.
248  // Otherwise, we have to ask Geant where we are.
249  unsigned short int cryostat = 0, tpc = 0;
250  if (bSingleTPC) {
251  cryostat = fCstat;
252  tpc = fTPC;
253  }
254  else {
255  // detect the TPC we are in
256  const G4VTouchable* pTouchable = step->GetPreStepPoint()->GetTouchable();
257  if (!pTouchable) {
258  throw cet::exception("LArG4") << "Untouchable step in LArVoxelReadout::ProcessHits()";
259  }
260 
261  // one of the ancestors of the touched volume is supposed to be
262  // actually a G4PVPlacementInTPC that knows which TPC it covers;
263  // currently, it's the 4th in the ladder:
264  // [0] voxel [1] voxel tower [2] voxel plane [3] the full box;
265  G4int depth = 0;
266  while (depth < pTouchable->GetHistoryDepth()) {
267  const G4PVPlacementInTPC* pPVinTPC =
268  dynamic_cast<const G4PVPlacementInTPC*>(pTouchable->GetVolume(depth++));
269  if (!pPVinTPC) continue;
270  cryostat = pPVinTPC->ID.Cryostat;
271  tpc = pPVinTPC->ID.TPC;
272  if (Has(fSkipWireSignalInTPCs, tpc)) { return true; }
273  break;
274  } // while
275  if (depth < pTouchable->GetHistoryDepth()) {
276  // this is a fundamental error where the step does not happen in
277  // any TPC; this should not happen in the readout geometry!
278  throw cet::exception("LArG4") << "No TPC ID found in LArVoxelReadout::ProcessHits()";
279  } // if
280  MF_LOG_DEBUG("LArVoxelReadoutHit") << " hit in C=" << cryostat << " T=" << tpc;
281  } // if more than one TPC
282 
283  // Note that if there is no particle ID for this energy deposit, the
284  // trackID will be sim::NoParticleId.
285 
286  DriftIonizationElectrons(*fClockData, midPoint, g4time, trackID, cryostat, tpc, origTrackID);
287  } // end we are drifting
288  } // end there is non-zero energy deposition
289 
290  return true;
291  }
292 
293  //----------------------------------------------------------------------------
294  void
295  LArVoxelReadout::SetRandomEngines(CLHEP::HepRandomEngine* pPropGen)
296  {
297  assert(pPropGen); // random engine must be present
298  fPropGen = pPropGen;
299  }
300 
301  //----------------------------------------------------------------------------
304  {
305  //
306  // translate the landing position on the two frame coordinates
307  // ("width" and "depth")
308  //
309  auto const landingPos = plane.PointWidthDepthProjection(pos);
310 
311  //
312  // compute the distance of the landing position on the two frame
313  // coordinates ("width" and "depth");
314  // keep the point within 10 micrometers (0.001 cm) from the border
315  //
316  auto const offPlane = plane.DeltaFromActivePlane(landingPos, 0.001);
317 
318  //
319  // if both the distances are below the margin, move the point to
320  // the border
321  //
322 
323  // nothing to recover: landing is inside
324  if ((offPlane.X() == 0.0) && (offPlane.Y() == 0.0)) return pos;
325 
326  // won't recover: too far
327  if ((std::abs(offPlane.X()) > fOffPlaneMargin) || (std::abs(offPlane.Y()) > fOffPlaneMargin))
328  return pos;
329 
330  // we didn't fully decompose because it might be unnecessary;
331  // now we need the full thing
332  auto const distance = plane.DistanceFromPlane(pos);
333 
334  return plane.ComposePoint<geo::Point_t>(distance, landingPos + offPlane);
335  } // LArVoxelReadout::RecoverOffPlaneDeposit()
336 
337  //----------------------------------------------------------------------------
338  // energy is passed in with units of MeV, dx has units of cm
339  void
341  G4ThreeVector stepMidPoint,
342  const double simTime,
343  int trackID,
344  unsigned short int cryostat,
345  unsigned short int tpc,
346  int origTrackID)
347  {
348  auto const tpcClock = clockData.TPCClock();
349 
350  // this must be always true, unless caller has been sloppy
351  assert(fPropGen); // No propagation random generator provided?!
352 
353  CLHEP::RandGauss PropRand(*fPropGen);
354 
355  // This routine gets called frequently, once per every particle
356  // traveling through every voxel. Use whatever tricks we can to
357  // increase its execution speed.
358 
359  static double LifetimeCorr_const = -1000. * fElectronLifetime;
360  static double LDiff_const = std::sqrt(2. * fLongitudinalDiffusion);
361  static double TDiff_const = std::sqrt(2. * fTransverseDiffusion);
362  static double RecipDriftVel[3] = {
363  1. / fDriftVelocity[0], 1. / fDriftVelocity[1], 1. / fDriftVelocity[2]};
364 
365  struct Deposit_t {
366  double energy = 0.;
367  double electrons = 0.;
368 
369  void
370  add(double more_energy, double more_electrons)
371  {
372  energy += more_energy;
373  electrons += more_electrons;
374  }
375  }; // Deposit_t
376 
377  // Map of electrons to store - catalogued by map[channel][tdc]
378  std::map<raw::ChannelID_t, std::map<unsigned int, Deposit_t>> DepositsToStore;
379 
380  double xyz1[3] = {0.};
381 
382  double const xyz[3] = {
383  stepMidPoint.x() / CLHEP::cm, stepMidPoint.y() / CLHEP::cm, stepMidPoint.z() / CLHEP::cm};
384 
385  // Already know which TPC we're in because we have been told
386 
387  try {
388  const geo::TPCGeo& tpcg = fGeoHandle->TPC(tpc, cryostat);
389 
390  // X drift distance - the drift direction can be either in
391  // the positive or negative direction, so use std::abs
392 
393  /// \todo think about effects of drift between planes
394  double XDrift = std::abs(stepMidPoint.x() / CLHEP::cm - tpcg.PlaneLocation(0)[0]);
395  //std::cout<<tpcg.DriftDirection()<<std::endl;
396  if (tpcg.DriftDirection() == geo::kNegX)
397  XDrift = stepMidPoint.x() / CLHEP::cm - tpcg.PlaneLocation(0)[0];
398  else if (tpcg.DriftDirection() == geo::kPosX)
399  XDrift = tpcg.PlaneLocation(0)[0] - stepMidPoint.x() / CLHEP::cm;
400 
401  if (XDrift < 0.) return;
402 
403  // Get SCE {x,y,z} offsets for particular location in TPC
404  geo::Vector_t posOffsets;
405  auto const* SCE = lar::providerFrom<spacecharge::SpaceChargeService>();
406  if (SCE->EnableSimSpatialSCE() == true) {
407  posOffsets = SCE->GetPosOffsets({xyz[0], xyz[1], xyz[2]});
408  if (larsim::Utils::SCE::out_of_bounds(posOffsets)) {
409  return;
410  }
411  }
412  posOffsets.SetX(-posOffsets.X());
413 
414  // Drift time (nano-sec)
415  double TDrift;
416  XDrift += posOffsets.X();
417 
418  // Space charge distortion could push the energy deposit beyond the wire
419  // plane (see issue #15131). Given that we don't have any subtlety in the
420  // simulation of this region, bringing the deposit exactly on the plane
421  // should be enough for the time being.
422  if (XDrift < 0.) XDrift = 0.;
423 
424  TDrift = XDrift * RecipDriftVel[0];
425  if (tpcg.Nplanes() == 2) { // special case for ArgoNeuT (plane 0 is the second wire plane)
426  TDrift = ((XDrift - tpcg.PlanePitch(0, 1)) * RecipDriftVel[0] +
427  tpcg.PlanePitch(0, 1) * RecipDriftVel[1]);
428  }
429 
430  const double lifetimecorrection = TMath::Exp(TDrift / LifetimeCorr_const);
431  const int nIonizedElectrons =
434 
435  // if we have no electrons (too small energy or too large recombination)
436  // we are done already here
437  if (nIonizedElectrons <= 0) {
438  MF_LOG_DEBUG("LArVoxelReadout")
439  << "No electrons drifted to readout, " << energy << " MeV lost.";
440  return;
441  }
442  // includes the effect of lifetime
443  const double nElectrons = nIonizedElectrons * lifetimecorrection;
444 
445  // Longitudinal & transverse diffusion sigma (cm)
446  double SqrtT = std::sqrt(TDrift);
447  double LDiffSig = SqrtT * LDiff_const;
448  double TDiffSig = SqrtT * TDiff_const;
449  double electronclsize = fElectronClusterSize;
450 
451  int nClus = (int)std::ceil(nElectrons / electronclsize);
452  if (nClus < fMinNumberOfElCluster) {
453  electronclsize = nElectrons / fMinNumberOfElCluster;
454  if (electronclsize < 1.0) { electronclsize = 1.0; }
455  nClus = (int)std::ceil(nElectrons / electronclsize);
456  }
457 
458  // Compute arrays of values as quickly as possible.
459  std::vector<double> XDiff(nClus);
460  std::vector<double> YDiff(nClus);
461  std::vector<double> ZDiff(nClus);
462  std::vector<double> nElDiff(nClus, electronclsize);
463  std::vector<double> nEnDiff(nClus);
464 
465  // fix the number of electrons in the last cluster, that has smaller size
466  nElDiff.back() = nElectrons - (nClus - 1) * electronclsize;
467 
468  for (size_t xx = 0; xx < nElDiff.size(); ++xx) {
469  if (nElectrons > 0)
470  nEnDiff[xx] = energy / nElectrons * nElDiff[xx];
471  else
472  nEnDiff[xx] = 0.;
473  }
474 
475  double const avegageYtransversePos = (stepMidPoint.y() / CLHEP::cm) + posOffsets.Y();
476  double const avegageZtransversePos = (stepMidPoint.z() / CLHEP::cm) + posOffsets.Z();
477 
478  // Smear drift times by x position and drift time
479  if (LDiffSig > 0.0)
480  PropRand.fireArray(nClus, &XDiff[0], 0., LDiffSig);
481  else
482  XDiff.assign(nClus, 0.0);
483 
484  if (TDiffSig > 0.0) {
485  // Smear the Y,Z position by the transverse diffusion
486  PropRand.fireArray(nClus, &YDiff[0], avegageYtransversePos, TDiffSig);
487  PropRand.fireArray(nClus, &ZDiff[0], avegageZtransversePos, TDiffSig);
488  }
489  else {
490  YDiff.assign(nClus, avegageYtransversePos);
491  ZDiff.assign(nClus, avegageZtransversePos);
492  }
493 
494  // make a collection of electrons for each plane
495  for (size_t p = 0; p < tpcg.Nplanes(); ++p) {
496 
497  geo::PlaneGeo const& plane = tpcg.Plane(p);
498 
499  double Plane0Pitch = tpcg.Plane0Pitch(p);
500 
501  // "-" sign is because Plane0Pitch output is positive. Andrzej
502  xyz1[0] = tpcg.PlaneLocation(0)[0] - Plane0Pitch;
503 
504  // Drift nClus electron clusters to the induction plane
505  for (int k = 0; k < nClus; ++k) {
506  // Correct drift time for longitudinal diffusion and plane
507  double TDiff = TDrift + XDiff[k] * RecipDriftVel[0];
508  // Take into account different Efields between planes
509  // Also take into account special case for ArgoNeuT where Nplanes = 2.
510  for (size_t ip = 0; ip < p; ++ip) {
511  TDiff +=
512  tpcg.PlanePitch(ip, ip + 1) * RecipDriftVel[tpcg.Nplanes() == 3 ? ip + 1 : ip + 2];
513  }
514  xyz1[1] = YDiff[k];
515  xyz1[2] = ZDiff[k];
516 
517  /// \todo think about effects of drift between planes
518 
519  // grab the nearest channel to the xyz1 position
520  try {
521  if (fOffPlaneMargin != 0) {
522  // get the effective position where to consider the charge landed;
523  //
524  // Some optimisations are possible; in particular, this method
525  // could be extended to inform us if the point was too far.
526  // Currently, if that is the case the code will proceed, find the
527  // point is off plane, emit a warning and skip the deposition.
528  //
529  auto const landingPos = RecoverOffPlaneDeposit({xyz1[0], xyz1[1], xyz1[2]}, plane);
530  xyz1[0] = landingPos.X();
531  xyz1[1] = landingPos.Y();
532  xyz1[2] = landingPos.Z();
533 
534  } // if charge lands off plane
535  uint32_t channel = fGeoHandle->NearestChannel(xyz1, p, tpc, cryostat);
536 
537  /// \todo check on what happens if we allow the tdc value to be
538  /// \todo beyond the end of the expected number of ticks
539  // Add potential decay/capture/etc delay effect, simTime.
540  unsigned int tdc = tpcClock.Ticks(clockData.G4ToElecTime(TDiff + simTime));
541 
542  // Add electrons produced by each cluster to the map
543  DepositsToStore[channel][tdc].add(nEnDiff[k], nElDiff[k]);
544  }
545  catch (cet::exception& e) {
546  MF_LOG_DEBUG("LArVoxelReadout")
547  << "unable to drift electrons from point (" << xyz[0] << "," << xyz[1] << ","
548  << xyz[2] << ") with exception " << e;
549  }
550  } // end loop over clusters
551  } // end loop over planes
552 
553  // Now store them in SimChannels
554  ChannelMap_t& ChannelDataMap = fChannelMaps[cryostat][tpc];
555 
556  // browse deposited data on each channel: (channel; deposit data in time)
557  for (auto const& deposit_per_channel : DepositsToStore) {
558 
559  raw::ChannelID_t channel = deposit_per_channel.first;
560 
561  // find whether we already have this channel
562  auto iChannelData = ChannelDataMap.find(channel);
563 
564  // channelData is the SimChannel these deposits are going to be added to
565  // If there is such a channel already, use it (first beanch).
566  // If it's a new channel, the inner assignment creates a new SimChannel
567  // in the map, and we save its reference in channelData
568  sim::SimChannel& channelData = (iChannelData == ChannelDataMap.end()) ?
569  (ChannelDataMap[channel] = sim::SimChannel(channel)) :
570  iChannelData->second;
571 
572  // go through all deposits, one for each TDC: (TDC, deposit data)
573  for (auto const& deposit_per_tdc : deposit_per_channel.second) {
574  channelData.AddIonizationElectrons(trackID,
575  deposit_per_tdc.first,
576  deposit_per_tdc.second.electrons,
577  xyz,
578  deposit_per_tdc.second.energy,
579  origTrackID);
580 
581  } // for deposit on TDCs
582  } // for deposit on channels
583 
584  } // end try intended to catch points where TPC can't be found
585  catch (cet::exception& e) {
586  MF_LOG_DEBUG("LArVoxelReadout") << "step cannot be found in a TPC\n" << e;
587  }
588 
589  return;
590  }
591 
592  //---------------------------------------------------------------------------------------
593  // Never used but still have to be defined for G4
594  void
596  {}
597  void
599  {}
600 
601 } // namespace larg4
CLHEP::HepRandomEngine * propGen
Random engine for charge propagation.
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
unsigned int fTPC
which TPC this LArVoxelReadout corresponds to
double PlanePitch(unsigned int p1=0, unsigned int p2=1) const
Definition: TPCGeo.cxx:388
Utilities related to art service access.
Collection of what it takes to set a LArVoxelReadout up.
Energy deposited on a readout channel by simulated tracks.
Definition: SimChannel.h:145
A G4PVPlacement with an additional identificator.
art::ServiceHandle< sim::LArG4Parameters const > fLgpHandle
Handle to the LArG4 parameters service.
ElecClock const & TPCClock() const noexcept
Borrow a const TPC clock with time set to Trigger time [us].
bool out_of_bounds(geo::Vector_t const &offset)
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:165
art::ServiceHandle< geo::Geometry const > fGeoHandle
Handle to the Geometry service.
pdgs p
Definition: selectors.fcl:22
Geometry information for a single TPC.
Definition: TPCGeo.h:38
double Temperature() const
In kelvin.
const ChannelMap_t & GetSimChannelMap() const
Returns the accumulated channel -&gt; SimChannel map for the single TPC.
LArVoxelReadout(std::string const &name)
Constructor. Can detect which TPC to cover by the name.
Point ComposePoint(WireDecomposedVector_t const &decomp) const
Returns the 3D point from composition of projection and distance.
Definition: PlaneGeo.h:1024
void Setup(Setup_t const &setupData)
Reads all the configuration elements from setupData
WidthDepthProjection_t PointWidthDepthProjection(geo::Point_t const &point) const
Returns the projection of the specified point on the plane.
Definition: PlaneGeo.h:1107
void SetRandomEngines(CLHEP::HepRandomEngine *pPropGen)
Sets the random generators to be used.
detinfo::DetectorClocksData const * fClockData
Drift towards negative X values.
Definition: geo_types.h:162
pure virtual base interface for detector clocks
double Efield(unsigned int planegap=0) const
kV/cm
bool bSingleTPC
true if this readout is associated with a single TPC
ID_t ID
Physical Volume identificator.
geo::Point_t RecoverOffPlaneDeposit(geo::Point_t const &pos, geo::PlaneGeo const &plane) const
Returns the point on the specified plane closest to position.
T abs(T value)
void SetSingleTPC(unsigned int cryostat, unsigned int tpc)
Associates this readout to one specific TPC.
std::map< unsigned int, sim::SimChannel > ChannelMap_t
Type of map channel -&gt; sim::SimChannel.
Use Geant4&#39;s user &quot;hooks&quot; to maintain a list of particles generated by Geant4.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
std::vector< unsigned short int > fSkipWireSignalInTPCs
void DriftIonizationElectrons(detinfo::DetectorClocksData const &clockData, G4ThreeVector stepMidPoint, const double simTime, int trackID, unsigned short int cryostat, unsigned short int tpc, int origTrackID)
Utility function for testing if Space Charge offsets are out of bounds.
for($it=0;$it< $RaceTrack_number;$it++)
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:82
static IonizationAndScintillation * Instance()
std::vector< sim::SimChannel > GetSimChannels() const
Creates a list with the accumulated information for the single TPC.
detinfo::DetectorPropertiesData const * fDetProp
double DriftVelocity(double efield=0., double temperature=0.) const
cm/us
bool Has(std::vector< unsigned short int > v, unsigned short int tpc) const
virtual G4bool ProcessHits(G4Step *, G4TouchableHistory *)
Definition of data types for geometry description.
double Plane0Pitch(unsigned int p) const
Definition: TPCGeo.cxx:324
DriftDirection_t DriftDirection() const
Returns an enumerator value describing the drift direction.
Definition: TPCGeo.h:144
std::vector< std::vector< ChannelMap_t > > fChannelMaps
Maps of cryostat, tpc to channel data.
virtual void EndOfEvent(G4HCofThisEvent *)
double fOffPlaneMargin
Charge deposited within this many [cm] from the plane is lead onto it.
void SetDiscoverTPC()
Sets this readout to discover the TPC of each processed hit.
A Geant4 sensitive detector that accumulates voxel information.
double offPlaneMargin
Margin for charge recovery (see LArVoxelReadout).
WidthDepthProjection_t DeltaFromActivePlane(WidthDepthProjection_t const &proj, double wMargin, double dMargin) const
Returns a projection vector that, added to the argument, gives a projection inside (or at the border ...
Definition: PlaneGeo.cxx:569
double G4ToElecTime(double const g4_time) const
Drift towards positive X values.
Definition: geo_types.h:161
Contains all timing reference information for the detector.
double DistanceFromPlane(geo::Point_t const &point) const
Returns the distance of the specified point from the wire plane.
Definition: PlaneGeo.h:621
unsigned int fCstat
and in which cryostat (if bSingleTPC is true)
void SetOffPlaneChargeRecoveryMargin(double margin)
Sets the margin for recovery of charge drifted off-plane.
Singleton to access a unified treatment of ionization and scintillation in LAr.
CLHEP::HepRandomEngine * fPropGen
random engine for charge propagation
virtual void Initialize(G4HCofThisEvent *)
do i e
Transports energy depositions from GEANT4 to TPC channels.
then echo fcl name
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:263
void AddIonizationElectrons(TrackID_t trackID, TDC_t tdc, double numberElectrons, double const *xyz, double energy, TrackID_t origTrackID=util::kBogusI)
Add ionization electrons and energy to this channel.
Definition: SimChannel.cxx:55
pdgs k
Definition: selectors.fcl:22
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
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
const double * PlaneLocation(unsigned int p) const
Definition: TPCGeo.cxx:382