LArSoft  v10_06_00
Liquid Argon Software toolkit - https://larsoft.org/
PDFastSimPAR_module.cc
Go to the documentation of this file.
1 // Class: PDFastSimPAR
3 // Plugin Type: producer
4 // File: PDFastSimPAR_module.cc
5 // Description:
6 // - acts on sim::SimEnergyDeposit from LArG4Main,
7 // - simulate (fast, photon visibility service) the OpDet response to optical
8 // photons Input: 'sim::SimEnergyDeposit' Output: 'sim::OpDetBacktrackerRecord'
9 // Fast simulation of propagating the photons created from SimEnergyDeposits.
10 
11 // This module does a fast simulation of propagating the photons created from
12 // SimEnergyDeposits, This simulation is done using the Semi-Analytical model, which
13 // stores the visibilities of each optical channel with respect to each optical
14 // voxel in the TPC volume, to avoid propagating single photons using Geant4. At
15 // the end of this module a collection of the propagated photons either as
16 //'sim::OpDetBacktrackerRecord' are placed into the art event.
17 
18 // The steps this module takes are:
19 // - to take number of photon and the vertex information from
20 // 'sim::SimEnergyDeposits',
21 // - use the Semi-Analytical model (visibilities) to determine the amount of visible
22 // photons at each optical channel,
23 // - visible photons: the number of photons times the visibility at the middle
24 // of the Geant4 step for a given optical channel.
25 // - other photon information is got from 'sim::SimEnergyDeposits'
26 // - add 'sim::OpDetBacktrackerRecord' to event
27 // Aug. 19 by Mu Wei
28 // Restructured Nov. 21 by P. Green
30 
31 // LArSoft libraries
44 
46 
47 // Art libraries
56 #include "cetlib_except/exception.h"
57 #include "fhiclcpp/ParameterSet.h"
58 #include "fhiclcpp/types/Atom.h"
59 #include "fhiclcpp/types/Comment.h"
61 #include "fhiclcpp/types/Name.h"
64 
65 // Random numbers
66 #include "CLHEP/Random/RandPoissonQ.h"
67 
68 #include "range/v3/view/enumerate.hpp"
69 
70 #include <cmath>
71 #include <ctime>
72 #include <map>
73 #include <memory>
74 #include <vector>
75 
76 namespace phot {
77  class PDFastSimPAR : public art::EDProducer {
78  public:
79  // Define the fhicl configuration
80  struct Config {
81  using Name = fhicl::Name;
85 
87  Comment("SimEnergyDeposit label.")};
89  Comment("Simulate slow scintillation light, default true"),
90  true};
92  Comment("Simulate slow scintillation light")};
94  Comment("Simulate reflected visible light")};
96  Name("IncludeAnodeReflections"),
97  Comment("Simulate anode reflections, default false"),
98  false};
100  Comment("Simulate light propagation time")};
102  Name("GeoPropTimeOnly"),
103  Comment("Simulate light propagation time geometric approximation, default false"),
104  false};
106  Name("UseLitePhotons"),
107  Comment("Store SimPhotonsLite/OpDetBTRs instead of SimPhotons")};
109  Comment("Photons cannot cross the cathode")};
111  Name("OnlyActiveVolume"),
112  Comment("PAR fast sim usually only for active volume, default true"),
113  true};
115  Comment("Set to true if light is only supported in C:1")};
116  DP ScintTimeTool{Name("ScintTimeTool"),
117  Comment("Tool describing scintillation time structure")};
119  Name("UseXeAbsorption"),
120  Comment("Use Xe absorption length instead of Ar, default false"),
121  false};
122  ODP VUVTiming{Name("VUVTiming"), Comment("Configuration for UV timing parameterization")};
123  ODP VISTiming{Name("VISTiming"),
124  Comment("Configuration for visible timing parameterization")};
125  DP VUVHits{Name("VUVHits"), Comment("Configuration for UV visibility parameterization")};
126  ODP VISHits{Name("VISHits"),
127  Comment("Configuration for visibile visibility parameterization")};
128  fhicl::Atom<bool> Verbose{Name("Verbose"), Comment("Print verbose information"), false};
129  };
131 
132  explicit PDFastSimPAR(Parameters const& config);
133  void produce(art::Event&) override;
134 
135  private:
136  void detectedNumPhotons(std::vector<int>& DetectedNumPhotons,
137  const std::vector<double>& OpDetVisibilities,
138  const int NumPhotons) const;
139 
140  void AddOpDetBTR(std::vector<sim::OpDetBacktrackerRecord>& opbtr,
141  std::vector<int>& ChannelMap,
142  const sim::OpDetBacktrackerRecord& btr) const;
143  void SimpleAddOpDetBTR(
144  // std::vector<sim::OpDetBacktrackerRecord>& opbtr,
145  std::map<int, sim::OBTRHelper>& opbtr,
146  std::vector<int>& ChannelMap,
147  size_t channel,
148  int trackID,
149  int time,
150  double pos[3],
151  double edeposit,
152  int num_photons = 1);
153 
154  bool isOpDetInSameTPC(geo::Point_t const& ScintPoint, geo::Point_t const& OpDetPoint) const;
155  std::vector<geo::Point_t> opDetCenters() const;
156 
157  // semi-analytical model
158  std::unique_ptr<SemiAnalyticalModel> fVisibilityModel;
159 
160  // propagation time model
161  std::unique_ptr<PropagationTimeModel> fPropTimeModel;
162 
163  // random numbers
164  CLHEP::HepRandomEngine& fPhotonEngine;
165  std::unique_ptr<CLHEP::RandPoissonQ> fRandPoissPhot;
166  CLHEP::HepRandomEngine& fScintTimeEngine;
167  std::unique_ptr<ScintTime> fScintTime; // Tool to retrieve timinig of scintillation
168 
169  // geometry properties
172  const size_t fNOpChannels;
173  const std::vector<geo::BoxBoundedGeo> fActiveVolumes;
174  const int fNTPC;
176  const std::vector<geo::Point_t> fOpDetCenter;
177 
178  // Module behavior
180  const bool fDoFastComponent;
181  const bool fDoSlowComponent;
182  const bool fDoReflectedLight;
184  const bool fIncludePropTime;
185  const bool fGeoPropTimeOnly;
186  const bool fUseLitePhotons;
187  const bool fOpaqueCathode;
188  const bool fOnlyActiveVolume;
189  const bool fOnlyOneCryostat;
190  const bool fUseXeAbsorption;
191  };
192 
193  //......................................................................
195  : art::EDProducer{config}
196  , fPhotonEngine(art::ServiceHandle<rndm::NuRandomService>()->registerAndSeedEngine(
197  createEngine(0, "HepJamesRandom", "photon"),
198  "HepJamesRandom",
199  "photon",
200  config.get_PSet(),
201  "SeedPhoton"))
202  , fRandPoissPhot(std::make_unique<CLHEP::RandPoissonQ>(fPhotonEngine))
204  createEngine(0, "HepJamesRandom", "scinttime"),
205  "HepJamesRandom",
206  "scinttime",
207  config.get_PSet(),
208  "SeedScintTime"))
209  , fScintTime{art::make_tool<phot::ScintTime>(config().ScintTimeTool.get<fhicl::ParameterSet>())}
210  , fGeom(*(lar::providerFrom<geo::Geometry>()))
211  , fISTPC{fGeom}
214  , fNTPC(fGeom.NTPC())
216  , fSimTag(config().SimulationLabel())
217  , fDoFastComponent(config().DoFastComponent())
218  , fDoSlowComponent(config().DoSlowComponent())
219  , fDoReflectedLight(config().DoReflectedLight())
220  , fIncludeAnodeReflections(config().IncludeAnodeReflections())
221  , fIncludePropTime(config().IncludePropTime())
222  , fGeoPropTimeOnly(config().GeoPropTimeOnly())
223  , fUseLitePhotons(config().UseLitePhotons())
224  , fOpaqueCathode(config().OpaqueCathode())
225  , fOnlyActiveVolume(config().OnlyActiveVolume())
226  , fOnlyOneCryostat(config().OnlyOneCryostat())
227  , fUseXeAbsorption(config().UseXeAbsorption())
228  {
229  mf::LogInfo("PDFastSimPAR") << "Initializing PDFastSimPAR." << std::endl;
230 
231  // Parameterized Simulation
232  fhicl::ParameterSet VUVHitsParams = config().VUVHits.get<fhicl::ParameterSet>();
233  fhicl::ParameterSet VUVTimingParams;
234  fhicl::ParameterSet VISHitsParams;
235  fhicl::ParameterSet VISTimingParams;
236 
237  // Validate configuration options
238  if (fIncludePropTime &&
239  !config().VUVTiming.get_if_present<fhicl::ParameterSet>(VUVTimingParams)) {
241  << "Propagation time simulation requested, but VUVTiming not specified."
242  << "\n";
243  }
245  !config().VISHits.get_if_present<fhicl::ParameterSet>(VISHitsParams)) {
247  << "Reflected light or anode reflections simulation requested, but VisHits not specified."
248  << "\n";
249  }
251  !config().VISTiming.get_if_present<fhicl::ParameterSet>(VISTimingParams)) {
253  << "Reflected light propagation time simulation requested, but VISTiming not specified."
254  << "\n";
255  }
256  if (fGeom.Ncryostats() > 1U) {
257  if (fOnlyOneCryostat) {
258  mf::LogWarning("PDFastSimPAR")
259  << std::string(80, '=') << "\nA detector with " << fGeom.Ncryostats()
260  << " cryostats is configured"
261  << " , and semi-analytic model is requested for scintillation photon propagation."
262  << " THIS CONFIGURATION IS NOT SUPPORTED and it is open to bugs"
263  << " (e.g. scintillation may be detected only in cryostat #0)."
264  << "\nThis would be normally a fatal error, but it has been forcibly overridden."
265  << "\n"
266  << std::string(80, '=');
267  }
268  else {
270  << "Photon propagation via semi-analytic model is not supported yet"
271  << " on detectors with more than one cryostat.";
272  }
273  }
274 
275  // Initialise the Scintillation Time
276  fScintTime->initRand(fScintTimeEngine);
277 
278  // photo-detector visibility model (semi-analytical model)
279  fVisibilityModel = std::make_unique<SemiAnalyticalModel>(
280  VUVHitsParams, VISHitsParams, fDoReflectedLight, fIncludeAnodeReflections, fUseXeAbsorption);
281 
282  // propagation time model
283  if (fIncludePropTime)
284  fPropTimeModel = std::make_unique<PropagationTimeModel>(
285  VUVTimingParams, VISTimingParams, fScintTimeEngine, fDoReflectedLight, fGeoPropTimeOnly);
286 
287  {
288  auto log = mf::LogTrace("PDFastSimPAR") << "PDFastSimPAR: active volume boundaries from "
289  << fActiveVolumes.size() << " volumes:";
290  for (auto const& [iCryo, box] : ::ranges::views::enumerate(fActiveVolumes)) {
291  log << "\n - C:" << iCryo << ": " << box.Min() << " -- " << box.Max() << " cm";
292  }
293  }
294 
295  if (fUseLitePhotons) {
296  mf::LogInfo("PDFastSimPAR") << "Using Lite Photons";
297  produces<std::vector<sim::SimPhotonsLite>>();
298  produces<std::vector<sim::OpDetBacktrackerRecord>>();
299  if (fDoReflectedLight) {
300  mf::LogInfo("PDFastSimPAR") << "Storing Reflected Photons";
301  produces<std::vector<sim::SimPhotonsLite>>("Reflected");
302  produces<std::vector<sim::OpDetBacktrackerRecord>>("Reflected");
303  }
304  }
305  else {
306  mf::LogInfo("PDFastSimPAR") << "Using Sim Photons";
307  produces<std::vector<sim::SimPhotons>>();
308  if (fDoReflectedLight) {
309  mf::LogInfo("PDFastSimPAR") << "Storing Reflected Photons";
310  produces<std::vector<sim::SimPhotons>>("Reflected");
311  }
312  }
313 
314  // determine drift distance
316  // for multiple TPCs, use second TPC to skip small volume at edges of detector (DUNE)
317  if (fNTPC > 1 && fDriftDistance < 50)
318  fDriftDistance = fGeom.TPC(geo::TPCID{0, 1}).DriftDistance();
319 
320  mf::LogInfo("PDFastSimPAR") << "PDFastSimPAR Initialization finish.\n"
321  << "Simulate using semi-analytic model for number of hits."
322  << std::endl;
323  }
324 
325  //......................................................................
327  {
328  mf::LogTrace("PDFastSimPAR") << "PDFastSimPAR Module Producer"
329  << "EventID: " << event.event();
330 
331  std::vector<int> PDChannelToSOCMapDirect(fNOpChannels, -1); // Where each OpChan is.
332  std::vector<int> PDChannelToSOCMapReflect(fNOpChannels, -1); // Where each OpChan is.
333 
334  // SimPhotonsLite
335  auto phlit = std::make_unique<std::vector<sim::SimPhotonsLite>>();
336  auto opbtr = std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
337  auto phlit_ref = std::make_unique<std::vector<sim::SimPhotonsLite>>();
338  auto opbtr_ref = std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
339 
340  //Helpers holding maps
341  std::map<int, sim::OBTRHelper> opbtr_helper, opbtr_helper_ref;
342 
343  auto& dir_phlitcol(*phlit);
344  auto& ref_phlitcol(*phlit_ref);
345  // SimPhotons
346  auto phot = std::make_unique<std::vector<sim::SimPhotons>>();
347  auto phot_ref = std::make_unique<std::vector<sim::SimPhotons>>();
348  auto& dir_photcol(*phot);
349  auto& ref_photcol(*phot_ref);
350  if (fUseLitePhotons) {
351  dir_phlitcol.resize(fNOpChannels);
352  ref_phlitcol.resize(fNOpChannels);
353  for (unsigned int i = 0; i < fNOpChannels; i++) {
354  dir_phlitcol[i].OpChannel = i;
355  ref_phlitcol[i].OpChannel = i;
356  }
357  }
358  else { // SimPhotons
359  dir_photcol.resize(fNOpChannels);
360  ref_photcol.resize(fNOpChannels);
361  for (unsigned int i = 0; i < fNOpChannels; i++) {
362  dir_photcol[i].fOpChannel = i;
363  ref_photcol[i].fOpChannel = i;
364  }
365  }
366 
368  if (!event.getByLabel(fSimTag, edepHandle)) {
369  mf::LogError("PDFastSimPAR") << "PDFastSimPAR Module Cannot getByLabel: " << fSimTag;
370  return;
371  }
372 
373  auto const& edeps = edepHandle;
374 
375  int num_points = 0;
376  int num_fastph = 0;
377  int num_slowph = 0;
378  int num_fastdp = 0;
379  int num_slowdp = 0;
380 
381  mf::LogTrace("PDFastSimPAR") << "Creating SimPhotonsLite/SimPhotons from " << (*edeps).size()
382  << " energy deposits\n";
383 
384  for (auto const& edepi : *edeps) {
385 
386  if (!(num_points % 1000)) {
387  mf::LogTrace("PDFastSimPAR")
388  << "SimEnergyDeposit: " << num_points << " " << edepi.TrackID() << " " << edepi.Energy()
389  << "\nStart: " << edepi.Start() << "\nEnd: " << edepi.End()
390  << "\nNF: " << edepi.NumFPhotons() << "\nNS: " << edepi.NumSPhotons()
391  << "\nSYR: " << edepi.ScintYieldRatio() << "\n";
392  }
393  num_points++;
394 
395  int nphot_fast = edepi.NumFPhotons();
396  int nphot_slow = edepi.NumSPhotons();
397 
398  num_fastph += nphot_fast;
399  num_slowph += nphot_slow;
400 
401  if (!((nphot_fast > 0 && fDoFastComponent) || (nphot_slow > 0 && fDoSlowComponent))) continue;
402 
403  int trackID = edepi.TrackID();
404  int nphot = edepi.NumPhotons();
405  double edeposit = edepi.Energy() / nphot;
406  double pos[3] = {edepi.MidPointX(), edepi.MidPointY(), edepi.MidPointZ()};
407  geo::Point_t const ScintPoint = {pos[0], pos[1], pos[2]};
408 
409  if (fOnlyActiveVolume && !fISTPC.isScintInActiveVolume(ScintPoint)) continue;
410 
411  // direct light
412  std::vector<int> DetectedNumFast(fNOpChannels);
413  std::vector<int> DetectedNumSlow(fNOpChannels);
414 
415  std::vector<double> OpDetVisibilities;
416  fVisibilityModel->detectedDirectVisibilities(OpDetVisibilities, ScintPoint);
417  detectedNumPhotons(DetectedNumFast, OpDetVisibilities, nphot_fast);
418  detectedNumPhotons(DetectedNumSlow, OpDetVisibilities, nphot_slow);
419 
421  std::vector<int> AnodeDetectedNumFast(fNOpChannels);
422  std::vector<int> AnodeDetectedNumSlow(fNOpChannels);
423 
424  std::vector<double> OpDetVisibilitiesAnode;
425  fVisibilityModel->detectedReflectedVisibilities(OpDetVisibilitiesAnode, ScintPoint, true);
426  detectedNumPhotons(AnodeDetectedNumFast, OpDetVisibilitiesAnode, nphot_fast);
427  detectedNumPhotons(AnodeDetectedNumSlow, OpDetVisibilitiesAnode, nphot_slow);
428 
429  // add to existing count
430  for (size_t i = 0; i < AnodeDetectedNumFast.size(); ++i) {
431  DetectedNumFast[i] += AnodeDetectedNumFast[i];
432  }
433  for (size_t i = 0; i < AnodeDetectedNumSlow.size(); ++i) {
434  DetectedNumSlow[i] += AnodeDetectedNumSlow[i];
435  }
436  }
437 
438  // reflected light, if enabled
439  std::vector<int> ReflDetectedNumFast(fNOpChannels);
440  std::vector<int> ReflDetectedNumSlow(fNOpChannels);
441  if (fDoReflectedLight) {
442  std::vector<double> OpDetVisibilitiesRefl;
443  fVisibilityModel->detectedReflectedVisibilities(OpDetVisibilitiesRefl, ScintPoint, false);
444  detectedNumPhotons(ReflDetectedNumFast, OpDetVisibilitiesRefl, nphot_fast);
445  detectedNumPhotons(ReflDetectedNumSlow, OpDetVisibilitiesRefl, nphot_slow);
446  }
447 
448  // loop through direct photons then reflected photons cases
449  size_t DoReflected = (fDoReflectedLight) ? 1 : 0;
450  for (size_t Reflected = 0; Reflected <= DoReflected; ++Reflected) {
451  for (size_t channel = 0; channel < fNOpChannels; channel++) {
452 
453  if (fOpaqueCathode && !isOpDetInSameTPC(ScintPoint, fOpDetCenter[channel])) continue;
454 
455  int ndetected_fast = DetectedNumFast[channel];
456  int ndetected_slow = DetectedNumSlow[channel];
457  if (Reflected) {
458  ndetected_fast = ReflDetectedNumFast[channel];
459  ndetected_slow = ReflDetectedNumSlow[channel];
460  }
461  if (!((ndetected_fast > 0 && fDoFastComponent) ||
462  (ndetected_slow > 0 && fDoSlowComponent)))
463  continue;
464 
465  // calculate propagation time, does not matter whether fast or slow photon
466  std::vector<double> transport_time;
467  if (fIncludePropTime) {
468  transport_time.resize(ndetected_fast + ndetected_slow);
469  fPropTimeModel->propagationTime(transport_time, ScintPoint, channel, Reflected);
470  }
471 
472  // SimPhotonsLite case
473  if (fUseLitePhotons) {
474  if (ndetected_fast > 0 && fDoFastComponent) {
475  int n = ndetected_fast;
476  num_fastdp += n;
477  for (int i = 0; i < n; ++i) {
478  // calculates the time at which the photon was produced
479  double dtime = edepi.StartT() + fScintTime->fastScintTime();
480  if (fIncludePropTime) dtime += transport_time[i];
481 
482  int time = static_cast<int>(std::round(dtime));
483  if (Reflected) {
484  ++ref_phlitcol[channel].DetectedPhotons[time];
486  // *opbtr_ref, PDChannelToSOCMapReflect, channel, trackID, time, pos, edeposit, 1);
487  opbtr_helper_ref,
488  PDChannelToSOCMapReflect,
489  channel,
490  trackID,
491  time,
492  pos,
493  edeposit,
494  1);
495  }
496  else {
497  ++dir_phlitcol[channel].DetectedPhotons[time];
499  // *opbtr, PDChannelToSOCMapDirect, channel, trackID, time, pos, edeposit, 1);
500  opbtr_helper,
501  PDChannelToSOCMapDirect,
502  channel,
503  trackID,
504  time,
505  pos,
506  edeposit,
507  1);
508  }
509  }
510  }
511  if (ndetected_slow > 0 && fDoSlowComponent) {
512  int n = ndetected_slow;
513  num_slowdp += n;
514  for (int i = 0; i < n; ++i) {
515  // calculates the time at which the photon was produced
516  double dtime = edepi.StartT() + fScintTime->slowScintTime();
517  if (fIncludePropTime) dtime += transport_time[ndetected_fast + i];
518  int time = static_cast<int>(std::round(dtime));
519  if (Reflected) {
520  ++ref_phlitcol[channel].DetectedPhotons[time];
522  // *opbtr_ref, PDChannelToSOCMapReflect, channel, trackID, time, pos, edeposit, 1);
523  opbtr_helper_ref,
524  PDChannelToSOCMapReflect,
525  channel,
526  trackID,
527  time,
528  pos,
529  edeposit,
530  1);
531  }
532  else {
533  ++dir_phlitcol[channel].DetectedPhotons[time];
535  // *opbtr, PDChannelToSOCMapDirect, channel, trackID, time, pos, edeposit, 1);
536  opbtr_helper,
537  PDChannelToSOCMapDirect,
538  channel,
539  trackID,
540  time,
541  pos,
542  edeposit,
543  1);
544  }
545  }
546  }
547  }
548  // SimPhotons case
549  else {
550  sim::OnePhoton photon;
551  photon.SetInSD = false;
552  photon.InitialPosition = edepi.End();
553  photon.MotherTrackID = edepi.TrackID();
554  if (Reflected)
555  photon.Energy = 2.9 * CLHEP::eV; // 430 nm
556  else
557  photon.Energy = 9.7 * CLHEP::eV; // 128 nm
558  // TODO: un-hardcode and add another energy for Xe scintillation
559  if (ndetected_fast > 0 && fDoFastComponent) {
560  int n = ndetected_fast;
561  num_fastdp += n;
562  for (int i = 0; i < n; ++i) {
563  // calculates the time at which the photon was produced
564  double dtime = edepi.StartT() + fScintTime->fastScintTime();
565  if (fIncludePropTime) dtime += transport_time[i];
566  int time = static_cast<int>(std::round(dtime));
567  photon.Time = time;
568  if (Reflected)
569  ref_photcol[channel].insert(ref_photcol[channel].end(), 1, photon);
570  else
571  dir_photcol[channel].insert(dir_photcol[channel].end(), 1, photon);
572  }
573  }
574  if (ndetected_slow > 0 && fDoSlowComponent) {
575  int n = ndetected_slow;
576  num_slowdp += n;
577  for (int i = 0; i < n; ++i) {
578  double dtime = edepi.StartT() + fScintTime->slowScintTime();
579  if (fIncludePropTime) dtime += transport_time[ndetected_fast + i];
580  int time = static_cast<int>(std::round(dtime));
581  photon.Time = time;
582  if (Reflected)
583  ref_photcol[channel].insert(ref_photcol[channel].end(), 1, photon);
584  else
585  dir_photcol[channel].insert(dir_photcol[channel].end(), 1, photon);
586  }
587  }
588  }
589  }
590  }
591  }
592 
593  mf::LogTrace("PDFastSimPAR") << "Total points: " << num_points
594  << ", total fast photons: " << num_fastph
595  << ", total slow photons: " << num_slowph
596  << "\ndetected fast photons: " << num_fastdp
597  << ", detected slow photons: " << num_slowdp;
598 
599  mf::LogDebug("PDFastSimPAR") << "Number of entries in opbtrs";
600  for (auto& iopbtr : *opbtr) {
601  mf::LogDebug("PDFastSimPAR")
602  << "OpDet: " << iopbtr.OpDetNum() << " " << iopbtr.timePDclockSDPsMap().size();
603  }
604  mf::LogDebug("PDFastSimPAR") << "Number of entries in opbtrs refelected";
605  for (auto& iopbtr : *opbtr_ref) {
606  mf::LogDebug("PDFastSimPAR")
607  << "OpDet: " << iopbtr.OpDetNum() << " " << iopbtr.timePDclockSDPsMap().size();
608  }
609 
610  if (fUseLitePhotons) {
611 
612  for (auto& iopbtr : opbtr_helper) {
613  opbtr->emplace_back(iopbtr.second);
614  }
615 
616  event.put(move(phlit));
617  event.put(move(opbtr));
618  if (fDoReflectedLight) {
619  for (auto& iopbtr : opbtr_helper_ref) {
620  opbtr_ref->emplace_back(iopbtr.second);
621  }
622  event.put(move(phlit_ref), "Reflected");
623  event.put(move(opbtr_ref), "Reflected");
624  }
625  }
626  else {
627  event.put(move(phot));
628  if (fDoReflectedLight) { event.put(move(phot_ref), "Reflected"); }
629  }
630 
631  return;
632  }
633 
634  //......................................................................
635  void PDFastSimPAR::AddOpDetBTR(std::vector<sim::OpDetBacktrackerRecord>& opbtr,
636  std::vector<int>& ChannelMap,
637  const sim::OpDetBacktrackerRecord& btr) const
638  {
639  int iChan = btr.OpDetNum();
640  if (ChannelMap[iChan] < 0) {
641  ChannelMap[iChan] = opbtr.size();
642  opbtr.emplace_back(std::move(btr));
643  }
644  else {
645  size_t idtest = ChannelMap[iChan];
646  auto const& timePDclockSDPsMap = btr.timePDclockSDPsMap();
647  for (auto const& timePDclockSDP : timePDclockSDPsMap) {
648  for (auto const& sdp : timePDclockSDP.second) {
649  double xyz[3] = {sdp.x, sdp.y, sdp.z};
650  opbtr.at(idtest).AddScintillationPhotons(
651  sdp.trackID, timePDclockSDP.first, sdp.numPhotons, xyz, sdp.energy);
652  }
653  }
654  }
655  }
656 
657  void PDFastSimPAR::SimpleAddOpDetBTR( //std::vector<sim::OpDetBacktrackerRecord>& opbtr,
658  std::map<int, sim::OBTRHelper>& opbtr,
659  std::vector<int>& ChannelMap,
660  size_t channel,
661  int trackID,
662  int time,
663  double pos[3],
664  double edeposit,
665  int num_photons)
666  {
667  if (ChannelMap[channel] < 0) {
668  ChannelMap[channel] = opbtr.size();
669  // opbtr.push_back(sim::OpDetBacktrackerRecord(channel));
670  opbtr.emplace(channel, channel);
671  }
672  // size_t idtest = ChannelMap[channel];
673  // opbtr.at(idtest).AddScintillationPhotonsToMap(trackID, time, num_photons, pos, edeposit);
674  opbtr.at(channel).AddScintillationPhotonsToMap(trackID, time, num_photons, pos, edeposit);
675  }
676 
677  //......................................................................
678  // calculates number of photons detected given visibility and emitted number of photons
679  void PDFastSimPAR::detectedNumPhotons(std::vector<int>& DetectedNumPhotons,
680  const std::vector<double>& OpDetVisibilities,
681  const int NumPhotons) const
682  {
683  for (size_t i = 0; i < OpDetVisibilities.size(); ++i) {
684  DetectedNumPhotons[i] = fRandPoissPhot->fire(OpDetVisibilities[i] * NumPhotons);
685  }
686  }
687 
688  //......................................................................
689  // checks whether photo-detector is able to see the emitted light scintillation
691  geo::Point_t const& OpDetPoint) const
692  {
693  // check optical channel is in same TPC as scintillation light, if not doesn't see light
694  // temporary method, needs to be replaced with geometry service
695  // working for SBND, uBooNE, DUNE HD 1x2x6, DUNE HD 10kt and DUNE VD subset
696 
697  // special case for SBND = 2 TPCs
698  // check x coordinate has same sign or is close to zero
699  if (fNTPC == 2 && ((ScintPoint.X() < 0.) != (OpDetPoint.X() < 0.)) &&
700  std::abs(OpDetPoint.X()) > 10.) {
701  return false;
702  }
703 
704  // special case for DUNE-HD 10kt = 300 TPCs
705  // check whether distance in drift direction > 1 drift distance
706  if (fNTPC == 300 && std::abs(ScintPoint.X() - OpDetPoint.X()) > fDriftDistance) {
707  return false;
708  }
709  // not needed for DUNE HD 1x2x6, DUNE VD subset, uBooNE
710 
711  return true;
712  }
713 
714  std::vector<geo::Point_t> PDFastSimPAR::opDetCenters() const
715  {
716  std::vector<geo::Point_t> opDetCenter;
717  for (size_t const i : ::ranges::views::ints(size_t(0), fNOpChannels)) {
718  geo::OpDetGeo const& opDet = fGeom.OpDetGeoFromOpDet(i);
719  opDetCenter.push_back(opDet.GetCenter());
720  }
721  return opDetCenter;
722  }
723  // ---------------------------------------------------------------------------
724 
725 } // namespace phot
726 
const std::vector< geo::BoxBoundedGeo > fActiveVolumes
base_engine_t & createEngine(seed_t seed)
bool isOpDetInSameTPC(geo::Point_t const &ScintPoint, geo::Point_t const &OpDetPoint) const
void AddOpDetBTR(std::vector< sim::OpDetBacktrackerRecord > &opbtr, std::vector< int > &ChannelMap, const sim::OpDetBacktrackerRecord &btr) const
static std::vector< geo::BoxBoundedGeo > extractActiveLArVolume(geo::GeometryCore const &geom)
Definition: ISTPC.cxx:46
Utilities related to art service access.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
std::unique_ptr< PropagationTimeModel > fPropTimeModel
unsigned int NTPC(CryostatID const &cryoid=details::cryostat_zero) const
Returns the total number of TPCs in the specified cryostat.
Definition: GeometryCore.h:416
fhicl::Atom< bool > DoSlowComponent
Point_t const & GetCenter() const
Definition: OpDetGeo.h:71
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
PDFastSimPAR(Parameters const &config)
All information of a photon entering the sensitive optical detector volume.
Definition: SimPhotons.h:60
fhicl::Atom< bool > DoReflectedLight
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::unique_ptr< ScintTime > fScintTime
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
Definition: GeometryCore.h:303
Energy deposited on a readout Optical Detector by simulated tracks.
geo::Point_t InitialPosition
Scintillation position in world coordinates [cm].
Definition: SimPhotons.h:63
fhicl::Atom< bool > UseLitePhotons
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:49
std::unique_ptr< CLHEP::RandPoissonQ > fRandPoissPhot
CLHEP::HepRandomEngine & fScintTimeEngine
Simulation objects for optical detectors.
int OpDetNum() const
Returns the readout Optical Detector this object describes.
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
const std::vector< geo::Point_t > fOpDetCenter
Definitions of geometry vector data types.
std::unique_ptr< SemiAnalyticalModel > fVisibilityModel
fhicl::Atom< bool > OpaqueCathode
T get(std::string const &key) const
Definition: ParameterSet.h:314
fhicl::Atom< bool > IncludeAnodeReflections
void produce(art::Event &) override
void SimpleAddOpDetBTR(std::map< int, sim::OBTRHelper > &opbtr, std::vector< int > &ChannelMap, size_t channel, int trackID, int time, double pos[3], double edeposit, int num_photons=1)
The data type to uniquely identify a TPC.
Definition: geo_types.h:306
Description of the physical geometry of one entire detector.
Definition: GeometryCore.h:91
const art::InputTag fSimTag
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
unsigned int NOpDets() const
Number of OpDets in the whole detector.
Provides a base class aware of world box coordinates.
Encapsulate the geometry of an optical detector.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:180
fhicl::Atom< bool > UseXeAbsorption
General LArSoft Utilities.
fhicl::Atom< bool > GeoPropTimeOnly
CLHEP::HepRandomEngine & fPhotonEngine
double DriftDistance() const
Drift distance is defined as the distance between the anode and the cathode, in centimeters.
Definition: TPCGeo.cxx:165
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
std::vector< geo::Point_t > opDetCenters() const
bool SetInSD
Whether the photon reaches the sensitive detector.
Definition: SimPhotons.h:84
MaybeLogger_< ELseverityLevel::ELsev_success, false > LogDebug
contains information for a single step in the detector simulation
void detectedNumPhotons(std::vector< int > &DetectedNumPhotons, const std::vector< double > &OpDetVisibilities, const int NumPhotons) const
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
fhicl::Atom< art::InputTag > SimulationLabel
Definition: MVAAlg.h:12
Char_t n[5]
MaybeLogger_< ELseverityLevel::ELsev_success, true > LogTrace
fhicl::Atom< bool > IncludePropTime
float Energy
Scintillation photon energy [GeV].
Definition: SimPhotons.h:78
fhicl::Atom< bool > OnlyActiveVolume
TPCGeo const & TPC(TPCID const &tpcid=details::tpc_zero) const
Returns the specified TPC.
Definition: GeometryCore.h:448
bool isScintInActiveVolume(geo::Point_t const &ScintPoint)
Definition: ISTPC.cxx:37
const bool fIncludeAnodeReflections
timePDclockSDPs_t const & timePDclockSDPsMap() const
Returns all the deposited energy information as stored.
fhicl::Atom< bool > OnlyOneCryostat
art framework interface to geometry description
geo::GeometryCore const & fGeom
fhicl::Atom< bool > DoFastComponent
OpDetGeo const & OpDetGeoFromOpDet(unsigned int OpDet) const
Returns the geo::OpDetGeo object for the given detector number.
Event finding and building.
int MotherTrackID
ID of the GEANT4 track causing the scintillation.
Definition: SimPhotons.h:81