40 #include "cetlib/search_path.h" 41 #include "cetlib_except/exception.h" 81 #include "Geant4/G4LogicalVolumeStore.hh" 82 #include "Geant4/G4RunManager.hh" 83 #include "Geant4/G4SDManager.hh" 84 #include "Geant4/G4VSensitiveDetector.hh" 85 #include "Geant4/G4VUserDetectorConstruction.hh" 91 #include "boost/algorithm/string.hpp" 97 class LArVoxelListAction;
315 std::unique_ptr<g4b::G4Helper>
fG4Help{
nullptr};
334 std::vector<std::string>
349 std::set<std::string>
const& vol_names)
const;
373 template <
typename T>
374 std::vector<T>& append(std::vector<T>& dest, std::vector<T>&& source)
377 dest = std::move(source);
379 dest.insert(dest.end(), std::move_iterator{
begin(source)}, std::move_iterator{
end(source)});
380 source = std::vector<T>{};
394 ,
fG4PhysListName(pset.get<std::string>(
"G4PhysListName",
"larg4::PhysicsList"))
418 <<
"Option `DumpParticleList` can't be set if `MakeMCParticles` is unset.\n";
422 <<
"Option `KeepParticlesInVolumes` can't be set if `MakeMCParticles` is unset.\n";
426 if (pset.has_key(
"Seed")) {
428 <<
"The configuration of LArG4 module has the discontinued 'Seed' parameter.\n" 429 "Seeds are now controlled by two parameters: 'GEANTSeed' and 'PropagationSeed'.";
436 createEngine(0,
"G4Engine",
"GEANT"),
"G4Engine",
"GEANT", pset,
"GEANTSeed");
440 bool useInputLabels =
441 pset.get_if_present<std::vector<std::string>>(
"InputLabels",
fInputLabels);
460 produces<std::vector<sim::SimPhotons>>();
461 if (
fStoreReflected) { produces<std::vector<sim::SimPhotons>>(
"Reflected"); }
464 produces<std::vector<sim::SimPhotonsLite>>();
465 produces<std::vector<sim::OpDetBacktrackerRecord>>();
467 produces<std::vector<sim::SimPhotonsLite>>(
"Reflected");
468 produces<std::vector<sim::OpDetBacktrackerRecord>>(
"Reflected");
474 produces<std::vector<sim::SimEnergyDeposit>>(
"TPCActive");
475 produces<std::vector<sim::SimEnergyDeposit>>(
"Other");
479 produces<std::vector<simb::MCParticle>>();
480 produces<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>();
484 produces<std::vector<sim::AuxDetSimChannel>>();
487 cet::search_path sp(
"FW_SEARCH_PATH");
489 sp.find_file(pset.get<std::string>(
"GeantCommandFile"),
fG4MacroPath);
515 std::vector<G4VUserParallelWorld*> pworlds;
539 fG4Help->SetParallelWorlds(pworlds);
563 fG4Help->GetRunManager()->SetUserAction(stacking_action);
576 std::set<std::string>
const& vol_names)
const 579 if (
empty(vol_names))
return {};
583 std::vector<std::vector<TGeoNode const*>> node_paths = geom.FindAllVolumePaths(vol_names);
587 GeoVolumePairs.reserve(node_paths.size());
591 for (
size_t iVolume = 0; iVolume < node_paths.size(); ++iVolume) {
592 std::vector<TGeoNode const*> path = node_paths[iVolume];
594 auto pTransl =
new TGeoTranslation(0., 0., 0.);
595 auto pRot =
new TGeoRotation();
596 for (TGeoNode
const* node : path) {
597 TGeoTranslation thistranslate(*node->GetMatrix());
598 TGeoRotation thisrotate(*node->GetMatrix());
599 pTransl->Add(&thistranslate);
600 *pRot = *pRot * thisrotate;
605 auto pTransl2 =
new TGeoTranslation(
606 pTransl->GetTranslation()[0], pTransl->GetTranslation()[1], pTransl->GetTranslation()[2]);
607 double phi = 0., theta = 0., psi = 0.;
608 pRot->GetAngles(phi, theta, psi);
609 auto pRot2 =
new TGeoRotation();
610 pRot2->SetAngles(phi, theta, psi);
612 auto pTransf =
new TGeoCombiTrans(*pTransl2, *pRot2);
613 GeoVolumePairs.emplace_back(node_paths[iVolume].back()->GetVolume(), pTransf);
616 return std::make_unique<util::PositionInVolumeFilter>(std::move(GeoVolumePairs));
628 auto scCol = std::make_unique<std::vector<sim::SimChannel>>();
629 auto adCol = std::make_unique<std::vector<sim::AuxDetSimChannel>>();
634 auto partCol =
fMakeMCParticles ? std::make_unique<std::vector<simb::MCParticle>>() :
nullptr;
635 auto droppedPartCol =
637 auto PhotonCol = std::make_unique<std::vector<sim::SimPhotons>>();
638 auto PhotonColRefl = std::make_unique<std::vector<sim::SimPhotons>>();
639 auto LitePhotonCol = std::make_unique<std::vector<sim::SimPhotonsLite>>();
640 auto LitePhotonColRefl = std::make_unique<std::vector<sim::SimPhotonsLite>>();
641 auto cOpDetBacktrackerRecordCol = std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
642 auto cOpDetBacktrackerRecordColRefl =
643 std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
645 std::optional<art::PtrMaker<simb::MCParticle>> makeMCPartPtr;
649 auto edepCol_TPCActive = std::make_unique<std::vector<sim::SimEnergyDeposit>>();
650 auto edepCol_Other = std::make_unique<std::vector<sim::SimEnergyDeposit>>();
665 std::vector<art::Handle<std::vector<simb::MCTruth>>> mclists;
667 mclists = evt.
getMany<std::vector<simb::MCTruth>>();
674 unsigned int nGeneratedParticles = 0;
677 for (
size_t mcl = 0; mcl < mclists.size(); ++mcl) {
681 for (
size_t m = 0; m < mclistHandle->size(); ++m) {
689 if (!partCol)
continue;
695 for (
auto const& partPair : particleList) {
697 ++nGeneratedParticles;
706 if (!truthInfo.hasGeneratedParticleIndex() && (p.
Mother() == 0)) {
709 error <<
"Failed to match primary particle:\n";
711 error <<
"\nwith particles from the truth record '" 712 << mclistHandle.
provenance()->inputTag() <<
"':\n";
720 partCol->push_back(std::move(p));
722 tpassn->addSingle(mct, (*makeMCPartPtr)(partCol->size() - 1), truthInfo);
729 droppedPartCol->reserve(droppedParticleList.
size());
731 for (
auto const& partPair : droppedParticleList) {
739 droppedPartCol->push_back(std::move(mini_mcp));
745 mf::LogInfo(
"LArG4") <<
"Dump sim::ParticleList; size()=" << particleList.size() <<
"\n" 754 G4SDManager* sdManager = G4SDManager::GetSDMpointer();
758 sdManager->FindSensitiveDetector(
"OpDetSensitiveDetector"));
763 if (!lgp->NoPhotonPropagation()) {
765 for (
int Reflected = 0; Reflected <= 1; Reflected++) {
769 MF_LOG_DEBUG(
"Optical") <<
"Storing OpDet Hit Collection in Event";
770 std::vector<sim::SimPhotons>& ThePhotons =
773 PhotonColRefl->reserve(ThePhotons.size());
775 PhotonCol->reserve(ThePhotons.size());
776 for (
auto& it : ThePhotons) {
778 PhotonColRefl->push_back(std::move(it));
780 PhotonCol->push_back(std::move(it));
784 MF_LOG_DEBUG(
"Optical") <<
"Storing OpDet Hit Collection in Event";
786 std::map<int, std::map<int, int>> ThePhotons =
789 if (
size(ThePhotons) > 0) {
790 LitePhotonCol->reserve(ThePhotons.size());
791 for (
auto const& [opChannel, detectedPhotons] : ThePhotons) {
796 LitePhotonColRefl->push_back(std::move(ph));
798 LitePhotonCol->push_back(std::move(ph));
803 *cOpDetBacktrackerRecordColRefl =
806 *cOpDetBacktrackerRecordCol =
811 if (lgp->FillSimEnergyDeposits()) {
814 for (
auto& [volumeName, edepCol] : edepMap) {
816 auto const& destColl =
817 boost::contains(volumeName,
"TPCActive") ? edepCol_TPCActive : edepCol_Other;
818 append(*destColl, std::move(edepCol));
823 if (!lgp->NoElectronPropagation()) {
828 std::set<LArVoxelReadout*> ReadoutList;
830 for (
unsigned int c = 0; c < geom->
Ncryostats(); ++c) {
836 std::map<unsigned int, unsigned int> channelToscCol;
839 for (
unsigned int t = 0; t < ntpcs; ++t) {
840 std::string name(
"LArVoxelSD");
841 std::ostringstream sstr;
842 sstr << name <<
"_Cryostat" << c <<
"_TPC" << t;
846 G4VSensitiveDetector* sd = sdManager->FindSensitiveDetector(sstr.str(),
false);
848 if (!sd) sd = sdManager->FindSensitiveDetector(name,
false);
853 <<
"Sensitive detector for cryostat " << c <<
" TPC " << t <<
" not found (neither '" 854 << sstr.str() <<
"' nor '" << name <<
"' exist)\n";
862 if (!larVoxelReadout) {
864 <<
"Sensitive detector '" << sd->GetName() <<
"' is not a LArVoxelReadout object\n";
868 if (!
empty(channels)) {
869 MF_LOG_DEBUG(
"LArG4") <<
"now put " << channels.size() <<
" SimChannels from C=" << c
870 <<
" T=" << t <<
" into the event";
873 for (
auto ch_pair : channels) {
881 unsigned int ichan = sc.
Channel();
882 auto itertest = channelToscCol.find(ichan);
883 if (itertest == channelToscCol.end()) {
884 channelToscCol[ichan] = scCol->size();
885 scCol->emplace_back(std::move(sc));
888 unsigned int idtest = itertest->second;
890 for (
auto const& tdcide : tdcideMap) {
891 for (
auto const& ide : tdcide.second) {
892 double xyz[3] = {ide.x, ide.y, ide.z};
893 scCol->at(idtest).AddIonizationElectrons(ide.trackID,
904 scCol->emplace_back(std::move(sc));
909 ReadoutList.insert(const_cast<LArVoxelReadout*>(larVoxelReadout));
915 larVoxelReadout->ClearSimChannels();
922 adCol->reserve(auxDetGeom->NAuxDets());
923 for (
unsigned int a = 0; a < auxDetGeom->NAuxDets(); ++a) {
927 auto const& ad = auxDetGeom->AuxDet(a);
928 for (
size_t sv = 0; sv < ad.NSensitiveVolume(); ++sv) {
932 std::stringstream name;
933 name <<
"AuxDetSD_AuxDet" << a <<
"_" << sv;
934 G4VSensitiveDetector* sd = sdManager->FindSensitiveDetector(name.str().c_str());
937 <<
"Sensitive detector '" << name.str() <<
"' does not exist\n";
943 MF_LOG_DEBUG(
"LArG4") <<
"now put the AuxDetSimTracks in the event";
946 adCol->push_back(adsc);
947 auxDetReadout->
clear();
952 mf::LogInfo(
"LArG4") <<
"Geant4 simulated " << nGeneratedParticles
953 <<
" MC particles, we keep " << partCol->size() <<
" .";
958 <<
"Event " << evt.
id() <<
": " << scCol->size() <<
" channels with signal";
959 unsigned int nChannels = 0;
962 out <<
" #" << nChannels <<
": ";
969 if (!lgp->NoElectronPropagation()) evt.
put(std::move(scCol));
971 evt.
put(std::move(adCol));
972 if (partCol) evt.
put(std::move(partCol));
973 if (droppedPartCol) {
974 std::cout <<
"LArG4 dropped particles length = " << droppedPartCol->size() << std::endl;
975 evt.
put(std::move(droppedPartCol));
977 if (tpassn) evt.
put(std::move(tpassn));
978 if (!lgp->NoPhotonPropagation()) {
980 evt.
put(std::move(PhotonCol));
984 evt.
put(std::move(LitePhotonCol));
985 evt.
put(std::move(cOpDetBacktrackerRecordCol));
987 evt.
put(std::move(LitePhotonColRefl),
"Reflected");
988 evt.
put(std::move(cOpDetBacktrackerRecordColRefl),
"Reflected");
993 if (lgp->FillSimEnergyDeposits()) {
994 evt.
put(std::move(edepCol_TPCActive),
"TPCActive");
995 evt.
put(std::move(edepCol_Other),
"Other");
std::vector< std::string > fInputLabels
std::unique_ptr< g4b::G4Helper > fG4Help
G4 interface object.
base_engine_t & createEngine(seed_t seed)
Store parameters for running LArG4.
Collection of all it takes to set up this object.
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
std::vector< sim::OpDetBacktrackerRecord > YieldReflectedOpDetBacktrackerRecords()
bool fStoreDroppedMCParticles
Whether to keep a sim::MCParticleLite list of dropped particles.
bool KeepEMShowerDaughters() const
Energy deposited on a readout channel by simulated tracks.
Stores material properties and sends them to GEANT4 geometry.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
void GetPropertiesFromServices(detinfo::DetectorPropertiesData const &detProp)
Imports properties from LArSoft services.
std::vector< VolumeInfo_t > AllVolumeInfo_t
EDProducer(fhicl::ParameterSet const &pset)
simb::Origin_t Origin() const
void produces(std::string const &instanceName={}, Persistable const persistable=Persistable::Yes)
bool fMakeMCParticles
Whether to keep a sim::MCParticle list.
Class def header for MCParticleLite data container.
Contains data associated to particles from detector simulation.
cout<< "Opened file "<< fin<< " ixs= "<< ixs<< endl;if(ixs==0) hhh=(TH1F *) fff-> Get("h1")
Runs Geant4 simulation and propagation of electrons and photons to readout.
std::unordered_map< std::string, std::vector< sim::SimEnergyDeposit > > YieldSimEnergyDeposits()
Yields the map of energy deposits by volume name, and resets the internal one.
bool NoPhotonPropagation() const
Use Geant4 to run the LArSoft detector simulation.
unsigned int Ncryostats() const
Returns the number of cryostats in the detector.
std::vector< std::string > fKeepParticlesInVolumes
Only write particles that have trajectories through these volumes.
bool StoreTrajectories() const
std::map< int, int > DetectedPhotons
Number of photons detected at each given time: time tick -> photons.
Define the "parallel" geometry that's seen by the LAr Voxels.
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
bool fSparsifyTrajectories
Sparsify MCParticle Trajectories.
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
int fSmartStacking
Whether to instantiate and use class to.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Collection of particles crossing one auxiliary detector cell.
bool StoreReflected() const
bool fdumpSimChannels
Whether each event's sim::Channel will be displayed.
std::vector< sim::SimPhotons > & GetPhotons(bool Reflected=false)
larg4::ParticleListAction * fparticleListAction
Geant4 user action to particle information.
Simulation objects for optical detectors.
std::string OpDetGeoName() const
Get name of opdet geometry element.
sim::ParticleList && YieldList()
void ResetTrackIDOffset()
std::map< unsigned int, sim::SimChannel > ChannelMap_t
Type of map channel -> sim::SimChannel.
object containing MC truth information necessary for making RawDigits and doing back tracking ...
Use Geant4's user "hooks" to maintain a list of particles generated by Geant4.
bool NoElectronPropagation() const
Utility functions to print MC truth information.
#define DEFINE_ART_MODULE(klass)
static bool isDropped(simb::MCParticle const *p)
returns whether the specified particle has been marked as dropped
static void AddAndAdoptAction(UserAction *a)
Provenance const * provenance() const
LArG4(fhicl::ParameterSet const &pset)
art framework interface to geometry description for auxiliary detectors
void DumpMCTruth(Stream &&out, simb::MCTruth const &truth, unsigned int pointsPerLine, std::string indent, std::string firstIndent)
Dumps the content of the specified MC truth in the output stream.
bool FillSimEnergyDeposits() const
int OpChannel
Optical detector channel associated to this data.
unsigned int NTPC() const
Number of TPCs in this cryostat.
sim::ParticleList && YieldDroppedList()
Yields the (dropped) ParticleList accumulated during the current event.
void ParticleFilter(std::unique_ptr< util::PositionInVolumeFilter > &&filter)
Grabs a particle filter.
GeneratedParticleIndex_t GetPrimaryTruthIndex(int trackId) const
Returns the index of primary truth (sim::NoGeneratorIndex if none).
bool fdumpParticleList
Whether each event's sim::ParticleList will be displayed.
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
CryostatGeo const & Cryostat(CryostatID const &cryoid=details::cryostat_zero) const
Returns the specified cryostat.
unsigned int NOpDets() const
Number of OpDets in the whole detector.
void UpdateGeometry(G4LogicalVolumeStore *lvs)
Updates the material properties with the collected values.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
double ParticleKineticEnergyCut() const
raw::ChannelID_t Channel() const
Returns the readout channel this object describes.
static OpDetPhotonTable * Instance(bool LitePhotons=false)
A Geant4 sensitive detector that accumulates voxel information.
Define the "parallel" geometry that's seen by the AuxDet.
Compact representation of photons on a channel.
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
std::unique_ptr< util::PositionInVolumeFilter > CreateParticleVolumeFilter(std::set< std::string > const &vol_names) const
Pointer used for correctly updating the clock data state.
static UserActionManager * Instance()
std::vector< sim::OpDetBacktrackerRecord > YieldOpDetBacktrackerRecords()
Singleton to access a unified treatment of ionization and scintillation in LAr.
Contains information about a generated particle.
contains information for a single step in the detector simulation
const simb::Origin_t & Origin() const
void produce(art::Event &evt) override
static IonizationAndScintillation * CreateInstance(detinfo::DetectorPropertiesData const &detProp, CLHEP::HepRandomEngine &engine)
object containing MC truth information necessary for making RawDigits and doing back tracking ...
std::string fG4PhysListName
predefined physics list to use if not making a custom one
std::string const & GDMLFile() const
Returns the full directory path to the GDML file source.
bool fCheckOverlaps
Whether to use the G4 overlap checker.
Transports energy depositions from GEANT4 to TPC channels.
TDCIDEs_t const & TDCIDEMap() const
Returns all the deposited energy information as stored.
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Defines classes to filter particles based on their trajectory.
AllPhysicsLists fAllPhysicsLists
std::map< int, std::map< int, int > > GetLitePhotons(bool Reflected=false)
detinfo::DetectorPropertiesData fDetProp
Must outlive fAllPhysicsLists!
Particle list in DetSim contains Monte Carlo particle information.
CLHEP::HepRandomEngine & fEngine
void SparsifyTrajectory(double margin=0.1, bool keep_second_to_last=false)
void beginRun(art::Run &run) override
void ClearTable(size_t nch=0)
A Geant4 sensitive detector that accumulates information.
sim::AuxDetSimChannel const GetAuxDetSimChannel() const
art framework interface to geometry description
void DumpMCParticle(Stream &&out, simb::MCParticle const &particle, std::string indent, std::string firstIndent)
Dumps the content of the specified particle in the output stream.
cet::coded_exception< error, detail::translate > exception
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
bool UseLitePhotons() const
void ClearEnergyDeposits()
LArVoxelReadoutGeometry * fVoxelReadoutGeometry
The data type to uniquely identify a cryostat.
std::vector< Handle< PROD > > getMany(SelectorBase const &selector=MatchAllSelector{}) const