19 #include "G4SystemOfUnits.hh"
20 #include "G4UnitsTable.hh"
31 GGSUserAction(), _messenger(this,
"/GGS/userActions/hitsAction/",
"Commands for hits action"), _outFileBase(
""), _outFile(
32 NULL), _outTree(NULL), _outTreeName(
""), _privateMessenger(this) {
35 _messenger.DeclareProperty(
"fileBase", _outFileBase).SetGuidance(
"Sets the base name for ROOT output file").SetGuidance(
36 " Can be with or without extension (.root will be used automatically)").SetStates(G4State_PreInit,
38 _messenger.DeclareProperty(
"treeName", _outTreeName).SetGuidance(
39 "Set the name of the TTree object in the ROOT output file.").SetStates(G4State_PreInit, G4State_Idle);
42 "Class name of output integrated hits").SetStates(G4State_PreInit, G4State_Idle);
44 "Class name of output particle hits").SetStates(G4State_PreInit, G4State_Idle);
46 "Class name of output position hits").SetStates(G4State_PreInit, G4State_Idle);
54 for (
auto &handleElem : _outputHandles) {
55 OutputHandle &handle = handleElem.second;
56 if (handle.partHitArray) {
57 handle.partHitArray->SetOwner(
false);
59 if (handle.posHitArray) {
60 handle.posHitArray->SetOwner(
false);
68 static const std::string routineName(
"GSHitsAction::BeginOfRunAction");
74 if (!_outFile || (_outFile && _outFile->IsZombie())) {
75 COUT(ERROR) <<
"Cannot open ROOT file " << _outFileBase <<
"for run" << run->GetRunID() <<
ENDL;
82 if (_outTreeName ==
"") {
84 _outTree->SetTitle(TString(_outTree->GetTitle()) +
"Hits ");
87 _outTree =
new TTree(_outTreeName,
"GGS hits");
90 G4LogicalVolumeStore *logicalVS = G4LogicalVolumeStore::GetInstance();
94 for (
unsigned int i = 0; i < logicalVS->size(); i++) {
95 G4LogicalVolume *logicalV = logicalVS->at(i);
98 std::vector<G4VSensitiveDetector *> sDets(0);
99 G4VSensitiveDetector *sd = logicalV->GetSensitiveDetector();
110 for (
auto &sdPtr : sDets) {
111 auto sdName = sdPtr->GetName();
112 auto ggssdNamePos = sdName.find(
".GGSIntHitSD", 0);
113 if (ggssdNamePos != std::string::npos) {
115 if (intHitSD && intHitSD->isActive()) {
116 std::string sdNameReduced = sdName;
117 sdNameReduced.erase(ggssdNamePos, 12);
119 std::unordered_map<std::string, OutputHandle>::iterator handleIter = _outputHandles.find(sdName);
120 if (handleIter == _outputHandles.end()) {
123 auto insertResult = _outputHandles.insert(std::pair<std::string, OutputHandle> { sdName, OutputHandle() });
124 if (insertResult.second) {
125 handleIter = insertResult.first;
130 auto &newHandle = handleIter->second;
131 newHandle.intHitArray = std::unique_ptr<TClonesArray>(
new TClonesArray(newHandle.intHitClassName.c_str()));
133 _outTree->Branch((sdNameReduced +
"-GGSIntHits").data(),
"TClonesArray", newHandle.intHitArray.get(), 64000);
138 std::find_if(_thresholds.begin(), _thresholds.end(),
139 [&sdNameReduced] (
const ThresholdStruct &threshold) {
return (threshold.hitType == 0) && (sdNameReduced == threshold.detectorName);});
140 if (thresholdIter != _thresholds.end()) {
141 newHandle.intHitThreshold = thresholdIter->value;
145 newHandle.partHitArray = std::unique_ptr<TObjArray>(
new TObjArray());
148 newHandle.partHitArray->SetOwner(
true);
149 _outTree->Branch((sdNameReduced +
"-GGSPartHits").data(),
"TObjArray", newHandle.partHitArray.get(), 64000);
150 newHandle.partHitCAService = std::unique_ptr<GGSTClonesArrayService>(
154 std::find_if(_thresholds.begin(), _thresholds.end(),
155 [&sdNameReduced] (
const ThresholdStruct &threshold) {
return (threshold.hitType == 1) && (sdNameReduced == threshold.detectorName);});
156 if (thresholdIter != _thresholds.end()) {
157 newHandle.partHitThreshold = thresholdIter->value;
161 newHandle.posHitArray = std::unique_ptr<TObjArray>(
new TObjArray());
162 newHandle.posHitArray->SetOwner(
true);
163 _outTree->Branch((sdNameReduced +
"-GGSPosHits").data(),
"TObjArray", newHandle.posHitArray.get(), 64000);
164 newHandle.posHitCAService = std::unique_ptr<GGSTClonesArrayService>(
168 std::find_if(_thresholds.begin(), _thresholds.end(),
169 [&sdNameReduced] (
const ThresholdStruct &threshold) {
return (threshold.hitType == 2) && (sdNameReduced == threshold.detectorName);});
170 if (thresholdIter != _thresholds.end()) {
171 newHandle.posHitThreshold = thresholdIter->value;
176 unsigned int nBins = intHitSD->
GetTimeBins().size();
177 TArrayF timeBins(nBins);
178 for (
unsigned int iBin = 0; iBin < nBins; iBin++)
180 _outFile->WriteObject(&timeBins, (sdNameReduced +
"-GGSIntHits-TimeBins").data());
183 std::vector<float> detThresholds { (float) (newHandle.intHitThreshold / GeV),
184 (float) (newHandle.partHitThreshold / GeV), (float) (newHandle.posHitThreshold / GeV) };
185 _outFile->WriteObject(&detThresholds, (sdNameReduced +
"-GGSIntHits-Thresholds").data());
207 if (_outTreeName !=
"") {
225 _GiveBackAllArrays();
226 for (
auto &handleElem : _outputHandles) {
227 if (handleElem.second.posHitCAService) {
228 handleElem.second.posHitCAService->DeleteAll();
230 if (handleElem.second.partHitCAService) {
231 handleElem.second.partHitCAService->DeleteAll();
240 _GiveBackAllArrays();
244 for (
auto &handleElem : _outputHandles) {
245 OutputHandle &handle = handleElem.second;
246 handle.intHitArray->Clear(
"C");
247 if (handle.partHitArray) {
253 handle.partHitArray->SetOwner(
false);
255 handle.partHitArray->Clear();
258 handle.partHitArray->SetOwner(
true);
261 if (handle.posHitArray) {
262 handle.posHitArray->SetOwner(
false);
263 handle.posHitArray->Clear();
264 handle.posHitArray->SetOwner(
true);
278 G4SDManager *SDman = G4SDManager::GetSDMpointer();
281 G4HCofThisEvent *evHitColl =
event->GetHCofThisEvent();
284 for (
auto &handleElem : _outputHandles) {
286 const std::string &detectorName = handleElem.first;
287 OutputHandle &handle = handleElem.second;
289 G4int hitsCollID = SDman->GetCollectionID(detectorName);
292 _Convert(*((
GGSIntHitsCollection*) (evHitColl->GetHC(hitsCollID))), *(handle.intHitArray), handle, detectorName);
295 for (
int iIntHit = 0; iIntHit < handle.intHitArray->GetEntries(); ++iIntHit) {
297 if (tIntHit->_partHits) {
298 handle.partHitArray->AddAtAndExpand(tIntHit->_partHits, handle.partHitArray->GetEntries());
299 if (tIntHit->_partHits->GetEntries() > 0 && ((
GGSTPartHit*) (tIntHit->_partHits->At(0)))->_posHits) {
300 static TClonesArray *partHits = NULL;
301 static Int_t nPartHits = 0;
302 partHits = tIntHit->_partHits;
303 nPartHits = partHits->GetEntries();
304 for (Int_t iPartHit = 0; iPartHit < nPartHits; iPartHit++) {
306 partHit->_posHitIndex = handle.posHitArray->GetEntries();
307 handle.posHitArray->AddAtAndExpand(partHit->_posHits, handle.posHitArray->GetEntries());
318 if (_outTreeName !=
"") {
326 void GGSHitsAction::_Convert(
const GGSPosHitsCollection &posHits, TClonesArray &tPosHits, OutputHandle &handle) {
328 for (
size_t iHit = 0; iHit < posHits.GetSize(); ++iHit) {
329 auto &posHit = *((
GGSPosHit*) (posHits.GetHit(iHit)));
330 if (posHit.GetEnergyDeposit() > handle.posHitThreshold) {
332 tPosHit.
eDep = posHit.GetEnergyDeposit() / GeV;
333 tPosHit.
time = posHit.GetTime() / ns;
334 tPosHit.
pathLength = posHit.GetPathLength() / cm;
335 tPosHit.
startPoint[0] = posHit.GetStartPoint()[0] / cm;
336 tPosHit.
startPoint[1] = posHit.GetStartPoint()[1] / cm;
337 tPosHit.
startPoint[2] = posHit.GetStartPoint()[2] / cm;
338 tPosHit.
endPoint[0] = posHit.GetEndPoint()[0] / cm;
339 tPosHit.
endPoint[1] = posHit.GetEndPoint()[1] / cm;
340 tPosHit.
endPoint[2] = posHit.GetEndPoint()[2] / cm;
341 tPosHit.
startMomentum[0] = posHit.GetStartMomentum()[0] / GeV;
342 tPosHit.
startMomentum[1] = posHit.GetStartMomentum()[1] / GeV;
343 tPosHit.
startMomentum[2] = posHit.GetStartMomentum()[2] / GeV;
344 tPosHit.
startEnergy = posHit.GetStartEnergy() / GeV;
352 void GGSHitsAction::_Convert(
const GGSPartHitsCollection &partHits, TClonesArray &tPartHits, OutputHandle &handle) {
354 for (
size_t iHit = 0; iHit < partHits.GetSize(); ++iHit) {
355 auto &partHit = *((
GGSPartHit*) (partHits.GetHit(iHit)));
357 auto &tPartHit = *((
GGSTPartHit*) (tPartHits.ConstructedAt(tPartHits.GetEntries(),
"")));
360 if ((tPartHit._posHits)) {
361 tPartHit._posHits->Clear(
"C");
364 tPartHit._posHits = handle.posHitCAService->ProvideArray(posHitColl->GetSize());
366 _Convert(*posHitColl, *(tPartHit._posHits), handle);
369 if (partHit.GetEnergyDeposit() > handle.partHitThreshold || (posHitColl && tPartHit._posHits->GetEntries() != 0)) {
370 tPartHit.eDep = partHit.GetEnergyDeposit() / GeV;
371 tPartHit.time = partHit.GetTime() / ns;
372 tPartHit.pathLength = partHit.GetPathLength() / cm;
373 tPartHit.entrancePoint[0] = partHit.GetEntrancePoint()[0] / cm;
374 tPartHit.entrancePoint[1] = partHit.GetEntrancePoint()[1] / cm;
375 tPartHit.entrancePoint[2] = partHit.GetEntrancePoint()[2] / cm;
376 tPartHit.exitPoint[0] = partHit.GetExitPoint()[0] / cm;
377 tPartHit.exitPoint[1] = partHit.GetExitPoint()[1] / cm;
378 tPartHit.exitPoint[2] = partHit.GetExitPoint()[2] / cm;
379 tPartHit.entranceMomentum[0] = partHit.GetEntranceMomentum()[0] / GeV;
380 tPartHit.entranceMomentum[1] = partHit.GetEntranceMomentum()[1] / GeV;
381 tPartHit.entranceMomentum[2] = partHit.GetEntranceMomentum()[2] / GeV;
382 tPartHit.entranceEnergy = partHit.GetEntranceEnergy() / GeV;
383 tPartHit.trackID = partHit.GetTrackID();
384 tPartHit.parentID = partHit.GetParentID();
385 tPartHit.particlePdg = partHit.GetParticlePdg();
386 tPartHit.UserConversion(partHit);
389 if (tPartHit._posHits) {
390 handle.posHitCAService->TakeBackArray(tPartHit._posHits);
393 tPartHits.RemoveLast();
401 void GGSHitsAction::_Convert(
const GGSIntHitsCollection &intHits, TClonesArray &tIntHits, OutputHandle &handle,
402 const std::string &detectorName) {
404 for (
size_t iHit = 0; iHit < intHits.GetSize(); ++iHit) {
405 auto &intHit = *((
GGSIntHit*) (intHits.GetHit(iHit)));
407 auto &tIntHit = *((
GGSTIntHit*) (tIntHits.ConstructedAt(tIntHits.GetEntries(),
"")));
409 if (tIntHit._partHits) {
410 tIntHit._partHits->Clear(
"C");
413 tIntHit._partHits = handle.partHitCAService->ProvideArray(partHitColl->GetSize());
415 _Convert(*partHitColl, *(tIntHit._partHits), handle);
419 auto totEDep = intHit.GetTotalEnergyDep();
420 if (totEDep > handle.intHitThreshold || (partHitColl && tIntHit._partHits->GetEntries() != 0)) {
421 tIntHit.eDep = totEDep / GeV;
422 if (tIntHit.eDepTimeBin.GetSize() != (int) (intHit.GetEnergyDep().size()))
423 tIntHit.eDepTimeBin.Set(intHit.GetEnergyDep().size());
424 for (
unsigned int i = 0; i < intHit.GetEnergyDep().size(); i++) {
425 tIntHit.eDepTimeBin[i] = intHit.GetEnergyDep()[i] / GeV;
427 tIntHit.time = intHit.GetTime() / ns;
428 tIntHit.UserConversion(intHit);
432 intHit.GetAbsTranslation(), intHit.GetID());
435 if (tIntHit._partHits) {
436 handle.partHitCAService->TakeBackArray(tIntHit._partHits);
440 tIntHits.RemoveLast();
449 const std::string routineName(
"[GGSHitsAction::SetOutputIntHitClass] ");
452 TClass *intHitClass = TClass::GetClass(className.c_str());
454 throw std::runtime_error(routineName +
"Dictionary for class " + className +
" not found");
458 detectorName.insert(detectorName.find_first_of(
'.'),
".GGSIntHitSD");
459 auto handleIter = _outputHandles.find(detectorName);
460 if (handleIter == _outputHandles.end()) {
461 handleIter = _outputHandles.insert(std::pair<std::string, OutputHandle> { detectorName, OutputHandle() }).first;
465 handleIter->second.intHitClassName = className;
471 const std::string routineName(
"[GGSHitsAction::SetOutputPartHitClass] ");
474 TClass *partHitClass = TClass::GetClass(className.c_str());
476 throw std::runtime_error(routineName +
"Dictionary for class " + className +
" not found");
480 detectorName.insert(detectorName.find_first_of(
'.'),
".GGSIntHitSD");
481 auto handleIter = _outputHandles.find(detectorName);
482 if (handleIter == _outputHandles.end()) {
483 handleIter = _outputHandles.insert(std::pair<std::string, OutputHandle> { detectorName, OutputHandle() }).first;
487 handleIter->second.partHitClassName = className;
493 const std::string routineName(
"[GGSHitsAction::SetOutputPosHitClass] ");
496 TClass *posHitClass = TClass::GetClass(className.c_str());
498 throw std::runtime_error(routineName +
"Dictionary for class " + className +
" not found");
502 detectorName.insert(detectorName.find_first_of(
'.'),
".GGSIntHitSD");
503 auto handleIter = _outputHandles.find(detectorName);
504 if (handleIter == _outputHandles.end()) {
505 handleIter = _outputHandles.insert(std::pair<std::string, OutputHandle> { detectorName, OutputHandle() }).first;
509 handleIter->second.posHitClassName = className;
515 const std::string &valueStr,
const std::string &unit) {
517 const std::string routineName(
"GGSHitsAction::SetHitThreshold");
520 if (hitType ==
"integrated") {
523 else if (hitType ==
"particle") {
526 else if (hitType ==
"position") {
530 throw std::runtime_error(routineName +
": Unknown hit type " + hitType +
" for detector " + detectorName);
535 value = std::stof(valueStr);
536 }
catch (std::invalid_argument &exc) {
537 COUT(ERROR) <<
"Invalid threshold for " << hitType <<
" hits of detector " << detectorName <<
ENDL;
539 }
catch (std::out_of_range &exc) {
540 COUT(ERROR) <<
"Invalid value for threshold of " << hitType <<
" hits of detector " << detectorName <<
ENDL;
544 auto &unitsTable = G4UnitDefinition::GetUnitsTable();
545 auto unitCatIter = std::find_if(unitsTable.begin(), unitsTable.end(),
546 [&unit](
const G4UnitsCategory *unitCat) {
return (unitCat->GetName() ==
"Energy");});
547 if (unitCatIter == unitsTable.end()) {
548 throw std::runtime_error(routineName +
": energy unit category not found");
551 auto &unitsList = (*unitCatIter)->GetUnitsList();
552 auto unitIter = std::find_if(unitsList.begin(), unitsList.end(),
553 [&unit](
const G4UnitDefinition *unitDef) {
return unit == unitDef->GetSymbol().c_str();});
554 if (unitIter == unitsList.end()) {
555 throw std::runtime_error(routineName +
": unit " + unit +
" not found");
559 std::find_if(_thresholds.begin(), _thresholds.end(),
560 [&detectorName, hitTypeNo] (
const ThresholdStruct &threshold) {
return (threshold.hitType == hitTypeNo) && (threshold.detectorName == detectorName);});
561 if (thresholdIter == _thresholds.end()) {
562 _thresholds.push_back(ThresholdStruct { detectorName, hitTypeNo, -1. });
563 thresholdIter = _thresholds.end() - 1;
567 thresholdIter->value = value * (*unitIter)->GetValue();
570 thresholdIter->value = value * (*unitIter)->GetValue();
573 thresholdIter->value = value * (*unitIter)->GetValue();
581 GGSHitsAction::GGSHitsActionPrivateMessenger::GGSHitsActionPrivateMessenger(
GGSHitsAction * hitsAction) :
582 _hitsAction(hitsAction) {
583 _setThreshCmd = std::make_unique<G4UIcmdWithAString>(
"/GGS/userActions/hitsAction/setHitThreshold",
this);
584 _setThreshCmd->SetGuidance(
"Set energy deposit threshold for hit output");
585 _setThreshCmd->AvailableForStates(G4State_PreInit, G4State_Idle);
590 void GGSHitsAction::GGSHitsActionPrivateMessenger::SetNewValue(G4UIcommand *command, G4String newValue) {
591 const std::string routineName(
"GGSHitsAction::GGSHitsActionPrivateMessenger::SetNewValue");
592 if (command == _setThreshCmd.get()) {
594 if (tokens.size() != 4) {
595 throw std::runtime_error(
596 routineName +
": setHitTreshold expects 4 parameters, but " + std::to_string(tokens.size()) +
" were given.");
599 _hitsAction->SetHitThreshold(tokens[0], tokens[1], tokens[2], tokens[3]);
605 void GGSHitsAction::_GiveBackAllArrays() {
606 for (
auto &handleElem : _outputHandles) {
607 OutputHandle &handle = handleElem.second;
608 int nIntHits = handle.intHitArray->GetEntries();
609 for (
int iIntHit = 0; iIntHit < nIntHits; iIntHit++) {
611 if (intHit->_partHits) {
613 for (
int iPartHit = 0; iPartHit < nPartHits; iPartHit++) {
615 if (partHit->_posHits) {
616 handle.posHitCAService->TakeBackArray(partHit->_posHits);
619 handle.partHitCAService->TakeBackArray(intHit->_partHits);
G4THitsCollection< GGSPosHit > GGSPosHitsCollection
Alias for G4 template hits collection for GGSPosHit.
TFile * GetFileForThisRun(const path &baseName, const G4Run *run)
Opens a file for a given run and returns a pointer to it.
Float_t startMomentum[3]
Start momentum.
Float_t eDep
Total deposited energy.
Sensitive detector class for integrated hits.
Float_t time
Time of the hit.
virtual void UserConversion(const GGSPosHit &posHit)
Hook for user-defined conversion.
A service which manages a pool of reusable TClonesArray.
void EndOfRunAction(const G4Run *run)
Actions executed at end of run.
const std::vector< G4VSensitiveDetector * > & GetListOfSensitiveDetectors()
Retrieves a list of sensitive detectors collected into this object.
Float_t pathLength
Path length of the hit.
void SetHitThreshold(const std::string &detectorName, const std::string &hitType, const std::string &valueStr, const std::string &unit)
Sets a lower energy deposit threshold for hits.
GGSHitsAction()
Constructor.
void CloseFileForThisRun(const path &baseName)
Closes the ROOT output file.
Float_t startEnergy
Start kinetic energy.
~GGSHitsAction()
Destructor.
#define COUT(level)
Smart log macro. It writes on stdout only if the specified verbosity level is lesser than the maximum...
void EndOfEventAction(const G4Event *event)
Actions executed at end of event.
Class to store G4 particle hits.
Tokens Tokenize(const std::string &str, char delimiter= ' ')
Extracts words from a string.
bool GetPosHitsStorage()
Return current status of particle hits storage (i.e. persistence).
Definition of GGS Particle Hit.
Definition of GGS Position Hit.
int StoreVolume(TFile *filePtr, const std::string &detector, const G4VPhysicalVolume *volume, const G4ThreeVector &position, int id)
Set persistence for the specified volume.
A multiple sensitive detector.
void BeginOfEventAction(const G4Event *event)
Actions executed at beginning of event.
const std::vector< G4double > & GetTimeBins()
Time bins getter.
void BeginOfRunAction(const G4Run *run)
Actions executed at beginning of run.
bool GetPartHitsStorage()
Return current status of particle hits storage (i.e. persistence).
Int_t GetNPartHits()
Gets the number of particle hits.
G4THitsCollection< GGSIntHit > GGSIntHitsCollection
Alias for G4 template hits collection for GGSIntHit.
void SetOutputPartHitClass(std::string detectorName, const std::string &className)
Sets the name of the particle hit class to be used for output.
TTree * GetDefaultTree(TFile *file)
Gets the default tree for this file.
Class to store G4 position hits.
Class to store G4 position hits.
An action which saves hits in sensitive volumes on ROOT file.
static GGSRootFileService & GetInstance()
Get reference to GGSRootFileService unique instance.
G4THitsCollection< GGSPartHit > GGSPartHitsCollection
Alias for G4 template hits collection for GGSPartHit.
Mother class for user actions in GGS.
Definition of GGS Integrated Hit.
Float_t startPoint[3]
Start point.
void SetOutputPosHitClass(std::string detectorName, const std::string &className)
Sets the name of the position hit class to be used for output.
#define RegisterUA(uaClassName)
Macro for registration of user actions classes.
void SetOutputIntHitClass(std::string detectorName, const std::string &className)
Sets the name of the integrated hit class to be used for output of a given detector.
GGSTPartHit * GetPartHit(unsigned int iHit)
Get the specified particle hit.
Float_t endPoint[3]
End point.