47 #include "nurandom/RandomUtils/NuRandomService.h"
50 #include "art/Framework/Core/EDProducer.h"
51 #include "art/Framework/Core/ModuleMacros.h"
52 #include "art/Framework/Principal/Event.h"
53 #include "art/Framework/Principal/Handle.h"
54 #include "art/Framework/Services/Registry/ServiceHandle.h"
55 #include "art/Utilities/make_tool.h"
56 #include "canvas/Utilities/Exception.h"
57 #include "canvas/Utilities/InputTag.h"
58 #include "messagefacility/MessageLogger/MessageLogger.h"
59 #include "fhiclcpp/ParameterSet.h"
60 #include "fhiclcpp/types/Atom.h"
61 #include "fhiclcpp/types/Comment.h"
62 #include "fhiclcpp/types/DelegatedParameter.h"
63 #include "fhiclcpp/types/Name.h"
64 #include "fhiclcpp/types/OptionalDelegatedParameter.h"
65 #include "cetlib_except/exception.h"
68 #include "CLHEP/Random/RandPoissonQ.h"
84 using DP = fhicl::DelegatedParameter;
85 using ODP = fhicl::OptionalDelegatedParameter;
93 fhicl::Atom<bool>
GeoPropTimeOnly {
Name(
"GeoPropTimeOnly"),
Comment(
"Simulate light propagation time geometric approximation, default false"),
false };
107 void produce(art::Event&)
override;
114 const std::vector<double>& OpDetVisibilities,
115 const int NumPhotons)
const;
117 void AddOpDetBTR(std::vector< sim::OpDetBacktrackerRecord > & opbtr,
118 std::vector<int> & ChannelMap,
176 : art::EDProducer{config}
177 , fISTPC{*(lar::providerFrom<geo::Geometry>())}
178 , fPhotonEngine(art::ServiceHandle<rndm::NuRandomService>()->createEngine(
179 *
this,
"HepJamesRandom",
"photon", config.get_PSet(),
"SeedPhoton"))
180 ,
fScintTimeEngine(art::ServiceHandle<rndm::NuRandomService>()->createEngine(
181 *
this,
"HepJamesRandom",
"scinttime", config.get_PSet(),
"SeedScintTime"))
182 , simTag(config().SimulationLabel())
183 , fDoFastComponent(config().DoFastComponent())
184 , fDoSlowComponent(config().DoSlowComponent())
185 , fDoReflectedLight(config().DoReflectedLight())
186 , fIncludeAnodeReflections(config().IncludeAnodeReflections())
187 , fIncludePropTime(config().IncludePropTime())
188 , fGeoPropTimeOnly(config().GeoPropTimeOnly())
190 , fOpaqueCathode(config().OpaqueCathode())
191 , fOnlyActiveVolume(config().OnlyActiveVolume())
192 , fOnlyOneCryostat(config().OnlyOneCryostat())
193 , fScintTime{art::make_tool<phot::ScintTime>(config().ScintTimeTool.get<fhicl::ParameterSet>())}
194 , fVUVHitsParams(config().VUVHits.get<fhicl::ParameterSet>())
197 if(fIncludePropTime && !config().VUVTiming.get_if_present<fhicl::ParameterSet>(fVUVTimingParams)) {
198 throw art::Exception(art::errors::Configuration)
199 <<
"Propagation time simulation requested, but VUVTiming not specified." <<
"\n";
202 if(fDoReflectedLight && !config().VISHits.get_if_present<fhicl::ParameterSet>(fVISHitsParams)) {
203 throw art::Exception(art::errors::Configuration)
204 <<
"Reflected light simulation requested, but VisHits not specified." <<
"\n";
207 if (fDoReflectedLight && fIncludePropTime && !config().VISTiming.get_if_present<fhicl::ParameterSet>(fVISTimingParams)) {
208 throw art::Exception(art::errors::Configuration)
209 <<
"Reflected light propagation time simulation requested, but VISTiming not specified." <<
"\n";
212 if(fIncludeAnodeReflections && !config().VISHits.get_if_present<fhicl::ParameterSet>(fVISHitsParams)) {
213 throw art::Exception(art::errors::Configuration)
214 <<
"Anode reflections light simulation requested, but VisHits not specified." <<
"\n";
219 if (fUseLitePhotons) {
220 mf::LogInfo(
"PDFastSimPAR") <<
"Using Lite Photons";
221 produces< std::vector<sim::SimPhotonsLite> >();
222 produces< std::vector<sim::OpDetBacktrackerRecord> >();
223 if(fDoReflectedLight) {
224 mf::LogInfo(
"PDFastSimPAR") <<
"Storing Reflected Photons";
225 produces< std::vector<sim::SimPhotonsLite> >(
"Reflected");
226 produces< std::vector<sim::OpDetBacktrackerRecord> >(
"Reflected");
230 mf::LogInfo(
"PDFastSimPAR") <<
"Using Sim Photons";
231 produces< std::vector<sim::SimPhotons> >();
232 if(fDoReflectedLight) {
233 mf::LogInfo(
"PDFastSimPAR") <<
"Storing Reflected Photons";
234 produces< std::vector<sim::SimPhotons> >(
"Reflected");
243 mf::LogTrace(
"PDFastSimPAR") <<
"PDFastSimPAR Module Producer"
244 <<
"EventID: " <<
event.event();
246 std::vector<int> PDChannelToSOCMapDirect(
fNOpChannels, -1);
247 std::vector<int> PDChannelToSOCMapReflect(
fNOpChannels, -1);
250 auto phlit = std::make_unique<std::vector<sim::SimPhotonsLite>>();
251 auto opbtr = std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
252 auto phlit_ref = std::make_unique<std::vector<sim::SimPhotonsLite>>();
253 auto opbtr_ref = std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
254 auto& dir_phlitcol(*phlit);
255 auto& ref_phlitcol(*phlit_ref);
257 auto phot = std::make_unique<std::vector<sim::SimPhotons>>();
258 auto phot_ref = std::make_unique<std::vector<sim::SimPhotons>>();
259 auto& dir_photcol(*phot);
260 auto& ref_photcol(*phot_ref);
265 dir_phlitcol[i].OpChannel = i;
266 ref_phlitcol[i].OpChannel = i;
273 dir_photcol[i].fOpChannel = i;
274 ref_photcol[i].fOpChannel = i;
278 art::Handle<std::vector<sim::SimEnergyDeposit>> edepHandle;
279 if (!event.getByLabel(
simTag, edepHandle)) {
280 mf::LogError(
"PDFastSimPAR") <<
"PDFastSimPAR Module Cannot getByLabel: " <<
simTag;
284 auto const& edeps = edepHandle;
292 for (
auto const& edepi : *edeps) {
295 int nphot_fast = edepi.NumFPhotons();
296 int nphot_slow = edepi.NumSPhotons();
298 num_fastph += nphot_fast;
299 num_slowph += nphot_slow;
304 int trackID = edepi.TrackID();
305 int nphot = edepi.NumPhotons();
306 double edeposit = edepi.Energy() / nphot;
307 double pos[3] = {edepi.MidPointX(), edepi.MidPointY(), edepi.MidPointZ()};
308 geo::Point_t const ScintPoint = {pos[0], pos[1], pos[2]};
316 std::vector<double> OpDetVisibilities;
317 fVisibilityModel->detectedDirectVisibilities(OpDetVisibilities, ScintPoint);
325 std::vector<double> OpDetVisibilitiesAnode;
326 fVisibilityModel->detectedReflectedVisibilities(OpDetVisibilitiesAnode, ScintPoint,
true);
331 for (
size_t i=0; i<AnodeDetectedNumFast.size(); ++i) {DetectedNumFast[i] += AnodeDetectedNumFast[i];}
332 for (
size_t i=0; i<AnodeDetectedNumSlow.size(); ++i) {DetectedNumSlow[i] += AnodeDetectedNumSlow[i];}
339 std::vector<double> OpDetVisibilitiesRefl;
340 fVisibilityModel->detectedReflectedVisibilities(OpDetVisibilitiesRefl, ScintPoint,
false);
347 for (
size_t Reflected = 0; Reflected <= DoReflected; ++Reflected) {
348 for (
size_t channel = 0; channel <
fNOpChannels; channel++) {
352 int ndetected_fast = DetectedNumFast[channel];
353 int ndetected_slow = DetectedNumSlow[channel];
355 ndetected_fast = ReflDetectedNumFast[channel];
356 ndetected_slow = ReflDetectedNumSlow[channel];
362 std::vector<double> transport_time;
364 transport_time.resize(ndetected_fast + ndetected_slow);
365 fPropTimeModel->propagationTime(transport_time, ScintPoint, channel, Reflected);
372 int n = ndetected_fast;
374 for (
int i = 0; i <
n; ++i) {
379 else time =
static_cast<int>(edepi.StartT() +
fScintTime->GetScintTime());
380 if (Reflected) ++ref_phlitcol[channel].DetectedPhotons[time];
381 else ++dir_phlitcol[channel].DetectedPhotons[time];
386 int n = ndetected_slow;
388 for (
int i = 0; i <
n; ++i) {
391 if (
fIncludePropTime) time =
static_cast<int>(edepi.StartT() +
fScintTime->GetScintTime() + transport_time[ndetected_fast + i]);
392 else time =
static_cast<int>(edepi.StartT() +
fScintTime->GetScintTime());
393 if (Reflected) ++ref_phlitcol[channel].DetectedPhotons[time];
394 else ++dir_phlitcol[channel].DetectedPhotons[time];
398 if (Reflected)
AddOpDetBTR(*opbtr_ref, PDChannelToSOCMapReflect, tmpbtr);
399 else AddOpDetBTR(*opbtr, PDChannelToSOCMapDirect, tmpbtr);
406 if (Reflected) photon.
Energy = 2.9 * CLHEP::eV;
407 else photon.
Energy = 9.7 * CLHEP::eV;
409 int n = ndetected_fast;
411 for (
int i = 0; i <
n; ++i) {
416 else time =
static_cast<int>(edepi.StartT() +
fScintTime->GetScintTime());
418 if(Reflected) ref_photcol[channel].insert(ref_photcol[channel].
end(), 1, photon);
419 else dir_photcol[channel].insert(dir_photcol[channel].
end(), 1, photon);
423 int n = ndetected_slow;
425 for (
int i = 0; i <
n; ++i) {
428 if (
fIncludePropTime) time =
static_cast<int>(edepi.StartT() +
fScintTime->GetScintTime() + transport_time[ndetected_fast + i]);
429 else time =
static_cast<int>(edepi.StartT() +
fScintTime->GetScintTime());
431 if(Reflected) ref_photcol[channel].insert(ref_photcol[channel].
end(), 1, photon);
432 else dir_photcol[channel].insert(dir_photcol[channel].
end(), 1, photon);
440 mf::LogTrace(
"PDFastSimPAR") <<
"Total points: " << num_points
441 <<
", total fast photons: " << num_fastph
442 <<
", total slow photons: " << num_slowph
443 <<
"\ndetected fast photons: " << num_fastdp
444 <<
", detected slow photons: " << num_slowdp;
447 event.put(move(phlit));
448 event.put(move(opbtr));
450 event.put(move(phlit_ref),
"Reflected");
451 event.put(move(opbtr_ref),
"Reflected");
455 event.put(move(phot));
457 event.put(move(phot_ref),
"Reflected");
466 std::vector<int> & ChannelMap,
470 if (ChannelMap[iChan] < 0) {
471 ChannelMap[iChan] = opbtr.size();
472 opbtr.emplace_back(std::move(btr));
475 size_t idtest = ChannelMap[iChan];
477 for(
auto const& timePDclockSDP : timePDclockSDPsMap) {
478 for(
auto const& sdp : timePDclockSDP.second) {
479 double xyz[3] = {sdp.x, sdp.y, sdp.z};
480 opbtr.at(idtest).AddScintillationPhotons(sdp.trackID,
481 timePDclockSDP.first,
494 std::cout <<
"PDFastSimPAR Initialization" << std::endl;
495 std::cout <<
"Initializing the geometry of the detector." << std::endl;
496 std::cout <<
"Simulate using semi-analytic model for number of hits." << std::endl;
513 auto log = mf::LogTrace(
"PDFastSimPAR") <<
"PDFastSimPAR: active volume boundaries from "
516 log <<
"\n - C:" << iCryo <<
": " << box.Min() <<
" -- " << box.Max() <<
" cm";
520 if (geom.Ncryostats() > 1U) {
522 mf::LogWarning(
"PDFastSimPAR")
523 << std::string(80,
'=') <<
"\nA detector with " << geom.Ncryostats()
524 <<
" cryostats is configured"
525 <<
" , and semi-analytic model is requested for scintillation photon propagation."
526 <<
" THIS CONFIGURATION IS NOT SUPPORTED and it is open to bugs"
527 <<
" (e.g. scintillation may be detected only in cryostat #0)."
528 <<
"\nThis would be normally a fatal error, but it has been forcibly overridden."
530 << std::string(80,
'=');
533 throw art::Exception(art::errors::Configuration)
534 <<
"Photon propagation via semi-analytic model is not supported yet"
535 <<
" on detectors with more than one cryostat.";
550 for (
size_t i=0; i<OpDetVisibilities.size(); ++i){
551 DetectedNumPhotons[i] =
fRandPoissPhot->fire(OpDetVisibilities[i] * NumPhotons);
564 if (((ScintPoint.X() < 0.) != (OpDetPoint.X() < 0.)) &&
const bool fGeoPropTimeOnly
fhicl::OptionalDelegatedParameter ODP
std::vector< geo::Point_t > fOpDetCenter
fhicl::ParameterSet fVISHitsParams
bool isOpDetInSameTPC(geo::Point_t const &ScintPoint, geo::Point_t const &OpDetPoint) const
process_name can override from command line with o or output photon
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.
Definition of util::enumerate().
const bool fUseLitePhotons
std::unique_ptr< PropagationTimeModel > fPropTimeModel
fhicl::Atom< bool > DoSlowComponent
PDFastSimPAR(Parameters const &config)
All information of a photon entering the sensitive optical detector volume.
std::vector< geo::BoxBoundedGeo > fActiveVolumes
fhicl::Atom< bool > DoReflectedLight
void GetCenter(double *xyz, double localz=0.0) const
std::unique_ptr< ScintTime > fScintTime
const bool fOnlyActiveVolume
const bool fIncludePropTime
const bool fOpaqueCathode
Energy deposited on a readout Optical Detector by simulated tracks.
fhicl::DelegatedParameter DP
geo::Point_t InitialPosition
Scintillation position in world coordinates [cm].
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
const bool fDoReflectedLight
fhicl::Atom< bool > UseLitePhotons
std::unique_ptr< CLHEP::RandPoissonQ > fRandPoissPhot
CLHEP::HepRandomEngine & fScintTimeEngine
Simulation objects for optical detectors.
fhicl::ParameterSet fVISTimingParams
int OpDetNum() const
Returns the readout Optical Detector this object describes.
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
const bool fDoFastComponent
Definitions of geometry vector data types.
std::unique_ptr< SemiAnalyticalModel > fVisibilityModel
fhicl::Atom< bool > OpaqueCathode
fhicl::ParameterSet fVUVTimingParams
fhicl::Atom< bool > IncludeAnodeReflections
auto end(FixedBins< T, C > const &) noexcept
void produce(art::Event &) override
BEGIN_PROLOG vertical distance to the surface Name
Test of util::counter and support utilities.
Description of geometry of one entire detector.
const bool fDoSlowComponent
Provides a base class aware of world box coordinates.
void AddScintillationPhotons(TrackID_t trackID, timePDclock_t timePDclock, double numberPhotons, double const *xyz, double energy)
Add scintillation photons and energy to this OpticalDetector.
Encapsulate the geometry of an optical detector.
fhicl::Atom< bool > GeoPropTimeOnly
CLHEP::HepRandomEngine & fPhotonEngine
bool SetInSD
Whether the photon reaches the sensitive detector.
const art::InputTag simTag
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
fhicl::Atom< art::InputTag > SimulationLabel
art::EDProducer::Table< Config > Parameters
fhicl::Atom< bool > IncludePropTime
float Energy
Scintillation photon energy [GeV].
fhicl::Atom< bool > OnlyActiveVolume
bool isScintInActiveVolume(geo::Point_t const &ScintPoint)
const bool fIncludeAnodeReflections
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
timePDclockSDPs_t const & timePDclockSDPsMap() const
Returns all the deposited energy information as stored.
fhicl::Atom< bool > OnlyOneCryostat
art framework interface to geometry description
BEGIN_PROLOG could also be cout
fhicl::Atom< bool > DoFastComponent
services LArG4Parameters UseLitePhotons
createEngine fScintTimeEngine(art::ServiceHandle< rndm::NuRandomService >() ->createEngine(*this,"HepJamesRandom","scinttime", p,"SeedScintTime"))
fhicl::ParameterSet fVUVHitsParams
const bool fOnlyOneCryostat