21 #include "nug4/G4Base/G4Helper.h" 41 #include "cetlib_except/exception.h" 46 #include "nurandom/RandomUtils/NuRandomService.h" 73 #include "nug4/G4Base/UserActionManager.h" 74 #include "nug4/ParticleNavigation/ParticleList.h" 78 #include "Geant4/G4LogicalVolumeStore.hh" 79 #include "Geant4/G4RunManager.hh" 80 #include "Geant4/G4SDManager.hh" 81 #include "Geant4/G4VSensitiveDetector.hh" 82 #include "Geant4/G4VUserDetectorConstruction.hh" 88 #include "boost/algorithm/string.hpp" 94 class LArVoxelListAction;
326 std::unique_ptr<g4b::G4Helper>
fG4Help{
nullptr};
343 std::vector<std::string>
358 std::set<std::string>
const& vol_names)
const;
384 template <
typename T>
386 append(std::vector<T>&
dest, std::vector<T>&& source)
391 dest.insert(dest.end(), std::move_iterator{
begin(source)}, std::move_iterator{
end(source)});
392 source = std::vector<T>{};
416 ->createEngine(*
this,
"HepJamesRandom",
"propagation", pset,
"PropagationSeed"))
426 <<
"Option `DumpParticleList` can't be set if `MakeMCParticles` is unset.\n";
430 <<
"Option `KeepParticlesInVolumes` can't be set if `MakeMCParticles` is unset.\n";
434 if (pset.has_key(
"Seed")) {
436 <<
"The configuration of LArG4 module has the discontinued 'Seed' parameter.\n" 437 "Seeds are now controlled by two parameters: 'GEANTSeed' and 'PropagationSeed'.";
445 *
this,
"G4Engine",
"GEANT", pset,
"GEANTSeed");
449 bool useInputLabels =
450 pset.get_if_present<std::vector<std::string>>(
"InputLabels",
fInputLabels);
469 produces<std::vector<sim::SimPhotons>>();
470 if (
fStoreReflected) { produces<std::vector<sim::SimPhotons>>(
"Reflected"); }
473 produces<std::vector<sim::SimPhotonsLite>>();
474 produces<std::vector<sim::OpDetBacktrackerRecord>>();
476 produces<std::vector<sim::SimPhotonsLite>>(
"Reflected");
477 produces<std::vector<sim::OpDetBacktrackerRecord>>(
"Reflected");
483 produces<std::vector<sim::SimEnergyDeposit>>(
"TPCActive");
484 produces<std::vector<sim::SimEnergyDeposit>>(
"Other");
488 produces<std::vector<simb::MCParticle>>();
489 produces<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>();
492 produces<std::vector<sim::AuxDetSimChannel>>();
523 std::vector<G4VUserParallelWorld*> pworlds;
545 fG4Help->SetParallelWorlds(pworlds);
552 g4b::UserActionManager* uaManager = g4b::UserActionManager::Instance();
572 fG4Help->GetRunManager()->SetUserAction(stacking_action);
585 std::unique_ptr<util::PositionInVolumeFilter>
589 if (
empty(vol_names))
return {};
593 std::vector<std::vector<TGeoNode const*>> node_paths = geom.FindAllVolumePaths(vol_names);
597 GeoVolumePairs.reserve(node_paths.size());
601 for (
size_t iVolume = 0; iVolume < node_paths.size(); ++iVolume) {
602 std::vector<TGeoNode const*> path = node_paths[iVolume];
604 auto pTransl =
new TGeoTranslation(0., 0., 0.);
605 auto pRot =
new TGeoRotation();
606 for (TGeoNode
const* node : path) {
607 TGeoTranslation thistranslate(*node->GetMatrix());
608 TGeoRotation thisrotate(*node->GetMatrix());
609 pTransl->Add(&thistranslate);
610 *pRot = *pRot * thisrotate;
615 auto pTransl2 =
new TGeoTranslation(
616 pTransl->GetTranslation()[0], pTransl->GetTranslation()[1], pTransl->GetTranslation()[2]);
617 double phi = 0.,
theta = 0., psi = 0.;
618 pRot->GetAngles(phi,
theta, psi);
619 auto pRot2 =
new TGeoRotation();
620 pRot2->SetAngles(phi,
theta, psi);
622 auto pTransf =
new TGeoCombiTrans(*pTransl2, *pRot2);
623 GeoVolumePairs.emplace_back(node_paths[iVolume].back()->GetVolume(), pTransf);
626 return std::make_unique<util::PositionInVolumeFilter>(
std::move(GeoVolumePairs));
640 auto scCol = std::make_unique<std::vector<sim::SimChannel>>();
641 auto adCol = std::make_unique<std::vector<sim::AuxDetSimChannel>>();
644 std::make_unique<art::Assns<simb::MCTruth, simb::MCParticle, sim::GeneratedParticleInfo>>() :
648 std::make_unique<std::vector<simb::MCParticle>>() :
650 auto PhotonCol = std::make_unique<std::vector<sim::SimPhotons>>();
651 auto PhotonColRefl = std::make_unique<std::vector<sim::SimPhotons>>();
652 auto LitePhotonCol = std::make_unique<std::vector<sim::SimPhotonsLite>>();
653 auto LitePhotonColRefl = std::make_unique<std::vector<sim::SimPhotonsLite>>();
654 auto cOpDetBacktrackerRecordCol = std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
655 auto cOpDetBacktrackerRecordColRefl =
656 std::make_unique<std::vector<sim::OpDetBacktrackerRecord>>();
658 std::optional<art::PtrMaker<simb::MCParticle>> makeMCPartPtr;
662 auto edepCol_TPCActive = std::make_unique<std::vector<sim::SimEnergyDeposit>>();
663 auto edepCol_Other = std::make_unique<std::vector<sim::SimEnergyDeposit>>();
678 std::vector<art::Handle<std::vector<simb::MCTruth>>> mclists;
681 mclists = evt.
getMany<std::vector<simb::MCTruth>>();
688 unsigned int nGeneratedParticles = 0;
691 for (
size_t mcl = 0; mcl < mclists.size(); ++mcl) {
695 for (
size_t m = 0;
m < mclistHandle->size(); ++
m) {
703 if (!partCol)
continue;
709 for (
auto const& partPair : particleList) {
711 ++nGeneratedParticles;
720 if (!truthInfo.hasGeneratedParticleIndex() && (p.
Mother() == 0)) {
723 error <<
"Failed to match primary particle:\n";
725 error <<
"\nwith particles from the truth record '" 726 << mclistHandle.
provenance()->inputTag() <<
"':\n";
736 tpassn->addSingle(mct, (*makeMCPartPtr)(partCol->size() - 1), truthInfo);
742 mf::LogInfo(
"LArG4") <<
"Dump sim::ParticleList; size()=" << particleList.size() <<
"\n" 751 G4SDManager* sdManager = G4SDManager::GetSDMpointer();
755 sdManager->FindSensitiveDetector(
"OpDetSensitiveDetector"));
761 if (!lgp->NoPhotonPropagation()) {
763 for (
int Reflected = 0; Reflected <= 1; Reflected++) {
767 MF_LOG_DEBUG(
"Optical") <<
"Storing OpDet Hit Collection in Event";
768 std::vector<sim::SimPhotons>& ThePhotons =
771 PhotonColRefl->reserve(ThePhotons.size());
773 PhotonCol->reserve(ThePhotons.size());
774 for (
auto& it : ThePhotons) {
782 MF_LOG_DEBUG(
"Optical") <<
"Storing OpDet Hit Collection in Event";
784 std::map<int, std::map<int, int>> ThePhotons =
787 if (
size(ThePhotons) > 0) {
788 LitePhotonCol->reserve(ThePhotons.size());
789 for (
auto const& [opChannel, detectedPhotons] : ThePhotons) {
794 LitePhotonColRefl->push_back(
std::move(ph));
801 *cOpDetBacktrackerRecordColRefl =
804 *cOpDetBacktrackerRecordCol =
809 if (lgp->FillSimEnergyDeposits()) {
812 for (
auto& [volumeName, edepCol] : edepMap) {
814 auto const& destColl =
815 boost::contains(volumeName,
"TPCActive") ? edepCol_TPCActive : edepCol_Other;
821 if (!lgp->NoElectronPropagation()) {
826 std::set<LArVoxelReadout*> ReadoutList;
834 std::map<unsigned int, unsigned int> channelToscCol;
837 for (
unsigned int t = 0;
t < ntpcs; ++
t) {
839 std::ostringstream sstr;
840 sstr << name <<
"_Cryostat" <<
c <<
"_TPC" <<
t;
844 G4VSensitiveDetector* sd = sdManager->FindSensitiveDetector(sstr.str(),
false);
846 if (!sd) sd = sdManager->FindSensitiveDetector(name,
false);
851 <<
"Sensitive detector for cryostat " <<
c <<
" TPC " << t <<
" not found (neither '" 852 << sstr.str() <<
"' nor '" << name <<
"' exist)\n";
860 if (!larVoxelReadout) {
862 <<
"Sensitive detector '" << sd->GetName() <<
"' is not a LArVoxelReadout object\n";
866 if (!
empty(channels)) {
867 MF_LOG_DEBUG(
"LArG4") <<
"now put " << channels.size() <<
" SimChannels from C=" <<
c 868 <<
" T=" << t <<
" into the event";
871 for (
auto ch_pair : channels) {
878 unsigned int ichan = sc.
Channel();
879 auto itertest = channelToscCol.find(ichan);
880 if (itertest == channelToscCol.end()) {
881 channelToscCol[ichan] = scCol->size();
885 unsigned int idtest = itertest->second;
887 for (
auto const& tdcide : tdcideMap) {
888 for (
auto const& ide : tdcide.second) {
889 double xyz[3] = {ide.x, ide.y, ide.z};
890 scCol->at(idtest).AddIonizationElectrons(
891 ide.trackID, tdcide.first, ide.numElectrons, xyz, ide.energy);
902 ReadoutList.insert(const_cast<LArVoxelReadout*>(larVoxelReadout));
908 larVoxelReadout->ClearSimChannels();
916 for (
unsigned int a = 0;
a < geom->
NAuxDets(); ++
a) {
925 std::stringstream
name;
926 name <<
"AuxDetSD_AuxDet" <<
a <<
"_" << sv;
927 G4VSensitiveDetector* sd = sdManager->FindSensitiveDetector(name.str().c_str());
930 <<
"Sensitive detector '" << name.str() <<
"' does not exist\n";
936 MF_LOG_DEBUG(
"LArG4") <<
"now put the AuxDetSimTracks in the event";
939 adCol->push_back(adsc);
940 auxDetReadout->
clear();
945 mf::LogInfo(
"LArG4") <<
"Geant4 simulated " << nGeneratedParticles <<
" MC particles, we keep " 946 << partCol->size() <<
" .";
951 <<
"Event " << evt.
id() <<
": " << scCol->size() <<
" channels with signal";
952 unsigned int nChannels = 0;
955 out <<
" #" << nChannels <<
": ";
962 if (!lgp->NoElectronPropagation()) evt.
put(
std::move(scCol));
967 if (!lgp->NoPhotonPropagation()) {
977 evt.
put(
std::move(cOpDetBacktrackerRecordColRefl),
"Reflected");
982 if (lgp->FillSimEnergyDeposits()) {
std::vector< std::string > fInputLabels
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
std::unique_ptr< g4b::G4Helper > fG4Help
G4 interface object.
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 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
std::string OpDetGeoName(unsigned int c=0) const
Returns gdml string which gives sensitive opdet name.
void GetPropertiesFromServices(detinfo::DetectorPropertiesData const &detProp)
Imports properties from LArSoft services.
std::vector< VolumeInfo_t > AllVolumeInfo_t
EDProducer(fhicl::ParameterSet const &pset)
void produces(std::string const &instanceName={}, Persistable const persistable=Persistable::Yes)
bool fMakeMCParticles
Whether to keep a sim::MCParticle list.
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
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.
Utility functions to print MC truth information.
art framework interface to geometry description
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.
bool fSparsifyTrajectories
Sparsify MCParticle Trajectories.
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
std::string GDMLFile() const
Returns the full directory path to the GDML file source.
bool fdumpSimChannels
Whether each event's sim::Channel will be displayed.
larg4::ParticleListAction * fparticleListAction
Geant4 user action to particle information.
Simulation objects for optical detectors.
sim::ParticleList && YieldList()
void ResetTrackIDOffset()
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
std::map< unsigned int, sim::SimChannel > ChannelMap_t
Type of map channel -> sim::SimChannel.
std::vector< sim::SimPhotons > & GetPhotons(bool Reflected=false)
bool NoElectronPropagation() const
#define DEFINE_ART_MODULE(klass)
static bool isDropped(simb::MCParticle const *p)
returns whether the specified particle has been marked as dropped
Provenance const * provenance() const
LArG4(fhicl::ParameterSet const &pset)
std::vector< Handle< PROD > > getMany(SelectorBase const &selector=MatchAllSelector{}) const
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.
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
size_t NSensitiveVolume() const
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.
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.
Contains data associated to particles from detector simulation.
double offPlaneMargin
Margin for charge recovery (see LArVoxelReadout).
std::unique_ptr< util::PositionInVolumeFilter > CreateParticleVolumeFilter(std::set< std::string > const &vol_names) const
Pointer used for correctly updating the clock data state.
std::vector< sim::OpDetBacktrackerRecord > YieldOpDetBacktrackerRecords()
Contains information about a generated particle.
contains information for a single step in the detector simulation
void produce(art::Event &evt) override
static IonizationAndScintillation * CreateInstance(detinfo::DetectorPropertiesData const &detProp, CLHEP::HepRandomEngine &engine)
std::string fG4PhysListName
predefined physics list to use if not making a custom one
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.
AllPhysicsLists fAllPhysicsLists
std::map< int, std::map< int, int > > GetLitePhotons(bool Reflected=false)
detinfo::DetectorPropertiesData fDetProp
Must outlive fAllPhysicsLists!
CLHEP::HepRandomEngine & fEngine
void SparsifyTrajectory(double margin=0.1, bool keep_second_to_last=false)
void beginRun(art::Run &run) override
static ServiceHandle< RandomNumberGenerator > & rng()
void ClearTable(size_t nch=0)
A Geant4 sensitive detector that accumulates information.
sim::AuxDetSimChannel const GetAuxDetSimChannel() const
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.