40 #include "cetlib/search_path.h" 41 #include "cetlib_except/exception.h" 79 #include "Geant4/G4LogicalVolumeStore.hh" 80 #include "Geant4/G4RunManager.hh" 81 #include "Geant4/G4SDManager.hh" 82 #include "Geant4/G4VSensitiveDetector.hh" 83 #include "Geant4/G4VUserDetectorConstruction.hh" 89 #include "boost/algorithm/string.hpp" 95 class LArVoxelListAction;
327 std::unique_ptr<g4b::G4Helper>
fG4Help{
nullptr};
346 std::vector<std::string>
361 std::set<std::string>
const& vol_names)
const;
387 template <
typename T>
388 std::vector<T>& append(std::vector<T>& dest, std::vector<T>&& source)
391 dest = std::move(source);
393 dest.insert(dest.end(), std::move_iterator{
begin(source)}, std::move_iterator{
end(source)});
394 source = std::vector<T>{};
408 ,
fG4PhysListName(pset.get<std::string>(
"G4PhysListName",
"larg4::PhysicsList"))
432 <<
"Option `DumpParticleList` can't be set if `MakeMCParticles` is unset.\n";
436 <<
"Option `KeepParticlesInVolumes` can't be set if `MakeMCParticles` is unset.\n";
440 if (pset.has_key(
"Seed")) {
442 <<
"The configuration of LArG4 module has the discontinued 'Seed' parameter.\n" 443 "Seeds are now controlled by two parameters: 'GEANTSeed' and 'PropagationSeed'.";
451 createEngine(0,
"G4Engine",
"GEANT"),
"G4Engine",
"GEANT", pset,
"GEANTSeed");
455 bool useInputLabels =
456 pset.get_if_present<std::vector<std::string>>(
"InputLabels",
fInputLabels);
475 produces<std::vector<sim::SimPhotons>>();
476 if (
fStoreReflected) { produces<std::vector<sim::SimPhotons>>(
"Reflected"); }
479 produces<std::vector<sim::SimPhotonsLite>>();
480 produces<std::vector<sim::OpDetBacktrackerRecord>>();
482 produces<std::vector<sim::SimPhotonsLite>>(
"Reflected");
483 produces<std::vector<sim::OpDetBacktrackerRecord>>(
"Reflected");
489 produces<std::vector<sim::SimEnergyDeposit>>(
"TPCActive");
490 produces<std::vector<sim::SimEnergyDeposit>>(
"Other");
494 produces<std::vector<simb::MCParticle>>();
495 produces<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>();
499 produces<std::vector<sim::AuxDetSimChannel>>();
502 cet::search_path sp(
"FW_SEARCH_PATH");
504 sp.find_file(pset.get<std::string>(
"GeantCommandFile"),
fG4MacroPath);
529 std::vector<G4VUserParallelWorld*> pworlds;
551 fG4Help->SetParallelWorlds(pworlds);
579 fG4Help->GetRunManager()->SetUserAction(stacking_action);
592 std::set<std::string>
const& vol_names)
const 595 if (
empty(vol_names))
return {};
599 std::vector<std::vector<TGeoNode const*>> node_paths = geom.FindAllVolumePaths(vol_names);
603 GeoVolumePairs.reserve(node_paths.size());
607 for (
size_t iVolume = 0; iVolume < node_paths.size(); ++iVolume) {
608 std::vector<TGeoNode const*> path = node_paths[iVolume];
610 auto pTransl =
new TGeoTranslation(0., 0., 0.);
611 auto pRot =
new TGeoRotation();
612 for (TGeoNode
const* node : path) {
613 TGeoTranslation thistranslate(*node->GetMatrix());
614 TGeoRotation thisrotate(*node->GetMatrix());
615 pTransl->Add(&thistranslate);
616 *pRot = *pRot * thisrotate;
621 auto pTransl2 =
new TGeoTranslation(
622 pTransl->GetTranslation()[0], pTransl->GetTranslation()[1], pTransl->GetTranslation()[2]);
623 double phi = 0., theta = 0., psi = 0.;
624 pRot->GetAngles(phi, theta, psi);
625 auto pRot2 =
new TGeoRotation();
626 pRot2->SetAngles(phi, theta, psi);
628 auto pTransf =
new TGeoCombiTrans(*pTransl2, *pRot2);
629 GeoVolumePairs.emplace_back(node_paths[iVolume].back()->GetVolume(), pTransf);
632 return std::make_unique<util::PositionInVolumeFilter>(std::move(GeoVolumePairs));
645 auto scCol = std::make_unique<std::vector<sim::SimChannel>>();
646 auto adCol = std::make_unique<std::vector<sim::AuxDetSimChannel>>();
651 auto partCol =
fMakeMCParticles ? std::make_unique<std::vector<simb::MCParticle>>() :
nullptr;
652 auto droppedPartCol =
654 auto PhotonCol = std::make_unique<std::vector<sim::SimPhotons>>();
655 auto PhotonColRefl = std::make_unique<std::vector<sim::SimPhotons>>();
656 auto LitePhotonCol = std::make_unique<std::vector<sim::SimPhotonsLite>>();
657 auto LitePhotonColRefl = std::make_unique<std::vector<sim::SimPhotonsLite>>();
658 auto cOpDetBacktrackerRecordCol = std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
659 auto cOpDetBacktrackerRecordColRefl =
660 std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
662 std::optional<art::PtrMaker<simb::MCParticle>> makeMCPartPtr;
666 auto edepCol_TPCActive = std::make_unique<std::vector<sim::SimEnergyDeposit>>();
667 auto edepCol_Other = std::make_unique<std::vector<sim::SimEnergyDeposit>>();
682 std::vector<art::Handle<std::vector<simb::MCTruth>>> mclists;
685 mclists = evt.
getMany<std::vector<simb::MCTruth>>();
692 unsigned int nGeneratedParticles = 0;
695 for (
size_t mcl = 0; mcl < mclists.size(); ++mcl) {
699 for (
size_t m = 0; m < mclistHandle->size(); ++m) {
707 if (!partCol)
continue;
713 for (
auto const& partPair : particleList) {
715 ++nGeneratedParticles;
724 if (!truthInfo.hasGeneratedParticleIndex() && (p.
Mother() == 0)) {
727 error <<
"Failed to match primary particle:\n";
729 error <<
"\nwith particles from the truth record '" 730 << mclistHandle.
provenance()->inputTag() <<
"':\n";
738 partCol->push_back(std::move(p));
740 tpassn->addSingle(mct, (*makeMCPartPtr)(partCol->size() - 1), truthInfo);
748 droppedPartCol->reserve(droppedParticleList.
size());
750 for (
auto const& partPair : droppedParticleList) {
758 droppedPartCol->push_back(std::move(mini_mcp));
764 mf::LogInfo(
"LArG4") <<
"Dump sim::ParticleList; size()=" << particleList.size() <<
"\n" 773 G4SDManager* sdManager = G4SDManager::GetSDMpointer();
777 sdManager->FindSensitiveDetector(
"OpDetSensitiveDetector"));
783 if (!lgp->NoPhotonPropagation()) {
785 for (
int Reflected = 0; Reflected <= 1; Reflected++) {
789 MF_LOG_DEBUG(
"Optical") <<
"Storing OpDet Hit Collection in Event";
790 std::vector<sim::SimPhotons>& ThePhotons =
793 PhotonColRefl->reserve(ThePhotons.size());
795 PhotonCol->reserve(ThePhotons.size());
796 for (
auto& it : ThePhotons) {
798 PhotonColRefl->push_back(std::move(it));
800 PhotonCol->push_back(std::move(it));
804 MF_LOG_DEBUG(
"Optical") <<
"Storing OpDet Hit Collection in Event";
806 std::map<int, std::map<int, int>> ThePhotons =
809 if (
size(ThePhotons) > 0) {
810 LitePhotonCol->reserve(ThePhotons.size());
811 for (
auto const& [opChannel, detectedPhotons] : ThePhotons) {
816 LitePhotonColRefl->push_back(std::move(ph));
818 LitePhotonCol->push_back(std::move(ph));
823 *cOpDetBacktrackerRecordColRefl =
826 *cOpDetBacktrackerRecordCol =
831 if (lgp->FillSimEnergyDeposits()) {
834 for (
auto& [volumeName, edepCol] : edepMap) {
836 auto const& destColl =
837 boost::contains(volumeName,
"TPCActive") ? edepCol_TPCActive : edepCol_Other;
838 append(*destColl, std::move(edepCol));
843 if (!lgp->NoElectronPropagation()) {
848 std::set<LArVoxelReadout*> ReadoutList;
850 for (
unsigned int c = 0; c < geom->
Ncryostats(); ++c) {
856 std::map<unsigned int, unsigned int> channelToscCol;
859 for (
unsigned int t = 0; t < ntpcs; ++t) {
860 std::string name(
"LArVoxelSD");
861 std::ostringstream sstr;
862 sstr << name <<
"_Cryostat" << c <<
"_TPC" << t;
866 G4VSensitiveDetector* sd = sdManager->FindSensitiveDetector(sstr.str(),
false);
868 if (!sd) sd = sdManager->FindSensitiveDetector(name,
false);
873 <<
"Sensitive detector for cryostat " << c <<
" TPC " << t <<
" not found (neither '" 874 << sstr.str() <<
"' nor '" << name <<
"' exist)\n";
882 if (!larVoxelReadout) {
884 <<
"Sensitive detector '" << sd->GetName() <<
"' is not a LArVoxelReadout object\n";
888 if (!
empty(channels)) {
889 MF_LOG_DEBUG(
"LArG4") <<
"now put " << channels.size() <<
" SimChannels from C=" << c
890 <<
" T=" << t <<
" into the event";
893 for (
auto ch_pair : channels) {
900 unsigned int ichan = sc.
Channel();
901 auto itertest = channelToscCol.find(ichan);
902 if (itertest == channelToscCol.end()) {
903 channelToscCol[ichan] = scCol->size();
904 scCol->emplace_back(std::move(sc));
907 unsigned int idtest = itertest->second;
909 for (
auto const& tdcide : tdcideMap) {
910 for (
auto const& ide : tdcide.second) {
911 double xyz[3] = {ide.x, ide.y, ide.z};
912 scCol->at(idtest).AddIonizationElectrons(ide.trackID,
923 scCol->emplace_back(std::move(sc));
928 ReadoutList.insert(const_cast<LArVoxelReadout*>(larVoxelReadout));
934 larVoxelReadout->ClearSimChannels();
942 for (
unsigned int a = 0; a < geom->
NAuxDets(); ++a) {
951 std::stringstream name;
952 name <<
"AuxDetSD_AuxDet" << a <<
"_" << sv;
953 G4VSensitiveDetector* sd = sdManager->FindSensitiveDetector(name.str().c_str());
956 <<
"Sensitive detector '" << name.str() <<
"' does not exist\n";
962 MF_LOG_DEBUG(
"LArG4") <<
"now put the AuxDetSimTracks in the event";
965 adCol->push_back(adsc);
966 auxDetReadout->
clear();
971 mf::LogInfo(
"LArG4") <<
"Geant4 simulated " << nGeneratedParticles
972 <<
" MC particles, we keep " << partCol->size() <<
" .";
977 <<
"Event " << evt.
id() <<
": " << scCol->size() <<
" channels with signal";
978 unsigned int nChannels = 0;
981 out <<
" #" << nChannels <<
": ";
988 if (!lgp->NoElectronPropagation()) evt.
put(std::move(scCol));
990 evt.
put(std::move(adCol));
991 if (partCol) evt.
put(std::move(partCol));
992 if (droppedPartCol) {
993 std::cout <<
"LArG4 dropped particles length = " << droppedPartCol->size() << std::endl;
994 evt.
put(std::move(droppedPartCol));
996 if (tpassn) evt.
put(std::move(tpassn));
997 if (!lgp->NoPhotonPropagation()) {
999 evt.
put(std::move(PhotonCol));
1003 evt.
put(std::move(LitePhotonCol));
1004 evt.
put(std::move(cOpDetBacktrackerRecordCol));
1006 evt.
put(std::move(LitePhotonColRefl),
"Reflected");
1007 evt.
put(std::move(cOpDetBacktrackerRecordColRefl),
"Reflected");
1012 if (lgp->FillSimEnergyDeposits()) {
1013 evt.
put(std::move(edepCol_TPCActive),
"TPCActive");
1014 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)
CLHEP::HepRandomEngine * propGen
Random engine for charge propagation.
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.
larg4::LArVoxelReadout::Setup_t readoutSetup
Set up data for LArVoxelReadout.
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.
CryostatGeo const & Cryostat(CryostatID const &cryoid=cryostat_zero) const
Returns the specified cryostat.
std::vector< std::string > fKeepParticlesInVolumes
Only write particles that have trajectories through these volumes.
std::string OpDetGeoName(CryostatID const &cid=cryostat_zero) const
Returns gdml string which gives sensitive opdet name.
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.
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)
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.
size_t NSensitiveVolume() const
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 ...
AuxDetGeo const & AuxDet(unsigned int const ad=0) const
Returns the specified auxiliary detector.
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.
double offPlaneMargin
Margin for charge recovery (see LArVoxelReadout).
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
unsigned int NAuxDets() const
Returns the number of auxiliary detectors.
The data type to uniquely identify a cryostat.
std::vector< Handle< PROD > > getMany(SelectorBase const &selector=MatchAllSelector{}) const