24 #include "art/Framework/Core/ProducesCollector.h" 
   25 #include "cetlib/search_path.h" 
   32 #include "artg4tk/pluginDetectors/gdml/ByParticle.hh" 
   33 #include "artg4tk/pluginDetectors/gdml/CalorimeterHit.hh" 
   34 #include "artg4tk/pluginDetectors/gdml/CalorimeterSD.hh" 
   35 #include "artg4tk/pluginDetectors/gdml/ColorReader.hh" 
   36 #include "artg4tk/pluginDetectors/gdml/DRCalorimeterHit.hh" 
   37 #include "artg4tk/pluginDetectors/gdml/DRCalorimeterSD.hh" 
   38 #include "artg4tk/pluginDetectors/gdml/HadIntAndEdepTrkSD.hh" 
   39 #include "artg4tk/pluginDetectors/gdml/HadInteractionSD.hh" 
   40 #include "artg4tk/pluginDetectors/gdml/PhotonHit.hh" 
   41 #include "artg4tk/pluginDetectors/gdml/PhotonSD.hh" 
   42 #include "artg4tk/pluginDetectors/gdml/TrackerHit.hh" 
   43 #include "artg4tk/pluginDetectors/gdml/TrackerSD.hh" 
   48 #include "Geant4/G4AutoDelete.hh" 
   49 #include "Geant4/G4GDMLParser.hh" 
   50 #include "Geant4/G4LogicalVolume.hh" 
   51 #include "Geant4/G4LogicalVolumeStore.hh" 
   52 #include "Geant4/G4PhysicalVolumeStore.hh" 
   53 #include "Geant4/G4RegionStore.hh" 
   54 #include "Geant4/G4SDManager.hh" 
   55 #include "Geant4/G4StepLimiter.hh" 
   56 #include "Geant4/G4Types.hh" 
   57 #include "Geant4/G4UnitsTable.hh" 
   58 #include "Geant4/G4UserLimits.hh" 
   59 #include "Geant4/G4VPhysicalVolume.hh" 
   60 #include "Geant4/G4VUserDetectorConstruction.hh" 
   61 #include "Geant4/globals.hh" 
   64 #include <unordered_map> 
   73     return std::make_unique<T>(std::move(t));
 
   78   : artg4tk::DetectorBase(p,
 
   79                           p.
get<string>(
"name", 
"LArG4DetectorService"),
 
   80                           p.
get<string>(
"category", 
"World"),
 
   81                           p.
get<string>(
"mother_category", 
""))
 
   82   , gdmlFileName_{p.get<std::string>(
"gdmlFileName_", 
"")}
 
   85   , 
volumeNames_{p.get<std::vector<std::string>>(
"volumeNames", {})}
 
   86   , 
stepLimits_{p.get<std::vector<float>>(
"stepLimits", {})}
 
   88   , 
dumpMP_{p.get<
bool>(
"DumpMaterialProperties", 
false)}
 
   91   G4UnitDefinition::GetUnitsTable();
 
   95     throw cet::exception(
"LArG4DetectorService") << 
"Configuration error: volumeNames:[] and" 
   96                                                  << 
" stepLimits:[] have different sizes!" 
  101   new G4UnitDefinition(
"volt/cm", 
"V/cm", 
"Electric field", 
CLHEP::volt / CLHEP::cm);
 
  104     mf::LogInfo(
"LArG4DetectorService::Ctr")
 
  105       << 
"Reading stepLimit(s) from the configuration file, for volume(s):";
 
  109       throw cet::exception(
"LArG4DetectorService")
 
  110         << 
"Invalid stepLimits found. Step limits must be" 
  111         << 
" positive! Bad value : stepLimits[" << i << 
"] = " << 
stepLimits_.at(i) << 
" [mm]\n";
 
  115     mf::LogInfo(
"LArG4DetectorService::Ctr")
 
  122 std::vector<G4LogicalVolume*>
 
  126   G4GDMLParser 
parser(&reader);
 
  128   cet::search_path sp{
"FW_SEARCH_PATH"};
 
  129   std::string fullGDMLFileName;
 
  131     throw cet::exception(
"LArG4DetectorService") << 
"Cannot find file: " << 
gdmlFileName_;
 
  133   parser.Read(fullGDMLFileName,
false);
 
  134   G4VPhysicalVolume* World = parser.GetWorldVolume();
 
  136   std::stringstream ss;
 
  137   ss << World->GetTranslation() << 
"\n\n";
 
  138   ss << 
"Found World:  " << World->GetName() << 
"\n";
 
  139   ss << 
