All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRTDetSimAlg.cxx
Go to the documentation of this file.
1 #ifndef SBND_CRTDETSIMALG_CC
2 #define SBND_CRTDETSIMALG_CC
3 
5 
6 namespace sbnd {
7 namespace crt {
8 
9  CRTDetSimAlg::CRTDetSimAlg(const Parameters & params, CLHEP::HepRandomEngine& engine, double g4RefTime)
10  : fParams(params())
11  , fEngine(engine)
12  , fG4RefTime(g4RefTime)
13  {
16 
17  fTaggers.clear();
18  fData.clear();
19  fAuxData.clear();
20  }
21 
22 
24 
25  std::vector<double> wvf_x = fParams.WaveformX();
26  std::vector<double> wvf_y = fParams.WaveformY();
27 
28  // Normalize the waveform
29  float max_y = *std::max_element(std::begin(wvf_y), std::end(wvf_y));
30  for (auto & y : wvf_y) y /= max_y;
31 
32  // Reverse the waveform, as we are only interested to use it to
33  // estimate its effect on time delays.
34  std::reverse(wvf_y.begin(),wvf_y.end());
35 
36  fInterpolator = std::make_unique<ROOT::Math::Interpolator>
37  (wvf_y.size(), ROOT::Math::Interpolation::kLINEAR);
38 
39  fInterpolator->SetData(wvf_x, wvf_y);
40 
41  }
42 
44  {
46  {
48  mf::LogInfo("CRTDetSimAlg") << "Configured to use G4 ref time as time offset: "
49  << fTimeOffset << " ns." << std::endl;
50  }
51  else
52  {
54  mf::LogInfo("CRTDetSimAlg") << "Configured to use GlobalT0Offset as time offset: "
55  << fTimeOffset << " ns." << std::endl;
56  }
57  }
58 
59  std::vector<std::pair<sbnd::crt::FEBData, std::vector<AuxDetIDE>>> CRTDetSimAlg::GetData()
60  {
61  return fData;
62  }
63 
64  std::vector<std::vector<int>> CRTDetSimAlg::GetAuxData()
65  {
66  return fAuxData;
67  }
68 
69 
70 
71  uint16_t CRTDetSimAlg::WaveformEmulation(const uint32_t & time_delay, const double & adc)
72  {
73 
75  {
76  return static_cast<uint16_t>(adc);
77  }
78 
79  if (time_delay < 0)
80  {
81  throw art::Exception(art::errors::LogicError)
82  << "Time delay cannot be negative for waveform emulation to happen." << std::endl;
83  }
84 
85  if (time_delay > fParams.WaveformX().back())
86  {
87  // If the time delay is more than the waveform rise time, we
88  // will never be able to see this signal. So return a 0 ADC value.
89  return 0;
90  }
91 
92  // Evaluate the waveform
93  double wf = fInterpolator->Eval(time_delay);
94  wf *= adc;
95 
96  if (fParams.DebugTrigger()) std::cout << "WaveformEmulation, time_delay " << time_delay
97  << ", adc " << adc
98  << ", waveform " << wf << std::endl;
99 
100  return static_cast<uint16_t>(wf);
101  }
102 
103 
105  const int & sipmID, const uint16_t & adc)
106  {
107  uint16_t original_adc = feb_data.ADC(sipmID);
108  uint16_t new_adc = original_adc + adc;
109 
110  if (new_adc > fParams.AdcSaturation())
111  {
112  new_adc = fParams.AdcSaturation();
113  }
114 
115  feb_data.SetADC(sipmID, new_adc);
116 
117  if (fParams.DebugTrigger()) std::cout << "Updating ADC value for FEB " << feb_data.Mac5()
118  << ", sipmID " << sipmID
119  << " with adc " << adc
120  << ": was " << original_adc
121  << ", now is " << feb_data.ADC(sipmID) << std::endl;
122 
123  }
124 
125 
126 
127 
128  void CRTDetSimAlg::ProcessStrips(const std::vector<StripData> & strips)
129  {
130  std::map<uint16_t, sbnd::crt::FEBData> mac_to_febdata;
131  std::map<uint16_t, std::vector<AuxDetIDE>> mac_to_ides;
132  std::map<uint16_t, std::vector<int>> mac_to_sipmids;
133 
134  // TODO Add pedestal fluctuations
135  std::array<uint16_t, 32> adc_pedestal = {static_cast<uint16_t>(fParams.QPed())};
136 
137  for (auto & strip : strips)
138  {
139 
140  // First time we encounter this FEB...
141  if (!mac_to_febdata.count(strip.mac5))
142  {
143  // Construct a new FEBData object with only pedestal values (will be filled later)
144  mac_to_febdata[strip.mac5] = sbnd::crt::FEBData(strip.mac5, // FEB ID
145  strip.sipm0.t0, // Ts0
146  strip.sipm0.t1, // Ts1
147  adc_pedestal, // ADCs
148  strip.sipm0.sipmID); // Coinc
149 
150  mac_to_ides[strip.mac5] = std::vector<AuxDetIDE>();
151  mac_to_sipmids[strip.mac5] = std::vector<int>();
152  }
153  // ... all the other times we encounter this FEB
154  else
155  {
156  // We want to save the earliest t1 and t0 for each FEB.
157  if (strip.sipm0.t1 < mac_to_febdata[strip.mac5].Ts1())
158  {
159  mac_to_febdata[strip.mac5].SetTs1(strip.sipm0.t1);
160  mac_to_febdata[strip.mac5].SetTs0(strip.sipm0.t0);
161  mac_to_febdata[strip.mac5].SetCoinc(strip.sipm0.sipmID);
162  }
163  }
164  }
165 
166 
167  for (auto & strip : strips)
168  {
169 
170  auto &feb_data = mac_to_febdata[strip.mac5];
171  uint32_t trigger_time = feb_data.Ts1();
172 
173  uint16_t adc_sipm0 = WaveformEmulation(strip.sipm0.t1 - trigger_time, strip.sipm0.adc);
174  uint16_t adc_sipm1 = WaveformEmulation(strip.sipm1.t1 - trigger_time, strip.sipm1.adc);
175 
176  AddADC(feb_data, strip.sipm0.sipmID, adc_sipm0);
177  AddADC(feb_data, strip.sipm1.sipmID, adc_sipm1);
178 
179  auto &ides = mac_to_ides[strip.mac5];
180  ides.push_back(strip.ide);
181 
182  auto &sipmids = mac_to_sipmids[strip.mac5];
183  sipmids.push_back(std::min(strip.sipm0.sipmID, strip.sipm1.sipmID));
184  }
185 
186  for (auto const& [mac, feb_data] : mac_to_febdata)
187  {
188  fData.push_back(std::make_pair(feb_data, mac_to_ides[mac]));
189  fAuxData.push_back(mac_to_sipmids[mac]);
190  }
191 
192  if (fParams.DebugTrigger()) std::cout << "Constructed " << mac_to_febdata.size()
193  << " FEBData object(s)." << std::endl << std::endl;
194  }
195 
196 
197 
199  {
200 
201  /** A struct to temporarily store information on a CRT Tagger trigger.
202  */
203  struct Trigger {
204  bool _is_bottom;
205  double _dead_time;
206  bool _planeX;
207  bool _planeY;
208  std::set<int> _mac5s;
209  std::vector<StripData> _strips;
210  uint32_t _trigger_time;
211  bool _debug;
212 
213  Trigger(bool is_bottom, double dead_time, bool debug) {
214  _planeX = _planeY = false;
215  _is_bottom = is_bottom;
216  _dead_time = dead_time;
217  _debug = debug;
218  }
219 
220  /** \brief Resets this trigger object */
221  void reset(uint32_t trigger_time) {
222  _planeX = _planeY = false;
223  _strips.clear();
224  _mac5s.clear();
225  _trigger_time = trigger_time;
226 
227  if(_debug) std::cout << "TRIGGER TIME IS " << _trigger_time << std::endl;
228  }
229 
230  /** \brief Add a strip belonging to a particular trigger */
231  void add_strip(StripData strip) {
232  _strips.push_back(strip);
233  _mac5s.insert(strip.mac5);
234 
235  if (strip.sipm_coinc) {
236  if (strip.planeID == 0) _planeX = true;
237  if (strip.planeID == 1) _planeY = true;
238  }
239 
240  if(_debug) std::cout << "\tAdded strip with mac " << strip.mac5
241  << " on plane " << strip.planeID
242  << ", with time " << strip.sipm0.t1 << std::endl;
243  }
244 
245  /** \brief Tells is a tagger is triggering or not */
246  bool tagger_triggered() {
247  if (_is_bottom) {
248  return _planeX or _planeY;
249  }
250  return _planeX and _planeY;
251  }
252 
253  /** \brief Returns true is the strip is in dead time */
254  bool is_in_dead_time(int mac5, int time) {
255  if (!_mac5s.count(mac5)) { return false; }
256  return (time <= _dead_time);
257  }
258 
259  void print_no_coinc(StripData strip) {
260  if (_debug) std::cout << "\tStrip with mac " << strip.mac5
261  << " on plane " << strip.planeID
262  << ", with time " << strip.sipm0.t1
263  << " -> didn't have SiPMs coincidence" << std::endl;
264  }
265 
266  void print_dead_time(StripData strip) {
267  if (_debug) std::cout << "\tStrip with mac " << strip.mac5
268  << " on plane " << strip.planeID
269  << ", with time " << strip.sipm0.t1
270  << " -> happened during dead time." << std::endl;
271  }
272  };
273 
274 
275  // Loop over all the CRT Taggers and simulate triggering, dead time, ...
276  for (auto iter : fTaggers)
277  {
278  auto & name = iter.first;
279  auto & tagger = iter.second;
280 
281  mf::LogInfo("CRTDetSimAlg") << "Simulating trigger for tagger " << name << std::endl;
282 
283  bool is_bottom = name.find("Bottom") != std::string::npos;
284  Trigger trigger(is_bottom, fParams.DeadTime(), fParams.DebugTrigger());
285 
286  auto & strip_data_v = tagger.data;
287 
288  // Time order the data
289  std::sort(strip_data_v.begin(), strip_data_v.end(),
290  [](const StripData& strip1,
291  const StripData& strip2) {
292  return strip1.sipm0.t1 < strip2.sipm0.t1;
293  });
294 
295  uint32_t trigger_ts1 = 0, current_time = 0;
296  bool first_trigger = true;
297 
298  // Loop over all the strips in this tagger
299  for (size_t i = 0; i < strip_data_v.size(); i++)
300  {
301  auto & strip_data = strip_data_v[i];
302 
303  current_time = strip_data.sipm0.t1;
304 
305  // Save the first trigger
306  if (strip_data.sipm_coinc and first_trigger)
307  {
308  first_trigger = false;
309  trigger_ts1 = current_time;
310  trigger.reset(trigger_ts1);
311  }
312 
313  // Save strips belonging to this trigger
314  if (current_time - trigger_ts1 < fParams.TaggerPlaneCoincidenceWindow())
315  {
316  trigger.add_strip(strip_data);
317  }
318  // Create a new trigger if either the current tagger is not trigger, or,
319  // if it is triggered, if we are past the dead time. Also, always require
320  // both sipm coincidence.
321  else if ((!trigger.tagger_triggered() or
322  (trigger.tagger_triggered() and
323  !trigger.is_in_dead_time(strip_data.mac5, current_time - trigger_ts1))) and
324  strip_data.sipm_coinc)
325  {
326  if (trigger.tagger_triggered()) {
327  ProcessStrips(trigger._strips);
328  }
329 
330  // Set the current, new, trigger
331  trigger_ts1 = current_time;
332 
333  // Reset the trigger object
334  trigger.reset(trigger_ts1);
335 
336  // Add this strip, which created the trigger
337  trigger.add_strip(strip_data);
338  }
339  else if (!strip_data.sipm_coinc)
340  {
341  trigger.print_no_coinc(strip_data);
342  }
343  else
344  {
345  trigger.print_dead_time(strip_data);
346  }
347 
348  } // loop over strips
349 
350  if (trigger.tagger_triggered()) {
351  ProcessStrips(trigger._strips);
352  }
353 
354  } // loop over taggers
355 
356  mf::LogInfo("CRTDetSimAlg") << "There are " << fData.size() << " FEBData objects." << std::endl;
357 
358  }
359 
360 
361  void CRTDetSimAlg::FillTaggers(const uint32_t adid, const uint32_t adsid,
362  vector<sim::AuxDetIDE> ides) {
363 
364  art::ServiceHandle<geo::Geometry> geoService;
365 
366  const geo::AuxDetGeo& adGeo = geoService->AuxDet(adid);
367  const geo::AuxDetSensitiveGeo& adsGeo = adGeo.SensitiveVolume(adsid);
368 
369  // Return the vector of IDEs
370  std::sort(ides.begin(), ides.end(),
371  [](const sim::AuxDetIDE & a, const sim::AuxDetIDE & b) -> bool{
372  return ((a.entryT + a.exitT)/2) < ((b.entryT + b.exitT)/2);
373  });
374 
375  // std::set<std::string> volNames = { adsGeo.TotalVolume()->GetName() };
376  std::set<std::string> volNames = { adGeo.TotalVolume()->GetName() };
377  std::vector<std::vector<TGeoNode const*> > paths =
378  geoService->FindAllVolumePaths(volNames);
379 
380  std::string path = "";
381  for (size_t inode=0; inode<paths.at(0).size(); inode++) {
382  path += paths.at(0).at(inode)->GetName();
383  if (inode < paths.at(0).size() - 1) {
384  path += "/";
385  }
386  }
387 
388  TGeoManager* manager = geoService->ROOTGeoManager();
389  manager->cd(path.c_str());
390 
391  // We get the array of strips first, which is the AuxDet,
392  // then from the AuxDet, we get the strip by picking the
393  // daughter with the ID of the AuxDetSensitive, and finally
394  // from the AuxDet, we go up and pick the module and tagger
395  TGeoNode* nodeArray = manager->GetCurrentNode();
396  TGeoNode* nodeStrip = nodeArray->GetDaughter(adsid);
397  TGeoNode* nodeModule = manager->GetMother(1);
398  TGeoNode* nodeTagger = manager->GetMother(2);
399 
400  std::string volumeName = nodeStrip->GetVolume()->GetName();
401 
402  mf::LogDebug("CRTDetSimAlg") << "Strip name: " << nodeStrip->GetName()
403  << ", number = " << nodeStrip->GetNumber()
404  << "\n Array name: " << nodeArray->GetName()
405  << ", number = " << nodeArray->GetNumber()
406  << "\n Module name: " << nodeModule->GetName()
407  << ", number = " << nodeModule->GetNumber()
408  << "\n Tagger name: " << nodeTagger->GetName()
409  << ", number = " << nodeTagger->GetNumber()
410  << "\n Strip volume name: " << volumeName << std::endl;
411 
412  // Retrive the ID of this CRT module
413  uint16_t mac5 = static_cast<uint16_t>(nodeModule->GetNumber());
414 
415  // Module position in parent (tagger) frame
416  double origin[3] = {0, 0, 0};
417  double modulePosMother[3];
418  nodeModule->LocalToMaster(origin, modulePosMother);
419 
420  // Determine plane ID (1 for z > 0, 0 for z < 0 in local coordinates)
421  unsigned planeID = (modulePosMother[2] > 0);
422 
423  // Determine module orientation: which way is the top (readout end)?
424  bool top = (planeID == 1) ? (modulePosMother[1] > 0) : (modulePosMother[0] < 0);
425 
426  // Simulate the CRT response for each hit
427  mf::LogInfo("CRTDetSimAlg") << "We have " << ides.size() << " IDE for this SimChannel." << std::endl;
428  for (size_t ide_i = 0; ide_i < ides.size(); ide_i++) {
429 
430  sim::AuxDetIDE ide = ides[ide_i];
431 
432  // Finally, what is the distance from the hit (centroid of the entry
433  // and exit points) to the readout end?
434  double x = (ide.entryX + ide.exitX) / 2;
435  double y = (ide.entryY + ide.exitY) / 2;
436  double z = (ide.entryZ + ide.exitZ) / 2;
437 
438  double tTrue = (ide.entryT + ide.exitT) / 2 + fTimeOffset; // ns
439  double eDep = ide.energyDeposited;
440 
441  mf::LogInfo("CRTDetSimAlg") << "True IDE with time " << tTrue
442  << ", energy " << eDep << std::endl;
443 
444  if (tTrue < 0) {
445  throw art::Exception(art::errors::LogicError)
446  << "Time cannot be negative. Check the time offset used for the CRT simulation.\n"
447  << "True time: " << (ide.entryT + ide.exitT) / 2 << "\n"
448  << "TimeOffset: " << fTimeOffset << std::endl;
449  }
450 
451  double world[3] = {x, y, z};
452  double svHitPosLocal[3];
453  adsGeo.WorldToLocal(world, svHitPosLocal);
454 
455  // Calculate distance to the readout
456  double distToReadout;
457  if (top) {
458  distToReadout = abs( adsGeo.HalfWidth1() - svHitPosLocal[0]);
459  }
460  else {
461  distToReadout = abs(-adsGeo.HalfWidth1() - svHitPosLocal[0]);
462  }
463 
464  // Calculate distance to fibers
465  double d0 = abs(-adsGeo.HalfHeight() - svHitPosLocal[1]); // L
466  double d1 = abs( adsGeo.HalfHeight() - svHitPosLocal[1]); // R
467 
468  // Simulate time response
469  // Waveform emulation is added later, because
470  // it depends on trigger time
471  long npe0, npe1;
472  double q0, q1;
473  ChargeResponse(eDep, d0, d1, distToReadout,
474  npe0, npe1, q0, q1);
475 
476  // Time relative to trigger, accounting for propagation delay and 'walk'
477  // for the fixed-threshold discriminator
478  uint32_t ts1_ch0 =
479  getChannelTriggerTicks(/*trigClock,*/ tTrue, npe0, distToReadout);
480  uint32_t ts1_ch1 =
481  getChannelTriggerTicks(/*trigClock,*/ tTrue, npe1, distToReadout);
482 
483  if (fParams.EqualizeSiPMTimes()) {
484  mf::LogWarning("CRTDetSimAlg") << "EqualizeSiPMTimes is on." << std::endl;
485  ts1_ch1 = ts1_ch0;
486  }
487 
488  // Time relative to PPS: Random for now! (FIXME)
489  uint32_t ppsTicks =
490  CLHEP::RandFlat::shootInt(&fEngine, /*trigClock.Frequency()*/ fParams.ClockSpeedCRT() * 1e6);
491 
492  // Adjacent channels on a strip are numbered sequentially.
493  //
494  // In the AuxDetChannelMapAlg methods, channels are identified by an
495  // AuxDet name (retrievable given the hit AuxDet ID) which specifies a
496  // module, and a channel number from 0 to 32.
497  // uint32_t moduleID = adid;
498  uint32_t moduleID = mac5;
499  uint32_t stripID = adsid;
500  uint32_t channel0ID = 32 * moduleID + 2 * stripID + 0;
501  uint32_t channel1ID = 32 * moduleID + 2 * stripID + 1;
502  uint32_t sipm0ID = stripID * 2 + 0;
503  uint32_t sipm1ID = stripID * 2 + 1;
504 
505  if (volumeName.find("MINOS") != std::string::npos) {continue;} // Ignoring MINOS modules for now.
506 
507  // Apply ADC threshold and strip-level coincidence (both fibers fire)
508  double threshold = static_cast<double>(fParams.QThreshold());
509  bool sipm_coinc = false;
510 
511  if (q0 > threshold &&
512  q1 > threshold &&
513  util::absDiff(ts1_ch0, ts1_ch1) < fParams.StripCoincidenceWindow())
514  {
515  sipm_coinc = true;
516  }
517 
518  // Time ordered
519  if (ts1_ch0 > ts1_ch1)
520  {
521  std::swap(ts1_ch0, ts1_ch1);
522  std::swap(channel0ID, channel1ID);
523  std::swap(q0, q1);
524  std::swap(sipm0ID, sipm1ID);
525  }
526 
527  SiPMData sipm0 = SiPMData(sipm0ID,
528  channel0ID,
529  ppsTicks,
530  ts1_ch0,
531  q0);
532  SiPMData sipm1 = SiPMData(sipm1ID,
533  channel1ID,
534  ppsTicks,
535  ts1_ch1,
536  q1);
537 
538  StripData strip_data = StripData(mac5,
539  planeID,
540  sipm0,
541  sipm1,
542  sipm_coinc,
543  ide);
544 
545  // Retrive the Tagger object
546  Tagger& tagger = fTaggers[nodeTagger->GetName()];
547  tagger.data.push_back(strip_data);
548 
549  double poss[3];
550  adsGeo.LocalToWorld(origin, poss);
551  mf::LogInfo("CRTDetSimAlg")
552  << "CRT HIT in adid/adsid " << adid << "/" << adsid << "\n"
553  << "MAC5 " << mac5 << "\n"
554  << "TRUE TIME " << tTrue << "\n"
555  << "TRACK ID " << ide.trackID << "\n"
556  << "CRT HIT POS " << x << " " << y << " " << z << "\n"
557  << "CRT STRIP POS " << poss[0] << " " << poss[1] << " " << poss[2] << "\n"
558  << "CRT MODULE POS " << modulePosMother[0] << " "
559  << modulePosMother[1] << " "
560  << modulePosMother[2] << " "
561  << "\n"
562  << "CRT PATH: " << path << "\n"
563  << "CRT level 0 (strip): " << nodeStrip->GetName() << "\n"
564  << "CRT level 1 (array): " << nodeArray->GetName() << "\n"
565  << "CRT level 2 (module): " << nodeModule->GetName() << "\n"
566  << "CRT level 3 (tagger): " << nodeTagger->GetName() << "\n"
567  << "CRT PLANE ID: " << planeID << "\n"
568  << "CRT distToReadout: " << distToReadout << " " << (top ? "top" : "bot") << "\n"
569  << "CRT Q SiPM 0: " << q0 << ", SiPM 1: " << q1
570  << "CRT Ts1 SiPM 0: " << ts1_ch0 << " SiPM 1: " << ts1_ch1 << "\n";
571  }
572  } //end FillTaggers
573 
574 
575  void CRTDetSimAlg::ChargeResponse(double eDep, double d0, double d1, double distToReadout, // input
576  long & npe0, long & npe1, double & q0, double &q1) // output
577  {
578  // The expected number of PE, using a quadratic model for the distance
579  // dependence, and scaling linearly with deposited energy.
580  double qr = fParams.UseEdep() ? 1.0 * eDep / fParams.Q0() : 1.0;
581 
582  double npeExpected =
583  fParams.NpeScaleNorm() / pow(distToReadout - fParams.NpeScaleShift(), 2) * qr;
584 
585  // Put PE on channels weighted by transverse distance across the strip,
586  // using an exponential model
587 
588  double abs0 = exp(-d0 / fParams.AbsLenEff());
589  double abs1 = exp(-d1 / fParams.AbsLenEff());
590  double npeExp0 = npeExpected * abs0 / (abs0 + abs1);
591  double npeExp1 = npeExpected * abs1 / (abs0 + abs1);
592 
593  // Observed PE (Poisson-fluctuated)
594  npe0 = CLHEP::RandPoisson::shoot(&fEngine, npeExp0);
595  npe1 = CLHEP::RandPoisson::shoot(&fEngine, npeExp1);
596 
597  // SiPM and ADC response: Npe to ADC counts, pedestal is added later
598  q0 = CLHEP::RandGauss::shoot(&fEngine, /*fQPed + */fParams.QSlope() * npe0,
599  fParams.QRMS() * sqrt(npe0));
600  q1 = CLHEP::RandGauss::shoot(&fEngine, /*fQPed + */fParams.QSlope() * npe1,
601  fParams.QRMS() * sqrt(npe1));
602 
603  // Apply saturation
604  double saturation = static_cast<double>(fParams.AdcSaturation());
605  if (q0 > saturation) q0 = saturation;
606  if (q1 > saturation) q1 = saturation;
607 
608  mf::LogInfo("CRTSetSimAlg")
609  << "CRT CHARGE RESPONSE: eDep = " << eDep
610  << ", npeExpected = " << npeExpected
611  << ", npe0 = " << npe0 << " -> q0 = " << q0
612  << ", npe1 = " << npe1 << " -> q1 = " << q1 << std::endl;
613  }
614 
615  uint32_t CRTDetSimAlg::getChannelTriggerTicks(/*detinfo::ElecClock& clock,*/
616  float t0, float npeMean, float r)
617  {
618  // Hit timing, with smearing and NPE dependence
619  double tDelayMean =
620  fParams.TDelayNorm() *
621  exp(-0.5 * pow((npeMean - fParams.TDelayShift()) / fParams.TDelaySigma(), 2)) +
623 
624  double tDelayRMS =
626  exp(-pow(npeMean - fParams.TDelayRMSGausShift(), 2) / fParams.TDelayRMSGausSigma()) +
629 
630  double tDelay = CLHEP::RandGauss::shoot(&fEngine, tDelayMean, tDelayRMS);
631 
632  // Time resolution of the interpolator
633  tDelay += CLHEP::RandGauss::shoot(&fEngine, 0, fParams.TResInterpolator());
634 
635  // Propagation time
636  double tProp = CLHEP::RandGauss::shoot(fParams.PropDelay(), fParams.PropDelayError()) * r;
637 
638  double t = t0 + tProp + tDelay;
639 
640  // Get clock ticks
641  // FIXME no clock available for CRTs, have to do it by hand
642  //clock.SetTime(t / 1e3); // SetTime takes microseconds
643  float time = (t / 1e3) * fParams.ClockSpeedCRT();
644 
645  if (time < 0) {
646  mf::LogWarning("CRTSetSimAlg") << "Time is negative. Check the time offset used." << std::endl;
647  }
648 
649  uint32_t time_int = static_cast<uint32_t>(time);
650 
651  mf::LogInfo("CRTSetSimAlg")
652  << "CRT TIMING: t0 = " << t0 << " (true G4 time)"
653  << ", tDelayMean = " << tDelayMean
654  << ", tDelayRMS = " << tDelayRMS
655  << ", tDelay = " << tDelay
656  << ", tProp = " << tProp
657  << ", t = " << t
658  << ", time = " << time
659  << ", time_int = " << time_int << " (time in uint32_t)" << std::endl;
660 
661  return time_int; // clock.Ticks();
662  }
663 
664 
666  {
667 
668  fTaggers.clear();
669  fData.clear();
670  fAuxData.clear();
671  }
672 
673 } // namespace crt
674 } // namespace sbnd
675 
676 #endif
uint32_t getChannelTriggerTicks(float t0, float npeMean, float r)
process_name opflash particleana ie ie ie z
fhicl::Atom< double > PropDelay
fhicl::Atom< double > TDelayRMSGausShift
fhicl::Atom< double > NpeScaleNorm
fhicl::Atom< double > QThreshold
void AddADC(sbnd::crt::FEBData &feb_data, const int &sipmID, const uint16_t &adc)
process_name opflash particleana ie x
std::vector< std::pair< sbnd::crt::FEBData, std::vector< AuxDetIDE > > > GetData()
int trackID
Geant4 supplied track ID.
AuxDetSensitiveGeo const & SensitiveVolume(size_t sv) const
Definition: AuxDetGeo.h:171
std::unique_ptr< ROOT::Math::Interpolator > fInterpolator
The interpolator used to estimate the CRT waveform.
CRTDetSimParams fParams
The table of CRT simulation parameters.
fhicl::Atom< double > TDelayRMSExpShift
void FillTaggers(const uint32_t adid, const uint32_t adsid, std::vector< AuxDetIDE > ides)
void ProcessStrips(const std::vector< StripData > &strips)
double fG4RefTime
The G4 reference time that can be used as a time offset.
fhicl::Sequence< double > WaveformY
fhicl::Atom< bool > DoWaveformEmulation
fhicl::Atom< uint32_t > AdcSaturation
fhicl::Atom< double > QRMS
fhicl::Atom< double > Q0
fhicl::Atom< double > QSlope
fhicl::Atom< double > TResInterpolator
fhicl::Atom< double > TDelayShift
fhicl::Atom< double > TDelaySigma
process_name gaushit a
float exitY
Exit position Y of particle.
BEGIN_PROLOG triggeremu_data_config_icarus settings PMTADCthresholds sequence::icarus_stage0_multiTPC_TPC physics sequence::icarus_stage0_EastHits_TPC physics sequence::icarus_stage0_WestHits_TPC physics producers purityana0 caloskimCalorimetryCryoE physics caloskimCalorimetryCryoW physics path
fhicl::Sequence< double > WaveformX
std::vector< std::pair< sbnd::crt::FEBData, std::vector< AuxDetIDE > > > fData
This member stores the final FEBData for the CRT simulation.
walls no top
Definition: selectors.fcl:105
unsigned planeID
The plane ID (0 or 1 for horizontal or vertical)
timescale_traits< TriggerTimeCategory >::time_point_t trigger_time
A point in time on the trigger time scale.
T abs(T value)
adc_array_t ADC() const
Definition: FEBData.cxx:44
SiPMData sipm0
One SiPM (the one that sees signal first)
fhicl::Atom< double > TDelayOffset
process_name opflash particleana ie ie y
float entryT
Entry time of particle.
std::vector< std::vector< int > > GetAuxData()
fhicl::Atom< bool > EqualizeSiPMTimes
void SetADC(size_t sipmID, uint16_t adc)
Definition: FEBData.cxx:78
std::map< std::string, Tagger > fTaggers
A list of hit taggers, before any coincidence requirement (name -&gt; tagger)
fhicl::Atom< double > PropDelayError
std::vector< StripData > data
A vector of strips that have energy deposits.
fhicl::Atom< double > AbsLenEff
float exitT
Exit time of particle.
fhicl::Atom< double > TDelayRMSExpNorm
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
fEngine(art::ServiceHandle< rndm::NuRandomService >() ->createEngine(*this, pset,"Seed"))
process_name drop raw::OpDetWaveforms_DataApr2016RecoStage1_saturation_ saturation
void ChargeResponse(double eDep, double d0, double d1, double distToReadout, long &npe0, long &npe1, double &q0, double &q1)
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
fhicl::Atom< double > TDelayRMSGausNorm
float exitZ
Exit position Z of particle.
float entryZ
Entry position Z of particle.
fhicl::Atom< bool > DebugTrigger
float exitX
Exit position X of particle.
fhicl::Atom< double > QPed
constexpr auto absDiff(A const &a, B const &b)
Returns the absolute value of the difference between two values.
Definition: NumericUtils.h:43
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
float energyDeposited
total energy deposited for this track ID and time
fhicl::Atom< double > TDelayRMSGausSigma
fhicl::Atom< bool > UseEdep
fhicl::Atom< double > StripCoincidenceWindow
fhicl::Atom< double > TaggerPlaneCoincidenceWindow
fhicl::Atom< double > DeadTime
float entryX
Entry position X of particle.
uint16_t Mac5() const
Definition: FEBData.cxx:29
float entryY
Entry position Y of particle.
const TGeoVolume * TotalVolume() const
Definition: AuxDetGeo.h:106
fhicl::Atom< double > GlobalT0Offset
MC truth information to make RawDigits and do back tracking.
CLHEP::HepRandomEngine & fEngine
The random-number engine.
createEngine fG4RefTime(art::ServiceHandle< detinfo::DetectorClocksService const >() ->DataForJob().G4ToElecTime(0)*1e3)
void WorldToLocal(const double *world, double *auxdet) const
Transform point from world frame to local auxiliary detector frame.
uint16_t mac5
The FEB number this strip is in.
fhicl::Atom< double > ClockSpeedCRT
fhicl::Atom< double > TDelayNorm
stream1 can override from command line with o or output services user sbnd
then echo fcl name
fhicl::Atom< double > NpeScaleShift
CRTDetSimAlg(const Parameters &p, CLHEP::HepRandomEngine &fRandEngine, double g4RefTime)
Definition: CRTDetSimAlg.cxx:9
void LocalToWorld(const double *auxdet, double *world) const
Transform point from local auxiliary detector frame to world frame.
bool sipm_coinc
Stores the ID of the SiPM that sees signal first (0-31)
std::vector< std::vector< int > > fAuxData
This member stores the indeces of SiPM per AuxDetIDE.
fhicl::Atom< double > TDelayRMSExpScale
process_name crt
double fTimeOffset
The time that will be used in the simulation.
esac echo uname r
uint16_t WaveformEmulation(const uint32_t &time_delay, const double &adc)
BEGIN_PROLOG could also be cout
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:227
fhicl::Atom< bool > UseG4RefTimeOffset