LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
SimDriftElectrons_module.cc
Go to the documentation of this file.
1 
55 // LArSoft includes
60 //#include "larcore/Geometry/GeometryCore.h"
67 #include "larcoreobj/SimpleTypesAndConstants/RawTypes.h" // raw::ChannelID_t
68 
69 // Framework includes
72 #include "fhiclcpp/ParameterSet.h"
80 
81 // External libraries
82 #include "CLHEP/Random/RandGauss.h"
83 #include "TMath.h"
84 
85 // C++ includes
86 #include <vector>
87 #include <map>
88 #include <algorithm> // std::find
89 #include <cmath>
90 
91 //stuff from wes
93 
94 
95 namespace detsim {
96 
97  // Base class for creation of raw signals on wires.
99 
100  public:
101 
102  explicit SimDriftElectrons(fhicl::ParameterSet const& pset);
103  virtual ~SimDriftElectrons() {};
104 
105  // Methods that that are available for a module derived from
106  // art::EDProducer.
107  void produce (art::Event& evt);
108  void beginJob();
109  void endJob();
110  void reconfigure(fhicl::ParameterSet const& p);
111 
112  private:
113 
114  // The label of the module that created the sim::SimEnergyDeposit
115  // objects (as of Oct-2017, this is probably "largeant").
117 
119  std::unique_ptr<CLHEP::RandGauss> fRandGauss;
120 
124  //double fSampleRate; // unused
125  //int fTriggerOffset; // unused
128 
130  double fLDiff_const;
131  double fTDiff_const;
132  double fRecipDriftVel[3];
133 
135 
136  //double fOffPlaneMargin;
137 
138  // In order to create the associations, for each channel we create
139  // we have to keep track of its index in the output vector, and the
140  // indexes of all the steps that contributed to it.
141  typedef struct {
142  size_t channelIndex;
143  std::vector<size_t> stepList;
145 
146  // Define type: channel -> sim::SimChannel's bookkeeping.
147  typedef std::map<raw::ChannelID_t, ChannelBookKeeping_t> ChannelMap_t;
148 
149 
150  // Array of maps of channel data indexed by [cryostat,tpc]
151  std::vector< std::vector<ChannelMap_t> > fChannelMaps;
152  // The above ensemble may be thought of as a 3D array of
153  // ChannelBookKeepings: e.g., SimChannel[cryostat,tpc,channel ID].
154 
155  // Save the number of cryostats, and the number of TPCs within
156  // each cryostat.
157  size_t fNCryostats;
158  std::vector<size_t> fNTPCs;
159 
160  // Per-cluster information.
161  std::vector< double > fLongDiff;
162  std::vector< double > fTransDiff1;
163  std::vector< double > fTransDiff2;
164  std::vector< double > fnElDiff;
165  std::vector< double > fnEnDiff;
166 
167  double fDriftClusterPos[3];
168 
169  // Utility routine.
170  //geo::vect::Vector_t RecoverOffPlaneDeposit (geo::vect::Vector_t const&, geo::PlaneGeo const&) const;
171 
174 
175 
176  //IS calculationg
178 
179  }; // class SimDriftElectrons
180 
181  //-------------------------------------------------
183  {
184  this->reconfigure(pset);
185 
186  produces< std::vector<sim::SimChannel> >();
187  if(fStoreDriftedElectronClusters)produces< std::vector<sim::SimDriftedElectronCluster> >();
188  //produces< art::Assns<sim::SimChannel, sim::SimEnergyDeposit> >();
189 
190  // create a default random engine; obtain the random seed from
191  // NuRandomService, unless overridden in configuration with key
192  // "Seed"
194  ->createEngine(*this, pset, "Seed");
195 
204  //fOffPlaneMargin = pset.get< double >("ChargeRecoveryMargin",0.0);
205  // Protection against a silly value.
206  //fOffPlaneMargin = std::max(fOffPlaneMargin,0.0);
207  }
208 
209  //-------------------------------------------------
211  {
212  std::string label= p.get< std::string >("SimulationLabel");
214 
215  fStoreDriftedElectronClusters = p.get< bool >("StoreDriftedElectronClusters", false);
216 
217 
218  return;
219  }
220 
221  //-------------------------------------------------
223  {
224  fTimeService = lar::providerFrom<detinfo::DetectorClocksService>();
226 
227  // Set up the gaussian generator.
229  CLHEP::HepRandomEngine& engine = rng->getEngine();
230  fRandGauss = std::unique_ptr<CLHEP::RandGauss>(new CLHEP::RandGauss(engine));
231 
232  // Define the physical constants we'll use.
233 
234  auto const * detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
235  fElectronLifetime = detprop->ElectronLifetime(); // Electron lifetime as returned by the DetectorProperties service assumed to be in us;
236  for (int i = 0; i<3; ++i) {
237  double driftVelocity = detprop->DriftVelocity(detprop->Efield(i),
238  detprop->Temperature())*1.e-3; // Drift velocity as returned by the DetectorProperties service assumed to be in cm/us. Multiply by 1.e-3 to convert into LArSoft standard velocity units, cm/ns;
239 
240  fRecipDriftVel[i] = 1./driftVelocity;
241  }
242 
243  // To-do: Move the parameters we fetch from "LArG4" to detector
244  // properties.
246  fElectronClusterSize = paramHandle->ElectronClusterSize();
248  fLongitudinalDiffusion = paramHandle->LongitudinalDiffusion(); // cm^2/ns units
249  fTransverseDiffusion = paramHandle->TransverseDiffusion(); // cm^2/ns units
250 
251  LOG_DEBUG("SimDriftElectrons") << " e lifetime (ns): " << fElectronLifetime
252  << "\n Temperature (K): " << detprop->Temperature()
253  << "\n Drift velocity (cm/ns): " << 1./fRecipDriftVel[0]
254  <<" "<<1./fRecipDriftVel[1]<<" "<<1./fRecipDriftVel[2];
255 
256  // Opposite of lifetime. Convert from us to standard LArSoft time units, ns;
258  fLDiff_const = std::sqrt(2.*fLongitudinalDiffusion);
259  fTDiff_const = std::sqrt(2.*fTransverseDiffusion);
260 
261  // For this detector's geometry, save the number of cryostats and
262  // the number of TPCs within each cryostat.
264  fNTPCs.resize(fNCryostats);
265  for ( size_t n = 0; n < fNCryostats; ++n )
266  fNTPCs[n] = fGeometry->NTPC(n);
267 
268 
269  fISAlg.Initialize(lar::providerFrom<detinfo::LArPropertiesService>(),
270  detprop,
271  &(*paramHandle),
272  lar::providerFrom<spacecharge::SpaceChargeService>());
273 
274 
275  return;
276  }
277 
278  //-------------------------------------------------
280  {
281  }
282 
283  //-------------------------------------------------
285  {
286  // Fetch the SimEnergyDeposit objects for this event.
287  typedef art::Handle< std::vector<sim::SimEnergyDeposit> > energyDepositHandle_t;
288  energyDepositHandle_t energyDepositHandle;
289  // If there aren't any energy deposits for this event, don't
290  // panic. It's possible someone is doing a study with events
291  // outside the TPC, or where there are only non-ionizing
292  // particles, or something like that.
293  if (!event.getByLabel(fSimModuleLabel, energyDepositHandle))
294  return;
295 
296  // Define the container for the SimChannel objects that will be
297  // transferred to the art::Event after the put statement below.
298  std::unique_ptr< std::vector<sim::SimChannel> > channels(new std::vector<sim::SimChannel>);
299  // Container for the SimDriftedElectronCluster objects
300  std::unique_ptr< std::vector<sim::SimDriftedElectronCluster> > SimDriftedElectronClusterCollection( new std::vector<sim::SimDriftedElectronCluster>);
301 
302  // Clear the channel maps from the last event. Remember,
303  // fChannelMaps is an array[cryo][tpc] of maps.
304  size_t cryo = 0;
305  fChannelMaps.resize(fNCryostats);
306  for (auto& cryoData: fChannelMaps) { // each, a vector of maps
307  cryoData.resize(fNTPCs[cryo++]);
308  for (auto& channelsMap: cryoData) channelsMap.clear(); // each, a map
309  }
310 
311  // We're going through the input vector by index, rather than by
312  // iterator, because we need the index number to compute the
313  // associations near the end of this method.
314  auto const& energyDeposits = *energyDepositHandle;
315  auto energyDepositsSize = energyDeposits.size();
316 
317  // For each energy deposit in this event
318  for ( size_t edIndex = 0; edIndex < energyDepositsSize; ++edIndex )
319  {
320  auto const& energyDeposit = energyDeposits[edIndex];
321 
322  // "xyz" is the position of the energy deposit in world
323  // coordinates. Note that the units of distance in
324  // sim::SimEnergyDeposit are supposed to be cm.
325  auto const mp = energyDeposit.MidPoint();
326  double const xyz[3] = { mp.X(), mp.Y(), mp.Z() };
327 
328  // From the position in world coordinates, determine the
329  // cryostat and tpc. If somehow the step is outside a tpc
330  // (e.g., cosmic rays in rock) just move on to the next one.
331  unsigned int cryostat = 0;
332  try {
333  fGeometry->PositionToCryostat(xyz, cryostat);
334  }
335  catch(cet::exception &e){
336  mf::LogWarning("SimDriftElectrons") << "step "// << energyDeposit << "\n"
337  << "cannot be found in a cryostat\n"
338  << e;
339  continue;
340  }
341 
342  unsigned int tpc = 0;
343  try {
344  fGeometry->PositionToTPC(xyz, tpc, cryostat);
345  }
346  catch(cet::exception &e){
347  mf::LogWarning("SimDriftElectrons") << "step "// << energyDeposit << "\n"
348  << "cannot be found in a TPC\n"
349  << e;
350  continue;
351  }
352 
353  const geo::TPCGeo& tpcGeo = fGeometry->TPC(tpc, cryostat);
354 
355  // The drift direction can be either in the positive
356  // or negative direction in any coordinate x, y or z.
357  // Charge drift in ...
358  // +x: tpcGeo.DetectDriftDirection()==1
359  // -x: tpcGeo.DetectDriftDirection()==-1
360  // +y: tpcGeo.DetectDriftDirection()==2
361  // -y tpcGeo.DetectDriftDirection()==-2
362  // +z: tpcGeo.DetectDriftDirection()==3
363  // -z: tpcGeo.DetectDriftDirection()==-3
364 
365 
366  //Define charge drift direction: driftcoordinate (x, y or z) and driftsign (positive or negative). Also define coordinates perpendicular to drift direction.
367  int driftcoordinate = std::abs(tpcGeo.DetectDriftDirection())-1; //x:0, y:1, z:2
368 
369  int transversecoordinate1 = 0;
370  int transversecoordinate2 = 0;
371  if(driftcoordinate == 0)
372  {
373  transversecoordinate1 = 1;
374  transversecoordinate2 = 2;
375  }
376  else if(driftcoordinate == 1)
377  {
378  transversecoordinate1 = 0;
379  transversecoordinate2 = 2;
380  }
381  else if(driftcoordinate == 2)
382  {
383  transversecoordinate1 = 0;
384  transversecoordinate2 = 1;
385  }
386 
387  if(transversecoordinate1 == transversecoordinate2) continue; //this is the case when driftcoordinate != 0, 1 or 2
388 
389  int driftsign = 0; //1: +x, +y or +z, -1: -x, -y or -z
390  if(tpcGeo.DetectDriftDirection() > 0) driftsign = 1;
391  else driftsign = -1;
392 
393  //Check for charge deposits behind charge readout planes
394  if(driftsign == 1 && tpcGeo.PlaneLocation(0)[driftcoordinate] < xyz[driftcoordinate] )
395  continue;
396  if(driftsign == -1 && tpcGeo.PlaneLocation(0)[driftcoordinate] > xyz[driftcoordinate] )
397  continue;
398 
399 
400 
402  // Center of plane is also returned in cm units
403  double DriftDistance = std::abs(xyz[driftcoordinate] - tpcGeo.PlaneLocation(0)[driftcoordinate]);
404 
405  // Space-charge effect (SCE): Get SCE {x,y,z} offsets for
406  // particular location in TPC
407  geo::Vector_t posOffsets{0.0,0.0,0.0};
408  double posOffsetxyz[3] = {0.0,0.0,0.0}; //need this array for the driftcoordinate and transversecoordinates
409  auto const* SCE = lar::providerFrom<spacecharge::SpaceChargeService>();
410  if (SCE->EnableSimSpatialSCE() == true)
411  {
412  posOffsets = SCE->GetPosOffsets(mp);
413  posOffsetxyz[0] = posOffsets.X();
414  posOffsetxyz[1] = posOffsets.Y();
415  posOffsetxyz[2] = posOffsets.Z();
416  }
417 
418  double avegagetransversePos1 = 0.;
419  double avegagetransversePos2 = 0.;
420 
421  DriftDistance += -1.*posOffsetxyz[driftcoordinate];
422  avegagetransversePos1 = xyz[transversecoordinate1] + posOffsetxyz[transversecoordinate1];
423  avegagetransversePos2 = xyz[transversecoordinate2] + posOffsetxyz[transversecoordinate2];
424 
425 
426  // Space charge distortion could push the energy deposit beyond the wire
427  // plane (see issue #15131). Given that we don't have any subtlety in the
428  // simulation of this region, bringing the deposit exactly on the plane
429  // should be enough for the time being.
430  if (DriftDistance < 0.) DriftDistance = 0.;
431 
432  // Drift time in ns
433  double TDrift = DriftDistance * fRecipDriftVel[0];
434 
435  if (tpcGeo.Nplanes() == 2 && driftcoordinate == 0){// special case for ArgoNeuT (Nplanes = 2 and drift direction = x): plane 0 is the second wire plane
436  TDrift = ((DriftDistance - tpcGeo.PlanePitch(0,1)) * fRecipDriftVel[0]
437  + tpcGeo.PlanePitch(0,1) * fRecipDriftVel[1]);
438  }
439 
440  fISAlg.Reset();
442  //std::cout << "Got " << fISAlg.NumberIonizationElectrons() << "." << std::endl;
443 
444  const double lifetimecorrection = TMath::Exp(TDrift / fLifetimeCorr_const);
445  const int nIonizedElectrons = fISAlg.NumberIonizationElectrons();
446  const double energy = energyDeposit.Energy();
447 
448  // if we have no electrons (too small energy or too large recombination)
449  // we are done already here
450  if (nIonizedElectrons <= 0) {
451  LOG_DEBUG("SimDriftElectrons")
452  << "step "// << energyDeposit << "\n"
453  << "No electrons drifted to readout, " << energy << " MeV lost.";
454  continue;
455  }
456 
457  // includes the effect of lifetime: lifetimecorrection = exp[-tdrift/tau]
458  const double nElectrons = nIonizedElectrons * lifetimecorrection;
459  //std::cout << "After lifetime, " << nElectrons << " electrons." << std::endl;
460 
461  // Longitudinal & transverse diffusion sigma (cm)
462  double SqrtT = std::sqrt(TDrift);
463  double LDiffSig = SqrtT * fLDiff_const;
464  double TDiffSig = SqrtT * fTDiff_const;
465  double electronclsize = fElectronClusterSize;
466 
467  // Number of electron clusters.
468  int nClus = (int) std::ceil(nElectrons / electronclsize);
469  if (nClus < fMinNumberOfElCluster)
470  {
471  electronclsize = nElectrons / fMinNumberOfElCluster;
472  if (electronclsize < 1.0)
473  {
474  electronclsize = 1.0;
475  }
476  nClus = (int) std::ceil(nElectrons / electronclsize);
477  }
478 
479  // Empty and resize the electron-cluster vectors.
480  fLongDiff.clear();
481  fTransDiff1.clear();
482  fTransDiff2.clear();
483  fnElDiff.clear();
484  fnEnDiff.clear();
485  fLongDiff.resize(nClus);
486  fTransDiff1.resize(nClus);
487  fTransDiff2.resize(nClus);
488  fnElDiff.resize(nClus, electronclsize);
489  fnEnDiff.resize(nClus);
490 
491  // fix the number of electrons in the last cluster, that has a smaller size
492  fnElDiff.back() = nElectrons - (nClus-1)*electronclsize;
493 
494  for(size_t xx = 0; xx < fnElDiff.size(); ++xx){
495  if(nElectrons > 0) fnEnDiff[xx] = energy/nElectrons*fnElDiff[xx];
496  else fnEnDiff[xx] = 0.;
497  }
498 
499  //std::cout << "Split into, " << nClus << " clusters." << std::endl;
500 
501  // Smear drift times by longitudinal diffusion
502  if (LDiffSig > 0.0)
503  fRandGauss->fireArray( nClus, &fLongDiff[0], 0., LDiffSig);
504  else
505  fLongDiff.assign(nClus, 0.0);
506 
507  if (TDiffSig > 0.0) {
508  // Smear the coordinates in plane perpendicular to drift direction by the transverse diffusion
509  fRandGauss->fireArray( nClus, &fTransDiff1[0], avegagetransversePos1, TDiffSig);
510  fRandGauss->fireArray( nClus, &fTransDiff2[0], avegagetransversePos2, TDiffSig);
511  }
512  else {
513  fTransDiff1.assign(nClus, avegagetransversePos1);
514  fTransDiff2.assign(nClus, avegagetransversePos2);
515  }
516 
517  //std::cout << "Smeared the " << nClus << " clusters." << std::endl;
518 
519  // make a collection of electrons for each plane
520  for(size_t p = 0; p < tpcGeo.Nplanes(); ++p){
521 
522  fDriftClusterPos[driftcoordinate] = tpcGeo.PlaneLocation(p)[driftcoordinate];
523 
524  // Drift nClus electron clusters to the induction plane
525  for(int k = 0; k < nClus; ++k){
526 
527  //std::cout << "\tCluster " << k << " diffs are "
528  // << fLongDiff[k] << " " << fTransDiff1[k] << " " << fTransDiff2[k]
529  // << std::endl;
530 
531 
532  // Correct drift time for longitudinal diffusion and plane
533  double TDiff = TDrift + fLongDiff[k] * fRecipDriftVel[0];
534 
535  // Take into account different Efields between planes
536  // Also take into account special case for ArgoNeuT (Nplanes = 2 and drift direction = x): plane 0 is the second wire plane
537  for (size_t ip = 0; ip<p; ++ip){
538  TDiff += (tpcGeo.PlaneLocation(ip+1)[driftcoordinate] - tpcGeo.PlaneLocation(ip)[driftcoordinate]) * fRecipDriftVel[(tpcGeo.Nplanes() == 2 && driftcoordinate == 0)?ip+2:ip+1];
539  }
540 
541  fDriftClusterPos[transversecoordinate1] = fTransDiff1[k];
542  fDriftClusterPos[transversecoordinate2] = fTransDiff2[k];
543 
545 
546  // grab the nearest channel to the fDriftClusterPos position
547  try{
548  /*
549  if (fOffPlaneMargin != 0) {
550  // get the effective position where to consider the charge landed;
551  //
552  // Some optimisations are possible; in particular, this method
553  // could be extended to inform us if the point was too far.
554  // Currently, if that is the case the code will proceed, find the
555  // point is off plane, emit a warning and skip the deposition.
556  //
557  auto const landingPos
558  = RecoverOffPlaneDeposit({ fDriftClusterPos[0], fDriftClusterPos[1], fDriftClusterPos[2] }, plane);
559  fDriftClusterPos[0] = landingPos.X();
560  fDriftClusterPos[1] = landingPos.Y();
561  fDriftClusterPos[2] = landingPos.Z();
562 
563  } // if charge lands off plane
564  */
565  raw::ChannelID_t channel = fGeometry->NearestChannel(fDriftClusterPos, p, tpc, cryostat);
566 
567 // std::cout << "fDriftClusterPos[0]: " << fDriftClusterPos[0] << "\t fDriftClusterPos[1]: " << fDriftClusterPos[1] << "\t fDriftClusterPos[2]: " << fDriftClusterPos[2] << std::endl;
568 // std::cout << "channel: " << channel << std::endl;
569 
570  //std::cout << "\tgot channel " << channel << " for cluster " << k << std::endl;
571 
574  // Add potential decay/capture/etc delay effect, simTime.
575  auto const simTime = energyDeposit.Time();
576  unsigned int tdc = fClock.Ticks(fTimeService->G4ToElecTime(TDiff + simTime));
577 
578  // Find whether we already have this channel in our map.
579  ChannelMap_t& channelDataMap = fChannelMaps[cryostat][tpc];
580  auto search = channelDataMap.find(channel);
581 
582  // We will find (or create) the pointer to a
583  // sim::SimChannel.
584  //sim::SimChannel* channelPtr = NULL;
585  size_t channelIndex=0;
586 
587  // Have we created the sim::SimChannel corresponding to
588  // channel ID?
589  if (search == channelDataMap.end())
590  {
591  //std::cout << "\tHaven't done this channel before." << std::endl;
592 
593  // We haven't. Initialize the bookkeeping information
594  // for this channel.
595  ChannelBookKeeping_t bookKeeping;
596 
597  // Add a new channel to the end of the list we'll
598  // write out after we've processed this event.
599  bookKeeping.channelIndex = channels->size();
600  channels->emplace_back( channel );
601  channelIndex = bookKeeping.channelIndex;
602 
603  // Save the pointer to the newly-created
604  // sim::SimChannel.
605  //channelPtr = &(channels->back());
606  //bookKeeping.channelPtr = channelPtr;
607 
608  // Initialize a vector with the index of the step that
609  // created this channel.
610  bookKeeping.stepList.push_back( edIndex );
611 
612  // Save the bookkeeping information for this channel.
613  channelDataMap[channel] = bookKeeping;
614  }
615  else {
616  // We've created this SimChannel for a previous energy
617  // deposit. Get its address.
618 
619  //std::cout << "\tHave seen this channel before." << std::endl;
620 
621  auto& bookKeeping = search->second;
622  channelIndex = bookKeeping.channelIndex;
623  //channelPtr = bookKeeping.channelPtr;
624 
625  // Has this step contributed to this channel before?
626  auto& stepList = bookKeeping.stepList;
627  auto stepSearch = std::find(stepList.begin(), stepList.end(), edIndex );
628  if ( stepSearch == stepList.end() ) {
629  // No, so add this step's index to the list.
630  stepList.push_back( edIndex );
631  }
632  }
633 
634  sim::SimChannel* channelPtr = &(channels->at(channelIndex));
635 
636  //std::cout << "\tAdding electrons to SimChannel" << std::endl;
637  //std::cout << "\t\t"
638  // << energyDeposit.TrackID() << " " << tdc
639  // << " " << xyz[0] << " " << xyz[1] << " " << xyz[2]
640  // << " " << fnEnDiff[k] << " " << fnElDiff[k]
641  // << std::endl;
642 
643  //if(!channelPtr) std::cout << "\tUmm...ptr is NULL?" << std::endl;
644  //else std::cout << "\tChannel is " << channelPtr->Channel() << std::endl;
645  // Add the electron clusters and energy to the
646  // sim::SimChannel
647  channelPtr->AddIonizationElectrons(energyDeposit.TrackID(),
648  tdc,
649  fnElDiff[k],
650  xyz,
651  fnEnDiff[k]);
652 
654  SimDriftedElectronClusterCollection->push_back(sim::SimDriftedElectronCluster(
655  fnElDiff[k],
656  TDiff + simTime, // timing
657  {mp.X(),mp.Y(),mp.Z()}, // mean position of the deposited energy
658  {fDriftClusterPos[0],fDriftClusterPos[1],fDriftClusterPos[2]}, // final position of the drifted cluster
659  {LDiffSig,TDiffSig,TDiffSig}, // Longitudinal (X) and transverse (Y,Z) diffusion
660  fnEnDiff[k], //deposited energy that originated this cluster
661  energyDeposit.TrackID()) );
662 
663  //std::cout << "\tAdded the electrons." << std::endl;
664 
665  }
666  catch(cet::exception &e) {
667  mf::LogWarning("SimDriftElectrons") << "unable to drift electrons from point ("
668  << xyz[0] << "," << xyz[1] << "," << xyz[2]
669  << ") with exception " << e;
670  } // end try to determine channel
671  } // end loop over clusters
672  } // end loop over planes
673  } // for each sim::SimEnergyDeposit
674  /*
675  // Now that we've processed the information for all the
676  // sim::SimEnergyDeposit objects into sim::SimChannel objects,
677  // create the associations between them.
678 
679  // Define the container for the associations between the channels
680  // and the energy deposits (steps). Note it's possible for an
681  // energy deposit to be associated with more than one channel (if
682  // its electrons drift to multiple wires), and a channel will
683  // almost certainly have multiple energy deposits.
684  std::unique_ptr< art::Assns<sim::SimEnergyDeposit, sim::SimChannel> >
685  step2channel (new art::Assns<sim::SimEnergyDeposit, sim::SimChannel>);
686 
687  // For every element in the 3-D fChannelMaps array...
688  for ( auto i = fChannelMaps.begin(); i != fChannelMaps.end(); ++i ) {
689  for ( auto j = i->begin(); j != i->end(); ++j ) {
690  for ( auto k = j->begin(); k != j->end(); ++k ) {
691  const ChannelBookKeeping_t& bookKeeping = (*k).second;
692  const size_t channelIndex = bookKeeping.channelIndex;
693 
694  // Create a one-to-one association between each channel and
695  // each step that created it.
696  for ( size_t m = 0; m < bookKeeping.stepList.size(); ++m)
697  {
698  const size_t edIndex = bookKeeping.stepList[m];
699  // Props to me for figuring out the following two
700  // statements. You have to look deeply in the
701  // documentation for art::Ptr and util::Associations to
702  // put this together.
703  art::Ptr<sim::SimEnergyDeposit> energyDepositPtr( energyDepositHandle, edIndex );
704  util::CreateAssn(*this, event, *channels, energyDepositPtr, *step2channel, channelIndex);
705  }
706  }
707  }
708  }
709  */
710  // Write the sim::SimChannel collection.
711  event.put(std::move(channels));
712  if (fStoreDriftedElectronClusters) event.put(std::move(SimDriftedElectronClusterCollection));
713 
714  // ... and its associations.
715  //event.put(std::move(step2channel));
716 
717  return;
718  }
719 
720  //----------------------------------------------------------------------------
721  /*
722  geo::vect::Vector_t SimDriftElectrons::RecoverOffPlaneDeposit
723  (geo::vect::Vector_t const& pos, geo::PlaneGeo const& plane) const
724  {
725  //
726  // translate the landing position on the two frame coordinates
727  // ("width" and "depth")
728  //
729  auto const landingPos = plane.PointWidthDepthProjection(pos);
730 
731  //
732  // compute the distance of the landing position on the two frame
733  // coordinates ("width" and "depth");
734  // keep the point within 10 micrometers (0.001 cm) from the border
735  //
736  auto const offPlane = plane.DeltaFromActivePlane(landingPos, 0.001);
737 
738  //
739  // if both the distances are below the margin, move the point to
740  // the border
741  //
742 
743  // nothing to recover: landing is inside
744  if ((offPlane.X() == 0.0) && (offPlane.Y() == 0.0)) return pos;
745 
746  // won't recover: too far
747  if ((std::abs(offPlane.X()) > fOffPlaneMargin)
748  || (std::abs(offPlane.Y()) > fOffPlaneMargin))
749  return pos;
750 
751  // we didn't fully decompose because it might be unnecessary;
752  // now we need the full thing
753  auto const distance = plane.DistanceFromPlane(pos);
754 
755  return plane.ComposePoint(distance, landingPos + offPlane);
756 
757  } // SimDriftElectrons::RecoverOffPlaneDeposit()
758  */
759 } // namespace detsim
760 
Store parameters for running LArG4.
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:167
void Initialize(const detinfo::LArProperties *larp, const detinfo::DetectorProperties *detp, const sim::LArG4Parameters *lgp, const spacecharge::SpaceCharge *sce)
double PlanePitch(unsigned int p1=0, unsigned int p2=1) const
Returns the center of the TPC volume in world coordinates [cm].
Definition: TPCGeo.cxx:419
Double_t xx
Definition: macro.C:12
virtual const ::detinfo::ElecClock & TPCClock() const =0
Lends a constant TPC clock with time set to trigger time.
Energy deposited on a readout channel by simulated tracks.
Definition: SimChannel.h:143
contains objects relating to SimDriftedElectronCluster
CryostatGeo const & PositionToCryostat(geo::Point_t const &point) const
Returns the cryostat at specified location.
void CalculateIonizationAndScintillation(sim::SimEnergyDeposit const &edep)
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:145
Geometry information for a single TPC.
Definition: TPCGeo.h:37
std::vector< std::vector< ChannelMap_t > > fChannelMaps
Detector simulation of raw signals on wires.
art::ServiceHandle< geo::Geometry > fGeometry
Handle to the Geometry service.
int Ticks() const
Current clock tick (that is, the number of tick Time() falls in).
Definition: ElecClock.h:235
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
geo::TPCGeo const & PositionToTPC(geo::Point_t const &point) const
Returns the TPC at specified location.
base_engine_t & getEngine() const
double TransverseDiffusion() const
base_engine_t & createEngine(seed_t seed)
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
double ElectronClusterSize() const
const detinfo::DetectorClocks * fTimeService
T get(std::string const &key) const
Definition: ParameterSet.h:231
double energy
Definition: plottest35.C:25
virtual double G4ToElecTime(double g4_time) const =0
Given a simulation time [ns], converts it into electronics time [µs].
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
Conversion of times between different formats and references.
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:52
std::map< raw::ChannelID_t, ChannelBookKeeping_t > ChannelMap_t
static art::ServiceHandle< art::RandomNumberGenerator > & rng()
Utility object to perform functions of association.
double NumberIonizationElectrons() const
int MinNumberOfElCluster() const
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
short int DetectDriftDirection() const
Returns the expected drift direction based on geometry.
Definition: TPCGeo.cxx:182
::detinfo::ElecClock fClock
TPC electronics clock.
contains information for a single step in the detector simulation
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
object containing MC truth information necessary for making RawDigits and doing back tracking ...
#define LOG_DEBUG(id)
Char_t n[5]
std::unique_ptr< CLHEP::RandGauss > fRandGauss
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
double LongitudinalDiffusion() const
Class representing the time measured by an electronics clock.
Definition: ElecClock.h:91
TCEvent evt
Definition: DataStructs.cxx:5
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:27
Float_t e
Definition: plot.C:34
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.
void reconfigure(fhicl::ParameterSet const &p)
const double * PlaneLocation(unsigned int p) const
Returns the coordinates of the center of the specified plane [cm].
Definition: TPCGeo.cxx:413
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
SimDriftElectrons(fhicl::ParameterSet const &pset)
Event finding and building.