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