"World LV:  " << World->GetLogicalVolume()->GetName() << 
"\n";
 
  140   G4LogicalVolumeStore* pLVStore = G4LogicalVolumeStore::GetInstance();
 
  141   ss << 
"Found " << pLVStore->size() << 
" logical volumes." 
  143   G4PhysicalVolumeStore* pPVStore = G4PhysicalVolumeStore::GetInstance();
 
  144   ss << 
"Found " << pPVStore->size() << 
" physical volumes." 
  146   G4SDManager* SDman = G4SDManager::GetSDMpointer();
 
  147   const G4GDMLAuxMapType* auxmap = parser.GetAuxMap();
 
  148   ss << 
"Found " << auxmap->size() << 
" volume(s) with auxiliary information." 
  150   ss << 
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
 
  151   mf::LogInfo(
"LArG4DetectorService::doBuildLVs") << ss.str();
 
  153   for (
auto const& [volume, auxes] : *auxmap) {
 
  154     G4cout << 
"Volume " << volume->GetName()
 
  155            << 
" has the following list of auxiliary information: \n";
 
  156     for (
auto const& aux : auxes) {
 
  157       G4cout << 
"--> Type: " << aux.type << 
" Value: " << aux.value << 
"\n";
 
  159       G4double 
value = atof(aux.value);
 
  160       G4double val_unit = 1; 
 
  161       G4String provided_category = 
"NONE";
 
  162       if ((aux.unit) && (aux.unit != 
"")) { 
 
  163         val_unit = G4UnitDefinition::GetValueOf(aux.unit);
 
  164         provided_category = G4UnitDefinition::GetCategory(aux.unit);
 
  165         mf::LogInfo(
"AuxUnit") << 
" Unit parsed = " << aux.unit
 
  166                                << 
" from unit category: " << provided_category.c_str();
 
  171       if (aux.type == 
"StepLimit") {
 
  172         G4UserLimits* fStepLimit = 
new G4UserLimits();
 
  173         G4AutoDelete::Register(fStepLimit);
 
  176         G4String steplimit_category = 
"Length";
 
  177         if (provided_category == steplimit_category) {
 
  178           mf::LogInfo(
"AuxUnit") << 
"Valid StepLimit unit category obtained: " 
  179                                  << provided_category.c_str();
 
  181           value = (value / CLHEP::mm) * CLHEP::mm;
 
  182           fStepLimit->SetMaxAllowedStep(value);
 
  183           mf::LogInfo(
"fStepLimit")
 
  184             << 
"fStepLimit:  " << value << 
"  " << value / CLHEP::cm << 
" cm\n";
 
  186         else if (provided_category ==
 
  188           MF_LOG_WARNING(
"StepLimitUnit") << 
"StepLimit in geometry file does not have a unit!" 
  189                                           << 
" Defaulting to mm...";
 
  191           fStepLimit->SetMaxAllowedStep(value);
 
  192           mf::LogInfo(
"fStepLimit")
 
  193             << 
"fStepLimit:  " << value << 
"  " << value / CLHEP::cm << 
" cm\n";
 
  196           throw cet::exception(
"StepLimitUnit")
 
  197             << 
"StepLimit does not have a valid length unit!\n" 
  198             << 
" Category of unit provided = " << provided_category << 
".\n";
 
  201         volume->SetUserLimits(fStepLimit);
 
  203         MF_LOG_DEBUG(
"LArG4DetectorService::")
 
  204           << 
"Set stepLimit for volume: " << volume->GetName() << 
" from the GDML file.";
 
  205         setGDMLVolumes_.insert(std::make_pair(volume->GetName(), (float)(value / CLHEP::mm)));
 
  207       if (aux.type == 
"SensDet") {
 
  208         if (aux.value == 
"DRCalorimeter") {
 
  209           G4String 
name = volume->GetName() + 
"_DRCalorimeter";
 
  210           artg4tk::DRCalorimeterSD* aDRCalorimeterSD = 
new artg4tk::DRCalorimeterSD(name);
 
  211           SDman->AddNewDetector(aDRCalorimeterSD);
 
  212           volume->SetSensitiveDetector(aDRCalorimeterSD);
 
  213           std::cout << 
"Attaching sensitive Detector: " << aux.value
 
  214                     << 
" to Volume:  " << volume->GetName() << 
"\n";
 
  215           detectors_.emplace_back(volume->GetName(), aux.value);
 
  217         else if (aux.value == 
"Calorimeter") {
 
  218           G4String 
name = volume->GetName() + 
"_Calorimeter";
 
  219           artg4tk::CalorimeterSD* aCalorimeterSD = 
new artg4tk::CalorimeterSD(name);
 
  220           SDman->AddNewDetector(aCalorimeterSD);
 
  221           volume->SetSensitiveDetector(aCalorimeterSD);
 
  222           std::cout << 
"Attaching sensitive Detector: " << aux.value
 
  223                     << 
" to Volume:  " << volume->GetName() << 
"\n";
 
  224           detectors_.emplace_back(volume->GetName(), aux.value);
 
  226         else if (aux.value == 
"PhotonDetector") {
 
  227           G4String 
name = volume->GetName() + 
"_PhotonDetector";
 
  228           artg4tk::PhotonSD* aPhotonSD = 
new artg4tk::PhotonSD(name);
 
  229           SDman->AddNewDetector(aPhotonSD);
 
  230           volume->SetSensitiveDetector(aPhotonSD);
 
  231           std::cout << 
"Attaching sensitive Detector: " << aux.value
 
  232                     << 
" to Volume:  " << volume->GetName() << 
"\n";
 
  233           detectors_.emplace_back(volume->GetName(), aux.value);
 
  235         else if (aux.value == 
"Tracker") {
 
  236           G4String 
name = volume->GetName() + 
"_Tracker";
 
  237           artg4tk::TrackerSD* aTrackerSD = 
new artg4tk::TrackerSD(name);
 
  238           SDman->AddNewDetector(aTrackerSD);
 
  239           volume->SetSensitiveDetector(aTrackerSD);
 
  240           std::cout << 
"Attaching sensitive Detector: " << aux.value
 
  241                     << 
" to Volume:  " << volume->GetName() << 
"\n";
 
  242           detectors_.push_back(std::make_pair(volume->GetName(), aux.value));
 
  244         else if (aux.value == 
"SimEnergyDeposit") {
 
  245           G4String 
name = volume->GetName() + 
"_SimEnergyDeposit";
 
  247           SDman->AddNewDetector(aSimEnergyDepositSD);
 
  248           volume->SetSensitiveDetector(aSimEnergyDepositSD);
 
  249           std::cout << 
"Attaching sensitive Detector: " << aux.value
 
  250                     << 
" to Volume:  " << volume->GetName() << 
"\n";
 
  251           detectors_.emplace_back(volume->GetName(), aux.value);
 
  253         else if (aux.value == 
"AuxDet") {
 
  254           G4String 
name = volume->GetName() + 
"_AuxDet";
 
  256           SDman->AddNewDetector(aAuxDetSD);
 
  257           volume->SetSensitiveDetector(aAuxDetSD);
 
  258           std::cout << 
"Attaching sensitive Detector: " << aux.value
 
  259                     << 
" to Volume:  " << volume->GetName() << 
"\n";
 
  260           detectors_.emplace_back(volume->GetName(), aux.value);
 
  262         else if (aux.value == 
"HadInteraction") {
 
  263           G4String 
name = volume->GetName() + 
"_HadInteraction";
 
  264           artg4tk::HadInteractionSD* aHadInteractionSD = 
new artg4tk::HadInteractionSD(name);
 
  267           volume->SetSensitiveDetector(aHadInteractionSD);
 
  268           std::cout << 
"Attaching sensitive Detector: " << aux.value
 
  269                     << 
" to Volume:  " << volume->GetName() << 
"\n";
 
  270           detectors_.emplace_back(volume->GetName(), aux.value);
 
  272         else if (aux.value == 
"HadIntAndEdepTrk") {
 
  273           G4String 
name = volume->GetName() + 
"_HadIntAndEdepTrk";
 
  274           artg4tk::HadIntAndEdepTrkSD* aHadIntAndEdepTrkSD = 
new artg4tk::HadIntAndEdepTrkSD(name);
 
  277           volume->SetSensitiveDetector(aHadIntAndEdepTrkSD);
 
  278           std::cout << 
"Attaching sensitive Detector: " << aux.value
 
  279                     << 
" to Volume:  " << volume->GetName() << 
"\n";
 
  280           detectors_.emplace_back(volume->GetName(), aux.value);
 
  285       << 
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
 
  287   if (
dumpMP_) { G4cout << *(G4Material::GetMaterialTable()) << G4endl; }
 
  291   std::cout << 
" Collection Capacity:  " << SDman->GetCollectionCapacity() << 
"\n";
 
  292   G4HCtable* hctable = SDman->GetHCtable();
 
  293   for (G4int j = 0; j < SDman->GetCollectionCapacity(); ++j) {
 
  294     std::cout << 
"HC Name: " << hctable->GetHCname(j) << 
"   SD Name:  " << hctable->GetSDname(j)
 
  297   std::cout << 
"==================================================\n";
 
  299   std::vector<G4LogicalVolume*> myLVvec;
 
  300   myLVvec.push_back(pLVStore->at(0)); 
 
  301   std::cout << 
"nr of LV ======================:  " << myLVvec.size() << 
"\n";
 
  306 std::vector<G4VPhysicalVolume*>
 
  310   std::vector<G4VPhysicalVolume*> myPVvec;
 
  311   G4PhysicalVolumeStore* pPVStore = G4PhysicalVolumeStore::GetInstance();
 
  312   myPVvec.push_back(pPVStore->at(
 
  313     pPVStore->size() - 1)); 
 
  325     << 
"Setting step limits from configuration" 
  326     << 
" file. This will OVERRIDE redundant stepLimit(s) set in the GDML file. Note" 
  327     << 
" that stepLimits are only active if enabled in the physicsListService via the" 
  328     << 
" appropriate parameter.";
 
  330   std::string volumeName = 
"";
 
  331   G4LogicalVolume* setVol = 
nullptr;
 
  333     G4double previousStepLimit = 0.;
 
  336     if (setVol = G4LogicalVolumeStore::GetInstance()->GetVolume(
name, 
false); !setVol) {
 
  337       throw cet::exception(
"invalidInputVolumeName")
 
  338         << 
"Provided volume name : " << 
name << 
" not found!\n";
 
  342     volumeName = setVol->GetName();
 
  343     MF_LOG_DEBUG(
"LArG4DetectorService::setStepLimits")
 
  344       << 
"Got logical volume with name: " << volumeName;
 
  346     G4UserLimits* fStepLimitOverride = 
new G4UserLimits();
 
  347     G4AutoDelete::Register(fStepLimitOverride);
 
  352       previousStepLimit = (G4double)(search->second);
 
  353       if (newStepLimit != previousStepLimit) {
 
  355           << 
"OVERRIDING PREVIOUSLY SET" 
  356           << 
" STEPLIMIT FOR VOLUME : " << volumeName << 
" FROM " << previousStepLimit << 
" mm TO " 
  357           << newStepLimit << 
" mm";
 
  361           << 
"New stepLimit matches previously" 
  362           << 
" set stepLimit from the GDML file for volume : " << volumeName
 
  363           << 
" stepLimit : " << newStepLimit << 
" mm. Nothing will be changed.";
 
  368     fStepLimitOverride->SetMaxAllowedStep(newStepLimit); 
 
  369     mf::LogInfo(
"LArG4DetectorService::setStepLimits")
 
  370       << 
"fStepLimitOverride:  " << newStepLimit / CLHEP::mm << 
" mm " << newStepLimit / CLHEP::cm
 
  372       << 
"for volume: " << volumeName << 
"\n" 
  373       << 
"%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
 
  374     setVol->SetUserLimits(fStepLimitOverride);
 
  381   return myName() + volume_name;
 
  388   for (
auto const& [volume_name, sd_name] : 
detectors_) {
 
  389     if (sd_name == 
"DRCalorimeter") {
 
  391       collector.produces<artg4tk::DRCalorimeterHitCollection>(
instance);
 
  392       collector.produces<artg4tk::ByParticle>(
instance + 
"Edep");
 
  393       collector.produces<artg4tk::ByParticle>(
instance + 
"NCeren");
 
  395     else if (sd_name == 
"Calorimeter") {
 
  396       collector.produces<artg4tk::CalorimeterHitCollection>(
instanceName(volume_name));
 
  398     else if (sd_name == 
"PhotonDetector") {
 
  399       collector.produces<artg4tk::PhotonHitCollection>(
instanceName(volume_name));
 
  401     else if (sd_name == 
"Tracker") {
 
  402       collector.produces<artg4tk::TrackerHitCollection>(
instanceName(volume_name));
 
  404     else if (sd_name == 
"SimEnergyDeposit") {
 
  407     else if (sd_name == 
"AuxDet") {
 
  410     else if (sd_name == 
"HadInteraction") {
 
  411       collector.produces<artg4tk::ArtG4tkVtx>(); 
 
  413     else if (sd_name == 
"HadIntAndEdepTrk") {
 
  414       collector.produces<artg4tk::ArtG4tkVtx>();
 
  415       collector.produces<artg4tk::TrackerHitCollection>();
 
  427   G4SDManager* sdman = G4SDManager::GetSDMpointer();
 
  428   art::ServiceHandle<artg4tk::DetectorHolderService> detectorHolder;
 
  429   art::Event& 
e = detectorHolder->getCurrArtEvent();
 
  432   art::ServiceHandle<larg4::ParticleListActionService> particleListAction;
 
  434   for (
auto const& [volume_name, sd_name] : 
detectors_) {
 
  435     auto sd = sdman->FindSensitiveDetector(volume_name + 
"_" + sd_name);
 
  436     if (sd_name == 
"HadInteraction") {
 
  437       if (
auto hisd = dynamic_cast<artg4tk::HadInteractionSD*>(sd)) {
 
  438         if (
auto const& inter = hisd->Get1stInteraction(); inter.GetNumOutcoming() > 0) {
 
  439           e.put(make_product(inter));
 
  444     else if (sd_name == 
"HadIntAndEdepTrk") {
 
  445       if (
auto trksd = dynamic_cast<artg4tk::HadIntAndEdepTrkSD*>(sd)) {
 
  446         if (
auto const& inter = trksd->Get1stInteraction(); inter.GetNumOutcoming() > 0) {
 
  447           e.put(make_product(inter));
 
  449         if (
auto const& trkhits = trksd->GetEdepTrkHits(); !trkhits.empty()) {
 
  450           e.put(make_product(trkhits));
 
  455     else if (sd_name == 
"Tracker") {
 
  456       auto trsd = 
dynamic_cast<artg4tk::TrackerSD*
>(sd);
 
  457       e.put(make_product(trsd->GetHits()), 
instanceName(volume_name));
 
  459     else if (sd_name == 
"SimEnergyDeposit") {
 
  462       std::map<int, int> tmap = particleListAction->GetTargetIDMap();
 
  465           for(
auto  &
hit : hitCollection)
 
  467               hit.setTrackID(tmap[
hit.TrackID()]);
 
  470       e.put(make_product(hitCollection), 
instanceName(volume_name));
 
  472     else if (sd_name == 
"AuxDet") {
 
  473       auto auxsd = 
dynamic_cast<AuxDetSD*
>(sd);
 
  474       e.put(make_product(auxsd->GetHits()), 
instanceName(volume_name));
 
  476     else if (sd_name == 
"Calorimeter") {
 
  477       auto calsd = 
dynamic_cast<artg4tk::CalorimeterSD*
>(sd);
 
  478       e.put(make_product(calsd->GetHits()), 
instanceName(volume_name));
 
  480     else if (sd_name == 
"DRCalorimeter") {
 
  481       auto drcalsd = 
dynamic_cast<artg4tk::DRCalorimeterSD*
>(sd);
 
  483       e.put(make_product(drcalsd->GetHits()), identifier);
 
  484       e.put(make_product(drcalsd->GetEbyParticle()), identifier + 
"Edep");
 
  485       e.put(make_product(drcalsd->GetNCerenbyParticle()), identifier + 
"NCeren");
 
  487     else if (sd_name == 
"PhotonDetector") {
 
  488       auto phsd = 
dynamic_cast<artg4tk::PhotonSD*
>(sd);
 
  489       e.put(make_product(phsd->GetHits()), 
instanceName(volume_name));
 
void doCallArtProduces(art::ProducesCollector &collector) override
const std::string instance
std::size_t size(FixedBins< T, C > const &) noexcept
void doFillEventWithArtHits(G4HCofThisEvent *hc) override
LArG4DetectorService(fhicl::ParameterSet const &)
std::string instanceName(std::string const &) const 
std::vector< std::pair< std::string, std::string > > detectors_
std::string gdmlFileName_
bool updateSimEnergyDeposits_
Use Geant4's user "hooks" to maintain a list of particles generated by Geant4. 
MF_LOG_WARNING("SimWire")<< "SimWire is an example module that works for the "<< "MicroBooNE detector. Each experiment should implement "<< "its own version of this module to simulate electronics "<< "response."
const sim::SimEnergyDepositCollection & GetHits() const 
volt_as<> volt
Type of potential stored in volts, in double precision. 
std::vector< std::string > volumeNames_
std::vector< float > stepLimits_
std::vector< AuxDetHit > AuxDetHitCollection
std::vector< SimEnergyDeposit > SimEnergyDepositCollection
contains information for a single step in the detector simulation 
std::vector< G4LogicalVolume * > doBuildLVs() override
std::vector< G4VPhysicalVolume * > doPlaceToPVs(std::vector< G4LogicalVolume * >) override
std::map< std::string, G4double > overrideGDMLStepLimit_Map
std::unordered_map< std::string, float > setGDMLVolumes_
BEGIN_PROLOG could also be cout