56 #include "cetlib_except/exception.h" 66 #include "CLHEP/Random/RandPoissonQ.h" 68 #include "range/v3/view/enumerate.hpp" 87 Comment(
"SimEnergyDeposit label.")};
89 Comment(
"Simulate slow scintillation light, default true"),
92 Comment(
"Simulate slow scintillation light")};
94 Comment(
"Simulate reflected visible light")};
96 Name(
"IncludeAnodeReflections"),
97 Comment(
"Simulate anode reflections, default false"),
100 Comment(
"Simulate light propagation time")};
102 Name(
"GeoPropTimeOnly"),
103 Comment(
"Simulate light propagation time geometric approximation, default 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"),
115 Comment(
"Set to true if light is only supported in C:1")};
117 Comment(
"Tool describing scintillation time structure")};
119 Name(
"UseXeAbsorption"),
120 Comment(
"Use Xe absorption length instead of Ar, default false"),
124 Comment(
"Configuration for visible timing parameterization")};
127 Comment(
"Configuration for visibile visibility parameterization")};
137 const std::vector<double>& OpDetVisibilities,
138 const int NumPhotons)
const;
140 void AddOpDetBTR(std::vector<sim::OpDetBacktrackerRecord>& opbtr,
141 std::vector<int>& ChannelMap,
145 std::map<int, sim::OBTRHelper>& opbtr,
146 std::vector<int>& ChannelMap,
152 int num_photons = 1);
210 ,
fGeom(*(lar::providerFrom<geo::Geometry>()))
216 ,
fSimTag(config().SimulationLabel())
229 mf::LogInfo(
"PDFastSimPAR") <<
"Initializing PDFastSimPAR." << std::endl;
241 <<
"Propagation time simulation requested, but VUVTiming not specified." 247 <<
"Reflected light or anode reflections simulation requested, but VisHits not specified." 253 <<
"Reflected light propagation time simulation requested, but VISTiming not specified." 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." 266 << std::string(80,
'=');
270 <<
"Photon propagation via semi-analytic model is not supported yet" 271 <<
" on detectors with more than one cryostat.";
288 auto log =
mf::LogTrace(
"PDFastSimPAR") <<
"PDFastSimPAR: active volume boundaries from " 291 log <<
"\n - C:" << iCryo <<
": " << box.Min() <<
" -- " << box.Max() <<
" cm";
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");
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");
317 if (
fNTPC > 1 && fDriftDistance < 50)
320 mf::LogInfo(
"PDFastSimPAR") <<
"PDFastSimPAR Initialization finish.\n" 321 <<
"Simulate using semi-analytic model for number of hits." 328 mf::LogTrace(
"PDFastSimPAR") <<
"PDFastSimPAR Module Producer" 329 <<
"EventID: " <<
event.event();
331 std::vector<int> PDChannelToSOCMapDirect(
fNOpChannels, -1);
332 std::vector<int> PDChannelToSOCMapReflect(
fNOpChannels, -1);
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>>();
341 std::map<int, sim::OBTRHelper> opbtr_helper, opbtr_helper_ref;
343 auto& dir_phlitcol(*phlit);
344 auto& ref_phlitcol(*phlit_ref);
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);
354 dir_phlitcol[i].OpChannel = i;
355 ref_phlitcol[i].OpChannel = i;
362 dir_photcol[i].fOpChannel = i;
363 ref_photcol[i].fOpChannel = i;
373 auto const& edeps = edepHandle;
381 mf::LogTrace(
"PDFastSimPAR") <<
"Creating SimPhotonsLite/SimPhotons from " << (*edeps).size()
382 <<
" energy deposits\n";
384 for (
auto const& edepi : *edeps) {
386 if (!(num_points % 1000)) {
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";
395 int nphot_fast = edepi.NumFPhotons();
396 int nphot_slow = edepi.NumSPhotons();
398 num_fastph += nphot_fast;
399 num_slowph += nphot_slow;
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]};
415 std::vector<double> OpDetVisibilities;
416 fVisibilityModel->detectedDirectVisibilities(OpDetVisibilities, ScintPoint);
424 std::vector<double> OpDetVisibilitiesAnode;
425 fVisibilityModel->detectedReflectedVisibilities(OpDetVisibilitiesAnode, ScintPoint,
true);
430 for (
size_t i = 0; i < AnodeDetectedNumFast.size(); ++i) {
431 DetectedNumFast[i] += AnodeDetectedNumFast[i];
433 for (
size_t i = 0; i < AnodeDetectedNumSlow.size(); ++i) {
434 DetectedNumSlow[i] += AnodeDetectedNumSlow[i];
442 std::vector<double> OpDetVisibilitiesRefl;
443 fVisibilityModel->detectedReflectedVisibilities(OpDetVisibilitiesRefl, ScintPoint,
false);
450 for (
size_t Reflected = 0; Reflected <= DoReflected; ++Reflected) {
451 for (
size_t channel = 0; channel <
fNOpChannels; channel++) {
455 int ndetected_fast = DetectedNumFast[channel];
456 int ndetected_slow = DetectedNumSlow[channel];
458 ndetected_fast = ReflDetectedNumFast[channel];
459 ndetected_slow = ReflDetectedNumSlow[channel];
466 std::vector<double> transport_time;
468 transport_time.resize(ndetected_fast + ndetected_slow);
469 fPropTimeModel->propagationTime(transport_time, ScintPoint, channel, Reflected);
475 int n = ndetected_fast;
477 for (
int i = 0; i <
n; ++i) {
479 double dtime = edepi.StartT() +
fScintTime->fastScintTime();
482 int time =
static_cast<int>(std::round(dtime));
484 ++ref_phlitcol[channel].DetectedPhotons[time];
488 PDChannelToSOCMapReflect,
497 ++dir_phlitcol[channel].DetectedPhotons[time];
501 PDChannelToSOCMapDirect,
512 int n = ndetected_slow;
514 for (
int i = 0; i <
n; ++i) {
516 double dtime = edepi.StartT() +
fScintTime->slowScintTime();
518 int time =
static_cast<int>(std::round(dtime));
520 ++ref_phlitcol[channel].DetectedPhotons[time];
524 PDChannelToSOCMapReflect,
533 ++dir_phlitcol[channel].DetectedPhotons[time];
537 PDChannelToSOCMapDirect,
555 photon.
Energy = 2.9 * CLHEP::eV;
557 photon.
Energy = 9.7 * CLHEP::eV;
560 int n = ndetected_fast;
562 for (
int i = 0; i <
n; ++i) {
564 double dtime = edepi.StartT() +
fScintTime->fastScintTime();
566 int time =
static_cast<int>(std::round(dtime));
569 ref_photcol[channel].insert(ref_photcol[channel].
end(), 1, photon);
571 dir_photcol[channel].insert(dir_photcol[channel].
end(), 1, photon);
575 int n = ndetected_slow;
577 for (
int i = 0; i <
n; ++i) {
578 double dtime = edepi.StartT() +
fScintTime->slowScintTime();
580 int time =
static_cast<int>(std::round(dtime));
583 ref_photcol[channel].insert(ref_photcol[channel].
end(), 1, photon);
585 dir_photcol[channel].insert(dir_photcol[channel].
end(), 1, photon);
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;
599 mf::LogDebug(
"PDFastSimPAR") <<
"Number of entries in opbtrs";
600 for (
auto& iopbtr : *opbtr) {
602 <<
"OpDet: " << iopbtr.OpDetNum() <<
" " << iopbtr.timePDclockSDPsMap().size();
604 mf::LogDebug(
"PDFastSimPAR") <<
"Number of entries in opbtrs refelected";
605 for (
auto& iopbtr : *opbtr_ref) {
607 <<
"OpDet: " << iopbtr.OpDetNum() <<
" " << iopbtr.timePDclockSDPsMap().size();
612 for (
auto& iopbtr : opbtr_helper) {
613 opbtr->emplace_back(iopbtr.second);
616 event.put(move(phlit));
617 event.put(move(opbtr));
619 for (
auto& iopbtr : opbtr_helper_ref) {
620 opbtr_ref->emplace_back(iopbtr.second);
622 event.put(move(phlit_ref),
"Reflected");
623 event.put(move(opbtr_ref),
"Reflected");
627 event.put(move(
phot));
636 std::vector<int>& ChannelMap,
640 if (ChannelMap[iChan] < 0) {
641 ChannelMap[iChan] = opbtr.size();
642 opbtr.emplace_back(std::move(btr));
645 size_t idtest = ChannelMap[iChan];
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);
658 std::map<int, sim::OBTRHelper>& opbtr,
659 std::vector<int>& ChannelMap,
667 if (ChannelMap[channel] < 0) {
668 ChannelMap[channel] = opbtr.size();
670 opbtr.emplace(channel, channel);
674 opbtr.at(channel).AddScintillationPhotonsToMap(trackID, time, num_photons, pos, edeposit);
680 const std::vector<double>& OpDetVisibilities,
681 const int NumPhotons)
const 683 for (
size_t i = 0; i < OpDetVisibilities.size(); ++i) {
684 DetectedNumPhotons[i] =
fRandPoissPhot->fire(OpDetVisibilities[i] * NumPhotons);
699 if (
fNTPC == 2 && ((ScintPoint.X() < 0.) != (OpDetPoint.X() < 0.)) &&
716 std::vector<geo::Point_t> opDetCenter;
717 for (
size_t const i : ::ranges::views::ints(
size_t(0),
fNOpChannels)) {
719 opDetCenter.push_back(opDet.
GetCenter());
const bool fGeoPropTimeOnly
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
const size_t fNOpChannels
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)
Utilities related to art service access.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
const bool fUseLitePhotons
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.
fhicl::Atom< bool > DoSlowComponent
Point_t const & GetCenter() const
EDProducer(fhicl::ParameterSet const &pset)
PDFastSimPAR(Parameters const &config)
All information of a photon entering the sensitive optical detector volume.
fhicl::Atom< bool > DoReflectedLight
constexpr auto abs(T v)
Returns the absolute value of the argument.
std::unique_ptr< ScintTime > fScintTime
const bool fOnlyActiveVolume
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
const bool fIncludePropTime
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
const bool fUseXeAbsorption
const bool fOpaqueCathode
Energy deposited on a readout Optical Detector by simulated tracks.
geo::Point_t InitialPosition
Scintillation position in world coordinates [cm].
const bool fDoReflectedLight
fhicl::Atom< bool > UseLitePhotons
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
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.
const bool fDoFastComponent
#define DEFINE_ART_MODULE(klass)
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
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.
Description of the physical geometry of one entire detector.
const art::InputTag fSimTag
const bool fDoSlowComponent
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
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
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.
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.
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
fhicl::Atom< bool > Verbose
MaybeLogger_< ELseverityLevel::ELsev_success, true > LogTrace
fhicl::Atom< bool > IncludePropTime
float Energy
Scintillation photon energy [GeV].
fhicl::Atom< bool > OnlyActiveVolume
TPCGeo const & TPC(TPCID const &tpcid=details::tpc_zero) const
Returns the specified TPC.
bool isScintInActiveVolume(geo::Point_t const &ScintPoint)
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.
const bool fOnlyOneCryostat