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