IonizationReadout_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file IonizationReadout_module.cc
3 /// \brief Create the readout from the ionization signal
4 ///
5 /// \author brebel@fnal.gov
6 ////////////////////////////////////////////////////////////////////////
7 
8 #ifndef GAR_READOUTSIMULATION_IONIZATIONREADOUT
9 #define GAR_READOUTSIMULATION_IONIZATIONREADOUT
10 
11 // C++ Includes
12 #include <memory>
13 #include <vector>
14 #include <iostream>
15 #include <string>
16 #include <sys/stat.h>
17 
18 // Framework includes
22 #include "fhiclcpp/ParameterSet.h"
29 #include "cetlib_except/exception.h"
30 #include "cetlib/search_path.h"
31 
32 // nutools extensions
34 #include "nug4/ParticleNavigation/ParticleList.h"
35 #include "nurandom/RandomUtils/NuRandomService.h"
36 
37 // GArSoft Includes
42 #include "Utilities/AssociationUtil.h"
45 #include "Geometry/GeometryGAr.h"
46 #include "CoreUtils/ServiceUtil.h"
47 
48 // ROOT Includes
49 #include "TVector3.h"
50 #include "TFile.h"
51 
52 // Forward declarations
53 
54 ///Geant4 interface
55 namespace gar {
56  namespace rosim {
57 
58  /**
59  * @brief Runs Readout simulation including propagation of electrons and photons to readout
60  *
61  *
62  * Randomness
63  * -----------
64  *
65  * The random number generators used by this process are:
66  * - 'GEANT' instance: used by Geant4
67  * - 'propagation' instance: used in electron propagation
68  *
69  */
71  public:
72 
73  /// Standard constructor and destructor for an FMWK module.
74  explicit IonizationReadout(fhicl::ParameterSet const& pset);
75  virtual ~IonizationReadout();
76 
77  void produce (::art::Event& evt);
78  void beginJob();
79  void beginRun(::art::Run& run);
80  void reconfigure(fhicl::ParameterSet const& pset);
81 
82  private:
83 
84  void DriftElectronsToReadout(std::vector<sdp::EnergyDeposit> const& edepCol,
85  std::vector<edepIDE> & edepIDEs);
86  void CombineIDEs(std::vector<edepIDE> & edepIDEs,
87  std::vector<sdp::EnergyDeposit> const& edepCol);
88  void CreateSignalDigit(unsigned int const& channel,
89  std::vector<float> & electrons,
90  std::set<size_t> & eDepLocs,
91  std::deque<float> & eDepWeights,
92  std::vector<raw::RawDigit> & digCol,
93  ::art::ValidHandle< std::vector<sdp::EnergyDeposit> > & eDepCol,
95  ::art::Event & evt);
96  void CheckChannelToEnergyDepositMapping(unsigned int const& channel,
97  sdp::EnergyDeposit const& edep,
98  std::string const& id);
99 
100  std::string fG4Label; ///< label of G4 module
101  std::unique_ptr<ElectronDriftAlg> fDriftAlg; ///< algorithm to drift ionization electrons
102  const gar::detinfo::DetectorClocks* fTime; ///< electronics clock
103  std::unique_ptr<TPCReadoutSimAlg> fROSimAlg; ///< algorithm to simulate the electronics
104  fhicl::ParameterSet fISCalcPars; ///< parameter set for the IS calculator
105  size_t fNumTicks; ///< number of TDC samples
106  const gar::geo::GeometryCore* fGeo; ///< geometry information
107  bool fCheckChan; ///< flag to check mapping of energy deposits to channels
108  CLHEP::HepRandomEngine &fEngine; ///< random engine
109  std::string fPRFFileName; ///< where to find the pad response function histograms
110 
111  TH2F *fHFILLPRF; ///< pad response function for hole-filler chamber
112  TH2F *fIROCPRF; ///< pad response function for IROC
113  TH2F *fIOROCPRF; ///< pad response function for IOROC
114  TH2F *fOOROCPRF; ///< pad response function for OOROC
115 
116  bool fUsePRF; ///< switch to turn on PRF modeling, otherwise just use the arrival pad
117  };
118 
119  } // namespace rosim
120 
121 
122 
123 
124 
125  namespace rosim {
126 
127  //----------------------------------------------------------------------
128  // Constructor
131 
132  fTime = gar::providerFrom<detinfo::DetectorClocksServiceGAr>();
133 
134  fNumTicks = gar::providerFrom<detinfo::DetectorPropertiesService>()->NumberTimeSamples();
135 
136  fGeo = gar::providerFrom<geo::GeometryGAr>();
137 
138  this->reconfigure(pset);
139 
140  produces< std::vector<raw::RawDigit> >();
141  produces< ::art::Assns<sdp::EnergyDeposit, raw::RawDigit, float> >();
142 
143 
144  // read in the pad response function histograms
145 
146  cet::search_path sp("FW_SEARCH_PATH");
147  std::string fullname;
148  sp.find_file(fPRFFileName, fullname);
149  struct stat sb;
150  if (fullname.empty() || stat(fullname.c_str(), &sb)!=0)
151  throw cet::exception("IonizationReadout") << "Input pad response function file "
152  << fPRFFileName
153  << " not found in FW_SEARCH_PATH\n";
154 
155  TFile infile(fullname.c_str(),"READ"); // file will close when infile goes out of scope
156  fHFILLPRF = (TH2F*) infile.Get("respHFILL");
157  fIROCPRF = (TH2F*) infile.Get("respIROC");
158  fIOROCPRF = (TH2F*) infile.Get("respIOROC");
159  fOOROCPRF = (TH2F*) infile.Get("respOOROC");
160  fHFILLPRF->SetDirectory(0);
161  fIROCPRF->SetDirectory(0);
162  fIOROCPRF->SetDirectory(0);
163  fOOROCPRF->SetDirectory(0);
164 
165  return;
166  }
167 
168 
169 
170  //----------------------------------------------------------------------
171  // Destructor
173 
174 
175 
176  //----------------------------------------------------------------------
178 
179  MF_LOG_DEBUG("IonizationReadout") << "Debug: IonizationReadout()";
181 
182  fISCalcPars = pset.get<fhicl::ParameterSet>("ISCalcPars" );
183  fG4Label = pset.get<std::string >("G4ModuleLabel", "geant");
184  fCheckChan = pset.get<bool >("CheckChannelMapping", false );
185  fPRFFileName = pset.get<std::string >("PRFFileName", "MPD/TPCPRF/mpdtpcprf_v1.root");
186  fUsePRF = pset.get<bool >("UsePRF" , true );
187 
188  auto driftAlgPars = pset.get<fhicl::ParameterSet>("ElectronDriftAlgPars");
189  auto driftAlgName = driftAlgPars.get<std::string>("DriftAlgType");
190 
191 
192  if (driftAlgName.compare("Standard") == 0) {
193  fDriftAlg = std::make_unique<gar::rosim::ElectronDriftStandardAlg>(fEngine,
194  driftAlgPars);
195  } else {
196  throw cet::exception("IonizationReadout")
197  << "Unable to determine which electron drift algorithm to use, bail";
198  }
199 
200  auto tpcROAlgPars = pset.get<fhicl::ParameterSet>("TPCReadoutSimAlgPars");
201  auto tpcROAlgName = tpcROAlgPars.get<std::string>("TPCReadoutSimType");
202 
203  if (tpcROAlgName.compare("Standard") == 0){
204  fROSimAlg = std::make_unique<gar::rosim::TPCReadoutSimStandardAlg>(fEngine,
205  tpcROAlgPars);
206  } else {
207  throw cet::exception("IonizationReadout")
208  << "Unable to determine which TPC readout simulation algorithm to use, bail";
209  }
210 
211  return;
212  }
213 
214 
215 
216  //----------------------------------------------------------------------
218 
219  //auto* rng = &*(::art::ServiceHandle<::art::RandomNumberGenerator>());
220 
221  // create the ionization and scintillation calculator;
222  // this is a singleton (!) so we just need to make the instance in one
223  // location
225  fISCalcPars);
226 
227  return;
228  }
229 
230 
231 
232  //--------------------------------------------------------------------------
234  return;
235  }
236 
237 
238 
239  //--------------------------------------------------------------------------
241 
242  MF_LOG_DEBUG("IonizationReadout") << "produce()";
243 
244  // loop over the lists and put the particles and voxels into the event as collections
245  std::unique_ptr< std::vector<raw::RawDigit> > rdCol (new std::vector<raw::RawDigit> );
246  std::unique_ptr< ::art::Assns<sdp::EnergyDeposit, raw::RawDigit, float> > erassn(new ::art::Assns<sdp::EnergyDeposit, raw::RawDigit, float>);
247 
248  // first get the energy deposits from the event record
249  auto eDepCol = evt.getValidHandle< std::vector<sdp::EnergyDeposit> >(fG4Label);
250 
251  if(eDepCol->size() > 0){
252 
253  std::vector<edepIDE> eDepIDEs;
254 
255  // drift the ionization electrons to the readout and create edepIDE objects
256  this->DriftElectronsToReadout(*eDepCol, eDepIDEs);
257 
258  if (eDepIDEs.size()>0)
259  {
260 
261  // IDEs have been combined already; there are no repeat TDC values for any channel
262  unsigned int prevChan = eDepIDEs.front().Channel;
263  std::set<size_t> digitEDepLocs;
264  std::deque<float> digitEDepWeights;
265  std::vector<float> electrons(fNumTicks, 0.);
266 
267  // make the signal raw digits and set their associations to the energy deposits
268  for(auto edide : eDepIDEs){
269 
270  MF_LOG_DEBUG("IonizationReadout")
271  << "Current eDepIDE channel is "
272  << edide.Channel
273  << " previous channel is "
274  << prevChan;
275 
276  if(edide.Channel != prevChan){
277  MF_LOG_DEBUG("IonizationReadout")
278  << "There are "
279  << digitEDepLocs.size()
280  << " locations for "
281  << edide.Channel
282  << " rdCol size is currently "
283  << rdCol->size();
284 
285  // this method clears the electrons and digitEDepLocs collections
286  // after creating the RawDigit
287  this->CreateSignalDigit(prevChan,
288  electrons,
289  digitEDepLocs,
290  digitEDepWeights,
291  *rdCol,
292  eDepCol,
293  *erassn,
294  evt);
295 
296  // reset the previous channel info
297  prevChan = edide.Channel;
298 
299  }
300 
301  // put overflow times in the last bin. Is this okay? TODO
302  size_t esize = electrons.size();
303  if (esize>0) {
304  if (edide.TDC >= esize) {
305  electrons[esize - 1] = edide.NumElect;
306  } else {
307  electrons[edide.TDC] = edide.NumElect;
308  }
309  }
310 
311  for(auto loc : edide.edepLocs) digitEDepLocs.insert(loc);
312  for(auto w : edide.edepWeights) digitEDepWeights.push_front(w);
313 
314  } // end loop to fill signal raw digit vector and make EnergyDeposit associations
315 
316  // still one more digit to make because we ran out of channels to compare against
317  this->CreateSignalDigit(eDepIDEs.back().Channel,
318  electrons,
319  digitEDepLocs,
320  digitEDepWeights,
321  *rdCol,
322  eDepCol,
323  *erassn,
324  evt);
325 
326  MF_LOG_DEBUG("IonizationReadout")
327  << "Created "
328  << rdCol->size()
329  << " raw digits from signal";
330 
331  // now make the noise digits
332  // to do -- only make noise digits on channels we haven't
333  // yet considered for noise digits, but which may have
334  // been entirely zero-suppressed -- may need to keep a
335  // list of channels and pass it in
336  fROSimAlg->CreateNoiseDigits(*rdCol);
337 
338  } // end if the EdepIDEs have any size
339  } // end if there were energy deposits to use
340 
341  evt.put(std::move(rdCol));
342  evt.put(std::move(erassn));
343 
344  return;
345  } // IonizationReadout::produce()
346 
347  //--------------------------------------------------------------------------
348  void IonizationReadout::DriftElectronsToReadout(std::vector<sdp::EnergyDeposit> const& edepCol,
349  std::vector<edepIDE> & edepIDEs)
350  {
351  auto geo = gar::providerFrom<geo::GeometryGAr>();
352 
353  float xyz[3] = {0.};
354  unsigned int chan = 0;
355 
356  std::vector<edepIDE> edepIDEaccumulator;
357 
358  // now instantiate an ElectronDriftInfo object to keep track of the
359  // drifted locations of each electron cluster from each energy deposit
360  rosim::ElectronDriftInfo driftInfo;
361 
362  // loop over the energy deposits
363  for (size_t e = 0; e < edepCol.size(); ++e) {
364 
365  // get the positions, arrival times, and electron cluster sizes
366  // for this energy deposition
367  fDriftAlg->DriftElectronsToReadout(edepCol[e], driftInfo);
368 
369  // auto is vector<double> or vector<int> in the clusterSize case. Size of vector is
370  // number of clusters produced by DriftElectronsToReadout.
371  auto clusterXPos = driftInfo.ClusterXPos();
372  auto clusterYPos = driftInfo.ClusterYPos();
373  auto clusterZPos = driftInfo.ClusterZPos();
374  auto clusterTime = driftInfo.ClusterTime();
375  auto clusterSize = driftInfo.ClusterSize();
376 
377  // the vectors should all have the same size by the time we get them
378  // here (verified by the ElectronDriftInfo object when they are filled)
379  for (size_t c = 0; c < clusterXPos.size(); ++c) {
380 
381  xyz[0] = clusterXPos[c];
382  xyz[1] = clusterYPos[c];
383  xyz[2] = clusterZPos[c];
384 
385  // map the cluster's drift point to channels. Use the method that also gives
386  // us a list of neighboring channels.
387 
389  geo->NearestChannelInfo(xyz, cwn);
390 
391  // the first channel in the list is the nearest one to the xyz point
392  chan = cwn.at(0).id;
393 
394  // if charge is deposited on the cover electrodes or is otherwise in a gap, skip it
395 
396  if (chan == geo->GapChannelNumber()) continue;
397 
398  // incorporate pad response function.
399  // figure out what fraction of the charge of this cluster is to be deposted in each of the channels
400  // in chanset. Need to know if the channel is iroc, ioroc, ooroc, or hole-filler, and use the pad response functions
401 
402  TVector3 pos = cwn.at(0).pos;
403  TVector3 pproj(0,xyz[1],xyz[2]); // assume the pad planes are in the YZ plane
404 
405  std::vector<float> chanweight;
406  size_t ncdistrib = cwn.size();
407  if (!fUsePRF) ncdistrib = 1; // localize to just one channel if we aren't using the PRF
408  float sumw = 0;
409 
410  MF_LOG_DEBUG("IonizationReadout::DriftElectronsToReadout") << "pproj: " << pproj.Y() << " " << pproj.Z() << std::endl;
411  for (size_t icd=0; icd<ncdistrib; ++icd) {
412  TH2F *prfhist=0;
413  if (cwn.at(icd).roctype == gar::geo::HFILLER) {
414  prfhist = fHFILLPRF;
415  MF_LOG_DEBUG("IonizationReadout::DriftElectronsToReadout") << " hole filler" << std::endl;
416  } else if (cwn.at(icd).roctype == gar::geo::IROC) {
417  prfhist = fIROCPRF;
418  MF_LOG_DEBUG("IonizationReadout::DriftElectronsToReadout") << " iroc " << std::endl;
419  } else if (cwn.at(icd).roctype == gar::geo::IOROC) {
420  prfhist = fIOROCPRF;
421  MF_LOG_DEBUG("IonizationReadout::DriftElectronsToReadout") << " ioroc " << std::endl;
422  } else if (cwn.at(icd).roctype == gar::geo::OOROC) {
423  prfhist = fOOROCPRF;
424  MF_LOG_DEBUG("IonizationReadout::DriftElectronsToReadout") << " ooroc " << std::endl;
425  } else {
426  throw cet::exception("IonizationReadout::DriftElectronsToReadout") << "Ununderstood readout chamber type "
427  << cwn.at(icd).roctype << "\n";
428  }
429  TVector3 dproj = pproj - cwn.at(icd).pos;
430  dproj.SetX(0);
431  MF_LOG_DEBUG("IonizationReadout::DriftElectronsToReadout") << " Pad loc: " << cwn.at(icd).pos.Y() <<
432  " " << cwn.at(icd).pos.Z() << std::endl;
433 
434  float dist_along_padrow = dproj.Dot(cwn.at(icd).padrowdir);
435  float dist_perp_padrow = (dproj - dist_along_padrow*cwn.at(icd).padrowdir).Mag(); // assume symmetric PRF
436  MF_LOG_DEBUG("IonizationReadout::DriftElectronsToReadout") << "along, perp: " << dist_along_padrow <<
437  " " << dist_perp_padrow << std::endl;
438 
439  dist_along_padrow = TMath::Abs(dist_along_padrow);
440  if (dist_along_padrow < prfhist->GetXaxis()->GetBinUpEdge(prfhist->GetNbinsX()) &&
441  dist_perp_padrow < prfhist->GetYaxis()->GetBinUpEdge(prfhist->GetNbinsY())) {
442  chanweight.push_back(prfhist->GetBinContent(prfhist->FindBin(dist_along_padrow,dist_perp_padrow)));
443  } else {
444  chanweight.push_back(0);
445 
446  }
447  sumw += chanweight.back();
448  }
449 
450  if (sumw == 0) {
451  throw cet::exception("IonizationReadout::DriftElectronsToReadout") <<
452  "Weight sum is zero, even when including the closest channel " << std::endl;
453  }
454  float rsumw = 1.0/sumw;
455  for (size_t i=0; i<chanweight.size(); ++i) {
456  if (chanweight.at(i)>0 && clusterSize.at(c) > 0) {
457  edepIDEaccumulator.emplace_back(clusterSize.at(c)*chanweight.at(i)*rsumw,
458  cwn.at(i).id,
459  fTime->TPCG4Time2TDC(clusterTime.at(c)),
460  e, chanweight.at(i));
461  this->CheckChannelToEnergyDepositMapping(edepIDEaccumulator.back().Channel,
462  edepCol[e],
463  "DriftElectronsToReadout");
464  // compress as we go to save memory
465  if (edepIDEaccumulator.size() > 10000)
466  {
467  this->CombineIDEs(edepIDEaccumulator, edepCol);
468  edepIDEs.insert(edepIDEs.end(),edepIDEaccumulator.begin(),edepIDEaccumulator.end());
469  edepIDEaccumulator.clear();
470  }
471  }
472  }
473 
474  MF_LOG_DEBUG("IonizationReadout::DriftElectronsToReadout")
475  << "cluster time: "
476  << clusterTime[c]
477  << " TDC "
478  << fTime->TPCG4Time2TDC(clusterTime[c])
479  << " "
480  << fTime->G4ToElecTime(clusterTime[c])
481  << " "
482  << fTime->TPCClock().TickPeriod();
483 
484  }
485  } // end loop over deposit collections
486 
487  // one last collection of accumulated edepIDEs
488  edepIDEs.insert(edepIDEs.end(),edepIDEaccumulator.begin(),edepIDEaccumulator.end());
489  this->CombineIDEs(edepIDEs, edepCol);
490 
491  return;
492  }
493 
494  //--------------------------------------------------------------------------
495  void IonizationReadout::CombineIDEs(std::vector<edepIDE> & edepIDEs,
496  std::vector<sdp::EnergyDeposit> const& edepCol) {
497 
498  MF_LOG_DEBUG("IonizationReadout::CombineIDEs")
499  << "starting with "
500  << edepIDEs.size()
501  << " energy deposits";
502 
503  if (edepIDEs.size()==0) return;
504 
505  std::vector<edepIDE> temp;
506 
507  // sort the edepIDE objects. This is sorting by channel 1st & TDC
508  // 2nd via the < operator of edepIDE
509  std::sort(edepIDEs.begin(), edepIDEs.end());
510 
511  for(auto itr : edepIDEs){
512  for(auto edloc : itr.edepLocs) {
513  this->CheckChannelToEnergyDepositMapping(itr.Channel,
514  edepCol[edloc],
515  "CombineIDEsAfterSort");
516  }
517  }
518 
519  edepIDE prev = edepIDEs.front();
520  edepIDE sum(edepIDEs.front());
521  edepIDE cur(edepIDEs.front());
522 
523  // now loop over the sorted vector and combine any edepIDEs
524  // with the same channel and tdc values for the IDEs
525  // start with entry 1 as sum is already holding the information
526  // from entry 0
527  for (size_t e = 1; e < edepIDEs.size(); ++e) {
528  cur = edepIDEs[e];
529 
530  MF_LOG_DEBUG("IonizationReadout::CombineIDEs")
531  << "current edepIDE: "
532  << cur.NumElect
533  << " "
534  << cur.Channel
535  << " "
536  << cur.TDC
537  << " "
538  << cur.edepLocs.size();
539 
540  if (cur != prev) {
541  MF_LOG_DEBUG("IonizationReadout::CombineIDEs")
542  << "storing edepIDE sum: "
543  << sum.NumElect
544  << " "
545  << sum.Channel
546  << " "
547  << sum.TDC
548  << " "
549  << sum.edepLocs.size();
550 
551  if (fCheckChan) {
552  for (auto edloc : sum.edepLocs) {
553  this->CheckChannelToEnergyDepositMapping(sum.Channel,
554  edepCol[edloc],
555  "CombineIDEsStore");
556  }
557  }
558 
559  // put the summed edepIDE into the temp vector
560  temp.push_back(sum);
561 
562  // start over with a fresh sum
563  sum = cur;
564  prev = cur;
565 
566  } else {
567  MF_LOG_DEBUG("IonizationReadout::CombineIDEs")
568  << "summing current edepIDE";
569  sum += cur;
570  prev = cur;
571  }
572 
573  } // end loop to sum edepIDEs
574 
575  // now swap the input vector with the temp vector
576  temp.swap(edepIDEs);
577 
578  MF_LOG_DEBUG("IonizationReadout::CombineIDEs")
579  << "ending with "
580  << edepIDEs.size()
581  << " energy deposits";
582 
583  return;
584  }
585 
586  //--------------------------------------------------------------------------
588  std::vector<float> & electrons,
589  std::set<size_t> & eDepLocs,
590  std::deque<float> & eDepWeights,
591  std::vector<raw::RawDigit> & digCol,
592  ::art::ValidHandle< std::vector<sdp::EnergyDeposit> > & eDepCol,
594  ::art::Event & evt)
595  {
596 
597  // could be that all the adc's fell below threshold, so test if we got a raw digit at all.
598 
599  bool todrop=false;
600  raw::RawDigit tmpdigit = fROSimAlg->CreateRawDigit(channel, electrons, todrop);
601 
602  if (!todrop) {
603  digCol.emplace_back(tmpdigit);
604 
605  MF_LOG_DEBUG("IonizationReadout::CreateSignalDigit")
606  << "Associating "
607  << eDepLocs.size()
608  << " energy deposits to digit for channel "
609  << channel;
610 
611  // loop over the locations in the eDepCol to make the associations
612  size_t index = 0;
613  for (auto ed : eDepLocs) {
614  auto const ptr = art::Ptr<sdp::EnergyDeposit>(eDepCol, ed);
615 
616  this->CheckChannelToEnergyDepositMapping(channel, *ptr, "CreateSignalDigit");
617  MF_LOG_DEBUG("IonizationReadout::CreateSignalDigit")
618  << "Making association: " << digCol.size() << " " << ptr << std::endl;
619  util::CreateAssnD(*this, evt, digCol, ptr, eDepWeights.at(index), erassn);
620  index++;
621  }
622  }
623 
624  eDepLocs.clear();
625  eDepWeights.clear();
626  electrons.clear();
627  electrons.resize(fNumTicks, 0);
628 
629  return;
630  }
631 
632  //--------------------------------------------------------------------------
634  sdp::EnergyDeposit const& edep,
635  std::string const& id)
636  {
637  if (!fCheckChan) return;
638 
639  // check that the channel for this cluster is close to what we expect
640  // for the energy deposit
641 
642  float xyz[3] = {0.};
643  fGeo->ChannelToPosition(channel, xyz);
644 
645  if(std::abs(edep.Y() - xyz[1]) > 1 ||
646  std::abs(edep.Z() - xyz[2]) > 1){
647 
648  MF_LOG_DEBUG("IonizationReadout::CheckChannelToEnergyDepositMapping")
649  << "In function "
650  << id
651  << ": Channel "
652  << channel
653  << " is off from the energy deposit: ("
654  << xyz[1]
655  << ", "
656  << xyz[2]
657  << ") vs ("
658  << edep.Y()
659  << ", "
660  << edep.Z()
661  << ") " << std::endl;
662  }
663 
664  return;
665  }
666 
667  } // namespace rosim
668 
669  namespace rosim {
670 
672 
673  } // namespace rosim
674 } // gar
675 #endif // GAR_READOUTSIMULATION_IONIZATIONREADOUT
std::vector< gar::geo::ChanWithPos > ChanWithNeighbors
Definition: GeometryCore.h:91
TH2F * fIOROCPRF
pad response function for IOROC
base_engine_t & createEngine(seed_t seed)
bool fCheckChan
flag to check mapping of energy deposits to channels
std::vector< double > const & ClusterZPos() const
std::vector< double > const & ClusterYPos() const
std::string string
Definition: nybbler.cc:12
TH2F * fHFILLPRF
pad response function for hole-filler chamber
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
const gar::detinfo::DetectorClocks * fTime
electronics clock
float const & Z() const
Definition: EnergyDeposit.h:45
float const & Y() const
Definition: EnergyDeposit.h:44
std::unique_ptr< TPCReadoutSimAlg > fROSimAlg
algorithm to simulate the electronics
Description of geometry of one entire detector.
Definition: GeometryCore.h:436
void DriftElectronsToReadout(std::vector< sdp::EnergyDeposit > const &edepCol, std::vector< edepIDE > &edepIDEs)
uint8_t channel
Definition: CRTFragment.hh:201
std::vector< double > const & ClusterXPos() const
Definition: Run.h:17
double TickPeriod() const
A single tick period in nano-second, frequency is in MHz.
Definition: ElecClock.h:125
fhicl::ParameterSet fISCalcPars
parameter set for the IS calculator
T abs(T value)
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
string infile
bool CreateAssnD(PRODUCER const &prod, art::Event &evt, art::Assns< T, U, D > &assn, size_t first_index, size_t second_index, typename art::Assns< T, U, D >::data_t &&data)
Creates a single one-to-one association with associated data.
def move(depos, offset)
Definition: depos.py:107
virtual double G4ToElecTime(double g4_time) const =0
Given Geant4 time [ns], returns relative time [ns] w.r.t. electronics time T0.
T get(std::string const &key) const
Definition: ParameterSet.h:271
Runs Readout simulation including propagation of electrons and photons to readout.
bool fUsePRF
switch to turn on PRF modeling, otherwise just use the arrival pad
IonizationReadout(fhicl::ParameterSet const &pset)
Standard constructor and destructor for an FMWK module.
std::string fPRFFileName
where to find the pad response function histograms
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
std::string fG4Label
label of G4 module
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
static IonizationAndScintillation * CreateInstance(CLHEP::HepRandomEngine &engine, fhicl::ParameterSet const &pset)
virtual double TPCG4Time2TDC(double g4time) const =0
Given G4 time [ns], returns corresponding TPC electronics clock count [tdc].
size_t fNumTicks
number of TDC samples
const gar::geo::GeometryCore * fGeo
geometry information
void CombineIDEs(std::vector< edepIDE > &edepIDEs, std::vector< sdp::EnergyDeposit > const &edepCol)
General GArSoft Utilities.
void CheckChannelToEnergyDepositMapping(unsigned int const &channel, sdp::EnergyDeposit const &edep, std::string const &id)
TH2F * fOOROCPRF
pad response function for OOROC
std::unique_ptr< ElectronDriftAlg > fDriftAlg
algorithm to drift ionization electrons
#define MF_LOG_DEBUG(id)
virtual const ElecClock & TPCClock() const =0
Borrow a const TPC clock with time set to Trigger time [ns].
std::vector< double > const & ClusterTime() const
TH2F * fIROCPRF
pad response function for IROC
TCEvent evt
Definition: DataStructs.cxx:7
CLHEP::HepRandomEngine & fEngine
random engine
LArSoft geometry interface.
Definition: ChannelGeo.h:16
art framework interface to geometry description
void ChannelToPosition(unsigned int const channel, float *const worldLoc) const
static ServiceHandle< RandomNumberGenerator > & rng()
std::vector< int > const & ClusterSize() const
Definition: fwd.h:31
Collection of charge vs time digitized from a single readout channel.
Definition: RawDigit.h:67
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
void reconfigure(fhicl::ParameterSet const &pset)
void CreateSignalDigit(unsigned int const &channel, std::vector< float > &electrons, std::set< size_t > &eDepLocs, std::deque< float > &eDepWeights, std::vector< raw::RawDigit > &digCol,::art::ValidHandle< std::vector< sdp::EnergyDeposit > > &eDepCol,::art::Assns< sdp::EnergyDeposit, raw::RawDigit, float > &erassn,::art::Event &evt)