OpDetDigitizerProtoDUNE_module.cc
Go to the documentation of this file.
1 //=========================================================
2 // OpDetDigitizerProtoDUNE_module.cc
3 // This module produces digitized output
4 // (creating OpDetWaveform)
5 // from photon detectors taking SimPhotonsLite as input.
6 //
7 // Module specific for ProtoDUNE-SP to be able to use different QE for different PDs and other differences, if needed
8 // Created: 18/Jun/2021 - L. Paulucci
9 // Based on OpDetDigitizerDUNE_module.cc
10 // Modified:
11 //=========================================================
12 
13 #ifndef OpDetDigitizerProtoDUNE_h
14 #define OpDetDigitizerProtoDUNE_h
15 
16 // Framework includes
17 
25 #include "cetlib_except/exception.h"
26 #include "fhiclcpp/ParameterSet.h"
27 #include "art_root_io/TFileService.h"
28 #include "art_root_io/TFileDirectory.h"
30 
31 
32 
33 // ART extensions
34 #include "nurandom/RandomUtils/NuRandomService.h"
35 
36 // LArSoft includes
37 
50 
51 // CLHEP includes
52 
53 #include "CLHEP/Random/RandGauss.h"
54 #include "CLHEP/Random/RandExponential.h"
55 #include "CLHEP/Random/RandFlat.h"
56 
57 // C++ includes
58 
59 #include <vector>
60 #include <map>
61 #include <cmath>
62 #include <memory>
63 
64 // ROOT includes
65 
66 #include "TTree.h"
67 
68 
69 namespace opdet {
70 
71  class FocusList
72  {
73  public:
74  FocusList(int nSamples, int padding)
75  : fNSamples(nSamples), fPadding(padding) {}
76 
77  void AddRange(int from, int to)
78  {
79  from -= fPadding;
80  to += fPadding;
81 
82  if(from < 0) from = 0;
83  if(to >= fNSamples) to = fNSamples-1;
84 
85  for(unsigned int i = 0; i < ranges.size(); ++i){
86  std::pair<int, int>& r = ranges[i];
87  // Completely nested, discard
88  if(from >= r.first && to <= r.second) return;
89  // Extend end
90  if(from >= r.first && from <= r.second){
91  r.second = to;
92  return;
93  }
94  // Extend front
95  if(to >= r.first && to <= r.second){
96  r.first = from;
97  return;
98  }
99  }
100  // Discontiguous, add
101  ranges.emplace_back(from, to);
102  }
103 
104  std::vector<std::pair<int, int>> ranges;
105 
106  protected:
107  int fNSamples;
108  int fPadding;
109  };
110 
112 
113  public:
114 
116  // Should the destructor be empty?
117  // virtual ~OpDetDigitizerProtoDUNE();
118 
119  void produce(art::Event&);
120 
121  private:
122 
123  // The parameters read from the FHiCL file
124  std::vector<std::string> vInputModules;
125  std::set<std::string> fInputModules; // Input tag for OpDet collection
126  double fSampleFreq; // Sampling frequency in MHz
127  double fTimeBegin; // Beginning of waveform in us
128  double fTimeEnd; // End of waveform in us
129  double fVoltageToADC; // Conversion factor mV to ADC counts
130  double fLineNoiseRMS; // Pedestal RMS in ADC counts
131  double fDarkNoiseRate; // In Hz
132  double fCrossTalk; // Probability of SiPM producing 2 PE signal
133  // in response to 1 photon
134  short fPedestal; // In ADC counts
135  bool fDefaultSimWindow; // Set the start time to -1 drift window and
136  // the end time to the end time
137  // of the TPC readout
138  bool fFullWaveformOutput; // Output full waveforms -- produces large
139  // output. Mostly for debug purposes
140  size_t fReadoutWindow; // In ticks
141  size_t fPreTrigger; // In ticks
142 
143  int fPadding; // In ticks
144 
145  bool fDigiTree_SSP_LED; // To create a analysis Tree for SSP LED
146  bool fUseSDPs; // = pset.get< bool >("UseSDPs", true);
147 
148  double fQEOverride; //bars
149  // double fRefQEOverride; //Removed since there is no reflected light in ProtoDUNE-SP
152 
153  //-----------------------------------------------------
154  // Trigger analysis variables
155  std::vector<double> t_photon; // vitor
156  std::vector<int> op_photon;
157 
158  TTree *arvore2;
159  //-----------------------------------------------------
160 
161  // Threshold algorithm
162  std::unique_ptr< pmtana::AlgoSSPLeadingEdge > fThreshAlg;
163 
164  // Random number engines
165  std::unique_ptr< CLHEP::RandGauss > fRandGauss;
166  std::unique_ptr< CLHEP::RandExponential > fRandExponential;
167  std::unique_ptr< CLHEP::RandFlat > fRandFlat;
168 
169  // Function that adds n pulses to a waveform
170  void AddPulse(size_t timeBin, int scale,
171  std::vector< double >& waveform,
172  FocusList& fl) const;
173 
174  // Functional response to one photoelectron (time in ns)
175  double Pulse1PE(double time) const;
176 
177  // Single photoelectron pulse parameters
178  double fPulseLength; // 1PE pulse length in us
179  double fPeakTime; // Time when the pulse reaches its maximum in us
180  double fMaxAmplitude; // Maximum amplitude of the pulse in mV
181  double fFrontTime; // Constant in the exponential function
182  // of the leading edge in us
183  double fBackTime; // Constant in the exponential function
184  // of the tail in us
185 
186  // Make sure the FHiCL parameters make sense
187  void CheckFHiCLParameters() const;
188 
189  std::vector< double > fSinglePEWaveform;
190  void CreateSinglePEWaveform();
191 
192  // Produce waveform on one of the optical detectors
193  void CreatePDWaveform(art::Ptr<sim::OpDetBacktrackerRecord> const& btr_p,
194  geo::Geometry const& geometry,
195  std::vector< std::vector< double > >& pdWaveforms,
196  std::vector<FocusList>& fls,
197  sim::OpDetDivRec& DivRec,
198  bool Reflected);
199 
200  // Vary the pedestal
201  void AddLineNoise(std::vector< std::vector< double > >&,
202  const std::vector<FocusList>& fls) const;
203 
204  void AddDarkNoise(std::vector< std::vector< double > >&,
205  std::vector<FocusList>& fls) const;
206 
207  unsigned short CrossTalk() const;
208 
209  // Create a vector of shorts from a vector of doubles
210  // rounding it properly
211  std::vector< short > VectorOfDoublesToVectorOfShorts(std::vector< double > const&) const;
212 
213  // Make several shorter waveforms out of a long one using a hit finder,
214  // recording also when they start in the long waveform
215  std::map< size_t, std::vector< short > > SplitWaveform(std::vector< short > const&,
216  const FocusList&);
217 
218  double GetDriftWindow(detinfo::DetectorPropertiesData const& detProp) const;
219 
220  // Convert time to ticks or the other way around
221  // without any checks
222  double TickToTime(size_t tick) const;
223  size_t TimeToTick(double time) const;
224 
225 
226  bool Detected(int opDet, int &readoutChannel, bool Reflected);
227  };
228 
229 }
230 
231 #endif
232 
233 namespace opdet {
234 
236 
237 }
238 
239 namespace opdet {
240 
241  //---------------------------------------------------------------------------
242  // Constructor
244  : EDProducer{pset}
245  , vInputModules(pset.get< std::vector<std::string> >("InputModules"))
246  , fInputModules(vInputModules.begin(), vInputModules.end())
247  {
248 
249 
250  // Read the fcl-file
251 // auto tempvec =
252 // =
253  fVoltageToADC = pset.get< double >("VoltageToADC" );
254  fLineNoiseRMS = pset.get< double >("LineNoiseRMS" );
255  fDarkNoiseRate = pset.get< double >("DarkNoiseRate" );
256  fCrossTalk = pset.get< double >("CrossTalk" );
257  fPedestal = pset.get< short >("Pedestal" );
258  fDefaultSimWindow = pset.get< bool >("DefaultSimWindow" );
259  fFullWaveformOutput = pset.get< bool >("FullWaveformOutput");
260  fReadoutWindow = pset.get< size_t >("ReadoutWindow" );
261  fPreTrigger = pset.get< size_t >("PreTrigger" );
262 
263  fPadding = pset.get< int >("Padding" );
264 
265  fPulseLength = pset.get< double >("PulseLength" );
266  fPeakTime = pset.get< double >("PeakTime" );
267  fMaxAmplitude = pset.get< double >("MaxAmplitude" );
268  fFrontTime = pset.get< double >("FrontTime" );
269  fBackTime = pset.get< double >("BackTime" );
270  fDigiTree_SSP_LED = pset.get< bool >("SSP_LED_DigiTree" );
271  fUseSDPs = pset.get< bool >("UseSDPs", true );
272 
273  if (!fUseSDPs) {
274  throw art::Exception(art::errors::UnimplementedFeature) << "SimPhotonsLite is now deprecated in favor SDPs. If you do not have SDPs because your input file is old, use an older version of dunetpc to run this digitizer";
275  }
276 
277  // Replace QE with effective area. Get area from OpDet geometry
278  double tempQE = pset.get< double >("QEOverride", 0 );
279  double tempQEArapucaBeam = pset.get< double >("QEArapucaBeamOverride", 0 );
280  double tempQEArapucaNonBeam = pset.get< double >("QEArapucaNonBeamOverride", 0 );
281 
282  fQEOverride = 0;
285 
286  if (tempQE > 0) {
287  mf::LogInfo("OpDetDigitizerProtoDUNE") << "Overriding QE. All the functions of OpDetResponseService being ignored.";
288 
289  // Correct out the prescaling applied during simulation
290  auto const *LarProp = lar::providerFrom<detinfo::LArPropertiesService>();
291  fQEOverride = tempQE / LarProp->ScintPreScale();
292 
293  if (fQEOverride > 1.0001) {
294  mf::LogError("OpDetDigitizerProtoDUNE") << "Quantum efficiency set as OpDetDigitizerProtoDUNE.QEOverride, " << tempQE
295  << " is too large. It is larger than the prescaling applied during simulation, "
296  << LarProp->ScintPreScale()
297  << " (fQEOverride = " << fQEOverride
298  << "). Final QE must be equal to or smaller than the QE applied at simulation time.";
299  std::abort();
300  }
301  }
302 
303  if (tempQEArapucaBeam > 0) {
304  mf::LogInfo("OpDetDigitizerProtoDUNE") << "Overriding QE. All the functions of OpDetResponseService being ignored.";
305 
306  // Correct out the prescaling applied during simulation
307  auto const *LarProp = lar::providerFrom<detinfo::LArPropertiesService>();
308  fQEArapucaBeamOverride = tempQEArapucaBeam / LarProp->ScintPreScale();
309 
310  if (fQEArapucaBeamOverride > 1.0001) {
311  mf::LogError("OpDetDigitizerProtoDUNE") << "Quantum efficiency set as OpDetDigitizerProtoDUNE.QEOverride, " << tempQEArapucaBeam
312  << " is too large. It is larger than the prescaling applied during simulation, "
313  << LarProp->ScintPreScale()
314  << " fQEArapucaBeamOverride = " << fQEArapucaBeamOverride
315  << "). Final QE must be equal to or smaller than the QE applied at simulation time.";
316  std::abort();
317  }
318  }
319  if (tempQEArapucaNonBeam > 0) {
320  mf::LogInfo("OpDetDigitizerProtoDUNE") << "Overriding QE. All the functions of OpDetResponseService being ignored.";
321 
322  // Correct out the prescaling applied during simulation
323  auto const *LarProp = lar::providerFrom<detinfo::LArPropertiesService>();
324  fQEArapucaNonBeamOverride = tempQEArapucaNonBeam / LarProp->ScintPreScale();
325 
326  if (fQEArapucaNonBeamOverride > 1.0001) {
327  mf::LogError("OpDetDigitizerProtoDUNE") << "Quantum efficiency set as OpDetDigitizerProtoDUNE.QEOverride, " << tempQEArapucaNonBeam
328  << " is too large. It is larger than the prescaling applied during simulation, "
329  << LarProp->ScintPreScale()
330  << " fQEArapucaNonBeamOverride = " << fQEArapucaNonBeamOverride
331  << "). Final QE must be equal to or smaller than the QE applied at simulation time.";
332  std::abort();
333  }
334  }
335 
336  fThreshAlg = std::make_unique< pmtana::AlgoSSPLeadingEdge >
337  (pset.get< fhicl::ParameterSet >("algo_threshold"));
338 
339  if(fDigiTree_SSP_LED){
341  arvore2 = tfs->make<TTree>("PhotonData", "Photon_analysis");
342  arvore2->Branch("photon_opCh",&op_photon);
343  arvore2->Branch("photon_pulse",&t_photon);
344  }
345 
346  // This module produces (infrastructure piece)
347  produces< std::vector< raw::OpDetWaveform > >();
348  produces<std::vector<sim::OpDetDivRec> > ();
349 
350 
351  // Obtaining parameters from the DetectorClocksService
352  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
353  fSampleFreq = clockData.OpticalClock().Frequency();
354 
355  if (fDefaultSimWindow)
356  {
357  auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob(clockData);
358 
359  // Assume the readout starts at -1 drift window
360  fTimeBegin = -1*GetDriftWindow(detProp);
361 
362  // Take the TPC readout window size and convert
363  // to us with the electronics clock frequency
364  fTimeEnd = detProp.ReadOutWindowSize() / clockData.TPCClock().Frequency();
365  }
366  else
367  {
368  fTimeBegin = pset.get< double >("TimeBegin");
369  fTimeEnd = pset.get< double >("TimeEnd" );
370  }
371 
373 
374  // Initializing random number engines
375  unsigned int seed = pset.get< unsigned int >("Seed", sim::GetRandomNumberSeed());
376  auto& engine = createEngine(seed);
377  fRandGauss = std::make_unique< CLHEP::RandGauss >(engine);
378  fRandExponential = std::make_unique< CLHEP::RandExponential >(engine);
379  fRandFlat = std::make_unique< CLHEP::RandFlat >(engine);
380 
381  // Creating a single photoelectron waveform
382  // Hardcoded, probably need to read them from the FHiCL file
383  //fPulseLength = 4.0;
384  //fPeakTime = 0.260;
385  //fMaxAmplitude = 0.12;
386  //fFrontTime = 0.009;
387  //fBackTime = 0.476;
389 
390  }
391 
392  //---------------------------------------------------------------------------
394  {
395 
397 
398  // A pointer that will store produced OpDetWaveforms
399  // std::unique_ptr< std::vector< raw::OpDetWaveform > >
400  // std::make_unique< std::vector< raw::OpDetWaveform > >());
401  auto wave_forms_p = std::make_unique< std::vector< raw::OpDetWaveform > >();
402  auto bt_DivRec_p = std::make_unique< std::vector< sim::OpDetDivRec > >();
403 
404 
405  // Total number of ticks in the full waveform
406  // Including one pretrigger window before the waveform
407  // and one readout window - pretrigger window after the waveform
408  unsigned int nSamples = (fTimeEnd - fTimeBegin)*fSampleFreq
409  + fReadoutWindow;
410 
411  // Geometry service
413 
414  auto const btr_handles = evt.getMany<std::vector<sim::OpDetBacktrackerRecord>>();
415 
416  if (btr_handles.size() == 0)
417  throw art::Exception(art::errors::ProductNotFound)<<"No OpDetBacktrackerRecords retrieved.";
418 
419  for (auto btr_handle: btr_handles) {
420  // Do some checking before we proceed
421  if (!btr_handle.isValid()) continue;
422  if (!fInputModules.count(btr_handle.provenance()->moduleLabel())) continue;
423 
424  bool Reflected = (btr_handle.provenance()->productInstanceName() == "Reflected");
425 
426 
427  std::vector<art::Ptr<sim::OpDetBacktrackerRecord>> btr_vec;
428  art::fill_ptr_vector(btr_vec, btr_handle);
429 
430 
431  // For every optical detector:
432  for (auto const& btr : btr_vec)
433  {
434  int opDet = btr->OpDetNum();
435  //unsigned int opDet = btr->OpDetNum();
436 
437  // Get number of channels in this optical detector
438  unsigned int nChannelsPerOpDet = geometry->NOpHardwareChannels(opDet);
439 
440  std::vector<FocusList> fls(nChannelsPerOpDet, FocusList(nSamples, fPadding));
441  //std::vector<sim::OpDetDivRec> DivRec;
442  sim::OpDetDivRec DivRec(opDet);
443  //DivRec.chans.resize(nChannelsPerOpDet);
444 
445  // This vector stores waveforms created for each optical channel
446  std::vector< std::vector< double > > pdWaveforms(nChannelsPerOpDet,
447  std::vector< double >(nSamples, static_cast< double >(fPedestal)));
448 
449  CreatePDWaveform(btr, *geometry, pdWaveforms, fls, DivRec, Reflected);
450  //DivRec comes out with all of the ticks filled correctly, with each channel filled in it's map.
451  //Break here to investigate div recs as they are made and compare them to btrs
452 
453 
454  // Generate dark noise //I will not at this time include dark noise in my split backtracking records.
455  if (fDarkNoiseRate > 0.0) AddDarkNoise(pdWaveforms, fls);
456 
457  // Uncomment to undo the effect of FocusLists. Replaces the accumulated
458  // lists with ones asserting we need to look at the whole trace.
459  // for(FocusList& fl: fls){
460  // fl.ranges.clear();
461  // fl.ranges.emplace_back(0, nSamples-1);
462  // }
463 
464  // Vary the pedestal
465  if (fLineNoiseRMS > 0.0) AddLineNoise(pdWaveforms, fls);
466 
467  // Loop over all the created waveforms, split them into shorter
468  // waveforms and use them to initialize OpDetWaveforms
469  for (unsigned int hardwareChannel = 0;
470  hardwareChannel < nChannelsPerOpDet; ++hardwareChannel)
471  {
472  for(const std::pair<int, int>& p: fls[hardwareChannel].ranges){
473  // It's a shame we copy here. We could actually avoid by making the
474  // functions below take a begin()/end() pair.
475  const std::vector<double> sub(pdWaveforms[hardwareChannel].begin()+p.first,
476  pdWaveforms[hardwareChannel].begin()+p.second+1);
477 
478  std::vector< short > waveformOfShorts = VectorOfDoublesToVectorOfShorts(sub);
479 
480  std::map< size_t, std::vector < short > > mapTickWaveform =
482  SplitWaveform(waveformOfShorts, fls[hardwareChannel]) :
483  std::map< size_t, std::vector< short > >{ std::make_pair(0,
484  waveformOfShorts) };
485 
486  unsigned int opChannel = geometry->OpChannel(opDet, hardwareChannel);
487 
488  for (auto const& pairTickWaveform : mapTickWaveform)
489  {
490  double timeStamp =
491  static_cast< double >(TickToTime(pairTickWaveform.first+p.first));
492 
493  raw::OpDetWaveform adcVec(timeStamp, opChannel,
494  pairTickWaveform.second.size());
495 
496  for (short const& value : pairTickWaveform.second){
497  adcVec.emplace_back(value);
498  }
499 
500  // wave_forms_p->emplace_back(std::move(adcVec));
501  wave_forms_p->push_back(std::move(adcVec));
502  //art::Ptr< raw::OpDetWaveform > wave_form_p = make_wave_form_ptr(wave_forms_p->size()-1);
503  //bt_wave_assns->addSingle(btr, wave_form_p, DivRec/*DIVREC*/);
504  }
505  }
506  }
507  bt_DivRec_p->push_back(std::move(DivRec));
508  }
509  }
510 
511  if(fDigiTree_SSP_LED){
512  arvore2->Fill();
513  t_photon.clear();
514  op_photon.clear();
515  }
516 
517 
518  // Push the OpDetWaveforms into the event
519  evt.put(std::move(wave_forms_p));
520  if(fUseSDPs){ evt.put(std::move(bt_DivRec_p));}
521 
522 
523  }
524 
525  //---------------------------------------------------------------------------
527  int scale, std::vector< double >& waveform,
528  FocusList& fl) const
529  {
530 
531  // How many bins will be changed
532  size_t pulseLength = fSinglePEWaveform.size();
533  if ((timeBin + fSinglePEWaveform.size()) > waveform.size())
534  pulseLength = (waveform.size() - timeBin);
535 
536  fl.AddRange(timeBin, timeBin+pulseLength-1);
537 
538  // Adding a pulse to the waveform
539  for (size_t tick = 0; tick != pulseLength; ++tick)
540  waveform[timeBin + tick] += scale*fSinglePEWaveform[tick];
541 
542  }
543 
544  //---------------------------------------------------------------------------
546  {
547 
548  if (time < fPeakTime) return
549  (fVoltageToADC*fMaxAmplitude*std::exp((time - fPeakTime)/fFrontTime));
550  else return
551  (fVoltageToADC*fMaxAmplitude*std::exp(-(time - fPeakTime)/fBackTime));
552 
553  }
554 
555  //---------------------------------------------------------------------------
557  {
558 
559  size_t length =
560  static_cast< size_t > (std::round(fPulseLength*fSampleFreq));
561  fSinglePEWaveform.resize(length);
562  for (size_t tick = 0; tick != length; ++tick)
564  Pulse1PE(static_cast< double >(tick)/fSampleFreq);
565 
566  }
567 
568  //---------------------------------------------------------------------------
571  geo::Geometry const& geometry,
572  std::vector< std::vector< double > >& pdWaveforms,
573  std::vector<FocusList>& fls,
574  sim::OpDetDivRec& DivRec,
575  bool Reflected)
576  {
577 
578  int const opDet = btr_p->OpDetNum();
579  //unsigned int const opDet = btr_p->OpDetNum();
580  // This is int because otherwise detectedLite doesn't work
581  int readoutChannel;
582  // For a group of photons arriving at the same time this is a map
583  // of < arrival time (in ns), number of photons >
584  // std::map< int, int > const& photonsMap = litePhotons.DetectedPhotons;
585  //sim::timePDclockSDPs_t time_sdps_vector = btr_p->timePDclockSDPsMap();
586  //int time_sdps_vector = btr_p->timePDclockSDPsMap();
587  auto time_sdps_vector = btr_p->timePDclockSDPsMap();
588  /*
589  for(auto& divchan : DivRec.chans){
590  if(divchan.tick_photons_frac.size()<time_sdps_vector.size())
591  divchan.tick_photons_frac.resize(time_sdps_vector.size(), 0.0);
592  }*/
593 
594  // For every pair of (arrival time, number of photons) in the map:
595  //for (auto const& pulse : photonsMap)
596  //for (auto const& time_sdps : time_sdps_vector)
597  for (size_t i = 0; i<time_sdps_vector.size(); ++i) //I is now the time bin.
598  {
599  auto time_sdps = time_sdps_vector[i];
600  // Converting ns to us
601  // double photonTime = static_cast< double >(time_sdps.first)/1000.0;
602  //Really need to do something better here. This conversion is fragile, and makes the populating of the DivRecs confusing.
603  double photonTime = time_sdps.first/1000.0;//This should be done with the timing service
604  //for (int i = 0; i < pulse.second; ++i)
605  //for (size_t i = 0; i < time_sdps.second.size(); ++i)
606  for (auto const& sdp : time_sdps.second)
607  {
608  int tid = sdp.trackID;
609  for(int j=0; j<sdp.numPhotons;++j)
610  {
611  if ((photonTime >= fTimeBegin) && (photonTime < fTimeEnd))
612  {
613  // Sample a random subset according to QE
614  if ( Detected(opDet, readoutChannel, Reflected) )
615  {
616  unsigned int hardwareChannel =
617  geometry.HardwareChannelFromOpChannel(readoutChannel);
618  // Convert the time of the pulse to ticks
619  size_t timeBin = TimeToTick(photonTime);
620  // Add 1 pulse to the waveform
621  AddPulse(timeBin, CrossTalk(), pdWaveforms.at(hardwareChannel), fls[hardwareChannel]);
622 
623  unsigned int opChannel = geometry.OpChannel(opDet, hardwareChannel);
624  //Set/find tick. Set/find Channel
625  sim::OpDet_Time_Chans::stored_time_t tmp_time=time_sdps.first;
626  DivRec.AddPhoton(opChannel, tid, tmp_time);
627  if(fDigiTree_SSP_LED){
628  op_photon.emplace_back(opChannel);
629  t_photon.emplace_back(photonTime); //vitor: devo usar o time ou o tick?
630  }
631  }//else{
632  /* unsigned int hardwareChannel =
633  geometry.HardwareChannelFromOpChannel(readoutChannel);
634  unsigned int opChannel = geometry.OpChannel(opDet, hardwareChannel);
635  DivRec.tick_chans[i].DivChans.IfNotInit(opChannel);
636  }*/
637  }
638  // else
639  // remove this as it fills up logfiles for cosmic-ray runs
640  //mf::LogInfo("OpDetDigitizerProtoDUNE")
641  // << "Throwing away an out-of-time photon at " << photonTime << '\n';
642  }
643  }//end of this sdp.
644  /*double total=0.0; //This section is no longer needed. I store the un-normalized values, and normalize them at retrieval.
645  for(auto it=DivRec.tick_chans[i].DivChans.bit(); it!= DivRec.tick_chans[i].DivChans.lit(); ++it)
646  { //With a bit of work, we could avoid this loop by remembering this number from above.
647  total+=it->second.tick_photons_frac;
648  }
649  for(auto chan : DivRec.tick_chans[i].DivChans.chans())
650  {
651  DivRec.tick_chans[i].DivChans.NormPhotonFrac(chan, total);
652  }
653  total=0.0; // This isn't actually needed.*/
654  }//End this time tick.
655 
656  }
657 
658  //---------------------------------------------------------------------------
660  AddLineNoise(std::vector< std::vector< double > >& waveforms,
661  const std::vector<FocusList>& fls) const
662  {
663  int i = 0;
664  for(auto& waveform : waveforms){
665  for(unsigned int j = 0; j < fls[i].ranges.size(); ++j){
666  const std::pair<int, int>& p = fls[i].ranges[j];
667  for(int k = p.first; k <= p.second; ++k){
668  waveform[k] += fRandGauss->fire(0, fLineNoiseRMS);
669  }
670  }
671 
672  ++i;
673  }
674  }
675 
676  //---------------------------------------------------------------------------
678  AddDarkNoise(std::vector< std::vector< double > >& waveforms,
679  std::vector<FocusList>& fls) const
680  {
681  int i = 0;
682  for (auto& waveform : waveforms)
683  {
684  // Multiply by 10^6 since fDarkNoiseRate is in Hz
685  double darkNoiseTime = static_cast< double >(fRandExponential->
686  fire(1.0/fDarkNoiseRate)*1000000.0) + fTimeBegin;
687  while (darkNoiseTime < fTimeEnd)
688  {
689  size_t timeBin = TimeToTick(darkNoiseTime);
690  AddPulse(timeBin, CrossTalk(), waveform, fls[i]);
691  // Find next time to simulate a single PE pulse
692  darkNoiseTime += static_cast< double >
693  (fRandExponential->fire(1.0/fDarkNoiseRate)*1000000.0);
694  }
695 
696  ++i;
697  }
698  }
699 
700  //---------------------------------------------------------------------------
701  unsigned short OpDetDigitizerProtoDUNE::CrossTalk() const
702  {
703  // Sometimes this should produce 3 or more PEs (not implemented)
704  if (fCrossTalk <= 0.0) return 1;
705  else if (fRandFlat->fire(1.0) > fCrossTalk) return 1;
706  else return 2;
707  }
708 
709  //---------------------------------------------------------------------------
711  (std::vector< double > const& vectorOfDoubles) const
712  {
713  // Don't bother to round properly, it's faster this way
714  return std::vector<short>(vectorOfDoubles.begin(), vectorOfDoubles.end());
715 
716  /*
717  std::vector< short > vectorOfShorts;
718  vectorOfShorts.reserve(vectorOfDoubles.size());
719 
720  for (short const& value : vectorOfDoubles)
721  vectorOfShorts.emplace_back(static_cast< short >(std::round(value)));
722 
723  return vectorOfShorts;
724  */
725  }
726 
727  //---------------------------------------------------------------------------
728  std::map< size_t, std::vector< short > > OpDetDigitizerProtoDUNE::
729  SplitWaveform(std::vector< short > const& waveform,
730  const FocusList& fls)
731  {
732 
733  std::map< size_t, std::vector< short > > mapTickWaveform;
734 
735  ::pmtana::PedestalMean_t ped_mean (waveform.size(),0);
736  ::pmtana::PedestalSigma_t ped_sigma(waveform.size(),0);
737 
738  fThreshAlg->Reconstruct(waveform,ped_mean,ped_sigma);
739 
740  std::vector< pmtana::pulse_param > pulses;
741  for (size_t pulseCounter = 0; pulseCounter < fThreshAlg->GetNPulse();
742  ++pulseCounter)
743  pulses.emplace_back(fThreshAlg->GetPulse(pulseCounter));
744 
745  // We have to refine this algorithm later
746  for (pmtana::pulse_param const& pulse : pulses)
747  {
748  if (pulse.t_end <= pulse.t_start)
749  // Can I call it a logic error?
751  << "Pulse ends before or at the same time it starts!\n";
752 
754  waveform.begin() + static_cast< size_t >(pulse.t_start);
756  waveform.begin() + static_cast< size_t >(pulse.t_end );
757  mapTickWaveform.emplace(static_cast< size_t >(pulse.t_start),
758  std::vector< short >(window_start, window_end));
759  // Don't forget to check that the time output by the (new) algortihm
760  // is < fTimeEnd and > fTimeBegin!
761 
762  }
763 
764  return mapTickWaveform;
765 
766  }
767 
768  //---------------------------------------------------------------------------
770  {
771 
772  double driftWindow;
773 
774  double maxDrift = 0.0;
775  for (geo::TPCGeo const& tpc :
776  art::ServiceHandle< geo::Geometry >()->IterateTPCs())
777  if (maxDrift < tpc.DriftDistance()) maxDrift = tpc.DriftDistance();
778 
779  driftWindow = maxDrift/detProp.DriftVelocity();
780 
781  return driftWindow;
782 
783  }
784 
785  //---------------------------------------------------------------------------
787  {
788 
789  if (tick > fPreTrigger)
790  return (static_cast< double >(tick - fPreTrigger)/fSampleFreq
791  + fTimeBegin);
792  else
793  return (static_cast< double >(fPreTrigger - tick)/fSampleFreq*(-1.0)
794  + fTimeBegin);
795 
796  }
797 
798  //---------------------------------------------------------------------------
800  {
801 
802  return static_cast< size_t >(std::round((time - fTimeBegin)*fSampleFreq
803  + fPreTrigger));
804 
805  }
806 
807  //---------------------------------------------------------------------------
809  {
810 
811  // Are all these logic errors?
812 
813  if (fLineNoiseRMS < 0.0)
815  << "fLineNoiseRMS: " << fLineNoiseRMS << '\n'
816  << "Line noise RMS should be non-negative!\n";
817 
818  if (fDarkNoiseRate < 0.0)
820  << "fDarkNoiseRate: " << fDarkNoiseRate << '\n'
821  << "Dark noise rate should be non-negative!\n";
822 
825  << "PreTrigger: " << fPreTrigger << " and "
826  << "ReadoutWindow: " << fReadoutWindow << '\n'
827  << "Pretrigger window has to be shorter than readout window!\n";
828 
829  if (fTimeBegin >= fTimeEnd)
831  << "TimeBegin: " << fTimeBegin << " and "
832  << "TimeEnd: " << fTimeEnd << '\n'
833  << "TimeBegin should be less than TimeEnd!\n";
834 
835  }
836 
837  //---------------------------------------------------------------------------
838  bool OpDetDigitizerProtoDUNE::Detected(int OpDet, int &readoutChannel, bool Reflected) {
839 
840  if ( (!Reflected && fQEOverride > 0) ) {
841  // Find the Optical Detector using the geometry service
843 
844  // Here OpDet must be opdet since we are introducing
845  // channel mapping here.
846  float NOpHardwareChannels = geom->NOpHardwareChannels(OpDet);
847  int hardwareChannel = (int) ( CLHEP::RandFlat::shoot(1.0) * NOpHardwareChannels );
848  readoutChannel = geom->OpChannel(OpDet, hardwareChannel);
849 
850  // Check QE
851  if (OpDet>28 && OpDet<45) { //Arapucas on APA 6
852  if ( CLHEP::RandFlat::shoot(1.0) > fQEArapucaNonBeamOverride ) return false;
853  }
854  else {
855  if (OpDet>44 && OpDet<61) { //Arapucas on APA 3
856  if ( CLHEP::RandFlat::shoot(1.0) > fQEArapucaBeamOverride ) return false;
857  }
858  else{ //bars
859  if ( CLHEP::RandFlat::shoot(1.0) > fQEOverride ) return false;
860  }
861  }
862  return true;
863  }
864  else {
866  // Service for determining optical detector responses
867  return odResponse->detectedLite(OpDet, readoutChannel);
868  }
869  }
870 
871 
872 }
void AddDarkNoise(std::vector< std::vector< double > > &, std::vector< FocusList > &fls) const
base_engine_t & createEngine(seed_t seed)
Store parameters for running LArG4.
std::vector< double > PedestalSigma_t
FocusList(int nSamples, int padding)
void AddRange(int from, int to)
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
bool Detected(int opDet, int &readoutChannel, bool Reflected)
std::unique_ptr< CLHEP::RandGauss > fRandGauss
std::unique_ptr< CLHEP::RandFlat > fRandFlat
Geometry information for a single TPC.
Definition: TPCGeo.h:38
struct vector vector
double GetDriftWindow(detinfo::DetectorPropertiesData const &detProp) const
unsigned int NOpHardwareChannels(int opDet) const
intermediate_table::const_iterator const_iterator
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
OpDetDigitizerProtoDUNE(fhicl::ParameterSet const &)
std::vector< std::pair< int, int > > ranges
Simulation objects for optical detectors.
int OpDetNum() const
Returns the readout Optical Detector this object describes.
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
std::vector< short > VectorOfDoublesToVectorOfShorts(std::vector< double > const &) const
unsigned int HardwareChannelFromOpChannel(int opChannel) const
Convert unique channel to hardware channel.
std::vector< Handle< PROD > > getMany(SelectorBase const &selector=MatchAllSelector{}) const
Definition: DataViewImpl.h:479
def move(depos, offset)
Definition: depos.py:107
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
p
Definition: test.py:223
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
double DriftVelocity(double efield=0., double temperature=0.) const
cm/us
The geometry of one entire detector, as served by art.
Definition: Geometry.h:196
std::map< size_t, std::vector< short > > SplitWaveform(std::vector< short > const &, const FocusList &)
virtual bool detectedLite(int OpChannel, int &newOpChannel) const
unsigned int OpChannel(int detNum, int hardwareChannel) const
Convert detector number and hardware channel to unique channel.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
unsigned int GetRandomNumberSeed()
Definition: sim.h:32
void AddLineNoise(std::vector< std::vector< double > > &, const std::vector< FocusList > &fls) const
void CreatePDWaveform(art::Ptr< sim::OpDetBacktrackerRecord > const &btr_p, geo::Geometry const &geometry, std::vector< std::vector< double > > &pdWaveforms, std::vector< FocusList > &fls, sim::OpDetDivRec &DivRec, bool Reflected)
Index NOpHardwareChannels(Index opDet)
std::unique_ptr< pmtana::AlgoSSPLeadingEdge > fThreshAlg
std::unique_ptr< CLHEP::RandExponential > fRandExponential
void AddPulse(size_t timeBin, int scale, std::vector< double > &waveform, FocusList &fl) const
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
Tools and modules for checking out the basics of the Monte Carlo.
TCEvent evt
Definition: DataStructs.cxx:7
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:297
std::vector< double > PedestalMean_t
timePDclockSDPs_t const & timePDclockSDPsMap() const
Returns all the deposited energy information as stored.
void AddPhoton(int opchan, int tid, OpDet_Time_Chans::stored_time_t pdTime)
Definition: OpDetDivRec.cxx:25
std::string sub(const std::string &a, const std::string &b)
Definition: TruthText.cxx:100