281#include "TRestGeant4AnalysisProcess.h"
353string CapitalizeFirst(
string name) {
355 name[0] = toupper(name[0]);
360bool EndsWith(
const string& text,
const string& suffix) {
361 return text.size() >= suffix.size() &&
362 text.compare(text.size() - suffix.size(), suffix.size(), suffix) == 0;
365bool StartsWith(
const string& text,
const string& prefix) {
return text.rfind(prefix, 0) == 0; }
373 static const map<string, string> processNameMap = {
375 {
"Photoelectric",
"phot"},
376 {
"Compton",
"compt"},
377 {
"Rayleigh",
"Rayl"},
378 {
"Conversion",
"conv"},
379 {
"PhotonNuclear",
"photonNuclear"},
381 {
"Bremsstrahlung",
"eBrem"},
382 {
"Bremstralung",
"eBrem"},
383 {
"Annihilation",
"annihil"},
386 {
"IonIoni",
"ionIoni"},
387 {
"MuIoni",
"muIoni"},
389 {
"CoulombScat",
"CoulombScat"},
391 {
"HadElastic",
"hadElastic"},
392 {
"NeutronInelastic",
"neutronInelastic"},
393 {
"NInelastic",
"neutronInelastic"},
394 {
"ProtonInelastic",
"protonInelastic"},
395 {
"NCapture",
"nCapture"},
397 {
"RadioactiveDecay",
"RadioactiveDecay"},
398 {
"RadiactiveDecay",
"RadioactiveDecay"},
401 return processNameMap;
417 const auto it = processNameMap.find(name);
418 if (it != processNameMap.end()) {
422 for (
const auto& [restName, geant4Name] : processNameMap) {
423 if (CapitalizeFirst(geant4Name) == name) {
430 if (CapitalizeFirst(geant4Name.Data()) == name) {
431 return geant4Name.Data();
444 cout <<
"??????????????????????????????????????????????????" << endl;
445 cout <<
"REST warning : TRestGeant4AnalysisProcess." << endl;
446 cout <<
"------------------------------------------" << endl;
448 cout <<
" Volume " << volumeName <<
" is not an active volume" << endl;
450 cout <<
"List of active volumes : " << endl;
451 cout <<
"------------------------ " << endl;
455 cout <<
"??????????????????????????????????????????????????" << endl;
489 std::vector<string> fObservables;
490 fObservables = TRestEventProcess::ReadObservables();
491 std::map<std::string, std::string> aliasObsToVol = GetAliasObservableNameToVolume();
494 const auto availableProcesses = physicsInfo.GetAllProcesses();
502 const vector<tuple<string, string, vector<string>>> perProcessDefinitions = {
503 {
"PerProcessPhotoelectric",
"", {
"phot"}},
504 {
"PerProcessCompton",
"", {
"compt"}},
505 {
"PerProcessElectronicIoni",
"", {
"eIoni"}},
506 {
"PerProcessAlphaIoni",
"alpha", {
"ionIoni",
"alphaIoni"}},
507 {
"PerProcessIonIoni",
"", {
"ionIoni"}},
508 {
"PerProcessHadronicIoni",
"", {
"hIoni"}},
509 {
"PerProcessProtonIoni",
"proton", {
"hIoni"}},
510 {
"PerProcessMsc",
"", {
"msc"}},
511 {
"PerProcessHadronElastic",
"", {
"hadElastic"}},
512 {
"PerProcessNeutronElastic",
"neutron", {
"hadElastic"}},
514 for (
const auto& [obsName, particle, processes] : perProcessDefinitions) {
519 fAnalysisTree->AddObservable((
string)GetName() +
"_" + obsName,
"double",
520 "Energy deposited in the sensitive volume by a given process");
525 for (
unsigned int i = 0; i < fObservables.size(); i++) {
526 if (fObservables[i].find(
"VolumeEDep") != string::npos) {
527 TString volName = fObservables[i].substr(0, fObservables[i].length() - 10).c_str();
528 if (aliasObsToVol.find(fObservables[i]) != aliasObsToVol.end()) {
529 volName = aliasObsToVol[fObservables[i]].c_str();
536 fVolumeName.push_back(volName.Data());
544 if (fObservables[i].find(
"MeanPos") != string::npos) {
545 TString volName2 = fObservables[i].substr(0, fObservables[i].length() - 8).c_str();
546 if (aliasObsToVol.find(fObservables[i]) != aliasObsToVol.end()) {
547 volName2 = aliasObsToVol[fObservables[i]].c_str();
549 std::string dirId = fObservables[i].substr(fObservables[i].length() - 1, 1);
562 if ((dirId !=
"X") && (dirId !=
"Y") && (dirId !=
"Z")) {
564 cout <<
"??????????????????????????????????????????????????" << endl;
565 cout <<
"REST warning : TRestGeant4AnalysisProcess." << endl;
566 cout <<
"------------------------------------------" << endl;
568 cout <<
" Direction " << dirId <<
" is not valid" << endl;
569 cout <<
" Only X, Y or Z accepted" << endl;
574 if (StartsWith(fObservables[i],
"containsProcess")) {
575 const string processSuffix = fObservables[i].substr(
string(
"containsProcess").length());
581 if (geant4Name.empty()) {
582 RESTWarning <<
"TRestGeant4AnalysisProcess: unknown process '" << processSuffix
583 <<
"' in observable '" << fObservables[i] <<
"'. It will not be filled."
587 if (availableProcesses.count(geant4Name) == 0) {
588 RESTWarning <<
"TRestGeant4AnalysisProcess: Geant4 process '" << geant4Name
589 <<
"' (observable '" << fObservables[i]
590 <<
"') is not registered in the physics info of this simulation. "
591 <<
"Its value will always be 0 (processes sharing type and subtype, e.g. "
592 <<
"eIoni and ionIoni, are registered only once)" <<
RESTendl;
600 if (EndsWith(fObservables[i],
"Process") && !StartsWith(fObservables[i],
"firstTrackInSensitive")) {
601 const string nameWithoutSuffix =
602 fObservables[i].substr(0, fObservables[i].length() -
string(
"Process").length());
603 const bool hasAlias = aliasObsToVol.find(fObservables[i]) != aliasObsToVol.end();
608 for (
size_t length = 1; length <= nameWithoutSuffix.length(); length++) {
610 if (length == nameWithoutSuffix.length() && !hasAlias) {
613 const string candidate = nameWithoutSuffix.substr(nameWithoutSuffix.length() - length);
615 if (!candidateGeant4Name.empty()) {
616 processName = candidate;
617 geant4Name = candidateGeant4Name;
621 if (geant4Name.empty()) {
622 RESTWarning <<
"TRestGeant4AnalysisProcess: no known process name found in observable '"
623 << fObservables[i] <<
"'. It will not be filled." <<
RESTendl;
624 RESTWarning <<
"Valid process names are:";
626 RESTWarning <<
" " << restName;
628 RESTWarning <<
" (or a Geant4 process name with the first letter capitalized)" <<
RESTendl;
632 TString volName3 = nameWithoutSuffix.substr(0, nameWithoutSuffix.length() - processName.length());
634 volName3 = aliasObsToVol[fObservables[i]].c_str();
643 if (availableProcesses.count(geant4Name) == 0) {
644 RESTWarning <<
"TRestGeant4AnalysisProcess: Geant4 process '" << geant4Name
645 <<
"' (observable '" << fObservables[i]
646 <<
"') is not registered in the physics info of this simulation. "
647 <<
"It will be 0 unless energy is deposited under this process name "
648 <<
"(processes sharing type and subtype, e.g. eIoni and ionIoni, are "
649 <<
"registered only once)" <<
RESTendl;
656 if (fObservables[i].find(
"TracksCounter") != string::npos) {
657 TString particleName = fObservables[i].substr(0, fObservables[i].length() - 13).c_str();
662 if (fObservables[i].find(
"TracksEDep") != string::npos) {
663 TString particleName = fObservables[i].substr(0, fObservables[i].length() - 10).c_str();
679 Double_t sensitiveVolumeEnergy =
fOutputG4Event->GetEnergyInVolume(sensitiveVolumeName.Data());
681 double hitTime = std::numeric_limits<double>::infinity();
682 std::set<int> trackIdsInSensitiveVolume;
685 const auto& hits = track.GetHits();
686 for (
size_t hitIndex = 0; hitIndex < hits.GetNumberOfHits(); hitIndex++) {
687 const auto volumeName = hits.GetVolumeName(hitIndex);
688 if (volumeName != sensitiveVolumeName) {
691 const double energy = hits.GetEnergy(hitIndex);
696 const double time = hits.GetTime(hitIndex);
697 if (time < hitTime) {
701 trackIdsInSensitiveVolume.insert(track.GetTrackID());
707 std::set<int> trackParentsOfInterest;
708 for (
const auto& trackIdInSensitiveVolume : trackIdsInSensitiveVolume) {
709 const auto track =
fOutputG4Event->GetTrackByID(trackIdInSensitiveVolume);
712 while (parent !=
nullptr && !found) {
714 const auto& hits = parent->GetHits();
715 if (hits.GetVolumeName(0) != sensitiveVolumeName) {
716 for (
size_t hitIndex = 0; hitIndex < hits.GetNumberOfHits(); hitIndex++) {
717 const auto volumeName = hits.GetVolumeName(hitIndex);
718 if (volumeName != sensitiveVolumeName) {
720 trackParentsOfInterest.insert(parent->GetTrackID());
726 parent = parent->GetParentTrack();
730 if (!trackParentsOfInterest.empty()) {
731 const auto track =
fOutputG4Event->GetTrackByID(*trackParentsOfInterest.begin());
733 const auto position = track->GetInitialPosition();
738 const auto energy = track->GetInitialKineticEnergy();
741 const string particleName = track->GetParticleName().Data();
744 string parentParticleName;
745 if (track->GetParentTrack() !=
nullptr) {
746 parentParticleName = track->GetParentTrack()->GetParticleName().Data();
750 const string creatorProcess = track->GetCreatorProcess().Data();
753 const string volumeName = track->GetHits().GetVolumeName(0).Data();
760 cout <<
"----------------------------" << endl;
762 cout <<
"Sensitive volume Energy : " << sensitiveVolumeEnergy << endl;
763 cout <<
"Total energy : " <<
fOutputG4Event->GetTotalDepositedEnergy() << endl;
777 Double_t xDirection =
fOutputG4Event->GetPrimaryEventDirection(0).X();
780 Double_t yDirection =
fOutputG4Event->GetPrimaryEventDirection(0).Y();
783 Double_t zDirection =
fOutputG4Event->GetPrimaryEventDirection(0).Z();
787 string subEventPrimaryParticleName;
789 subEventPrimaryParticleName =
fOutputG4Event->GetSubEventPrimaryEventParticleName();
791 subEventPrimaryParticleName =
"generator";
795 TVector3 primaryDirection(xDirection, yDirection, zDirection);
796 primaryDirection = primaryDirection.Unit();
799 SetObservableValue(
"zenithYDegrees", TMath::ACos(-1 * yDirection) * TMath::RadToDeg());
801 sourceDirection = sourceDirection.Unit();
803 TMath::ACos(primaryDirection.Dot(sourceDirection)) * TMath::RadToDeg());
805 Double_t energyPrimary =
fOutputG4Event->GetPrimaryEventEnergy(0);
818 const Int_t processID = physicsInfo.GetProcessID(processName);
820 const bool processIsRegistered = physicsInfo.GetProcessName(processID) == processName;
821 Int_t containsProcess = 0;
822 if (processIsRegistered &&
fOutputG4Event->ContainsProcess(processID)) {
829 const auto energyInVolumePerProcess =
fOutputG4Event->GetEnergyInVolumePerProcessMap();
833 if (volume != energyInVolumePerProcess.end()) {
834 const auto process = volume->second.find(
fProcessName[n]);
835 if (process != volume->second.end()) {
836 energy = process->second;
844 const auto energyInVolumePerParticlePerProcess =
846 const auto sensitiveVolume = energyInVolumePerParticlePerProcess.find(sensitiveVolumeName.Data());
849 if (sensitiveVolume != energyInVolumePerParticlePerProcess.end()) {
850 for (
const auto& [particle, energyPerProcess] : sensitiveVolume->second) {
855 const auto process = energyPerProcess.find(processName);
856 if (process != energyPerProcess.end()) {
857 energy += process->second;
863 energy = sensitiveVolumeEnergy > 0 ? energy / sensitiveVolumeEnergy : 0;
891 if (
fDirID[n] == (TString)
"X")
894 else if (
fDirID[n] == (TString)
"Y")
897 else if (
fDirID[n] == (TString)
"Z")
904 cout <<
"G4 Tracks : " <<
fOutputG4Event->GetNumberOfTracks() << endl;
905 cout <<
"----------------------------" << endl;
911std::map<std::string, std::string> TRestGeant4AnalysisProcess::GetAliasObservableNameToVolume() {
913 std::map<std::string, std::string> obsNamesToVolumes;
915 while (e !=
nullptr) {
916 const char* obschr = e->Attribute(
"name");
917 const char* _value = e->Attribute(
"value");
918 const char* _vol = e->Attribute(
"volume");
921 if (_value ==
nullptr)
927 if (obschr !=
nullptr) {
931 obsNamesToVolumes[(string)obschr] = volume;
936 e = e->NextSiblingElement(
"observable");
939 return obsNamesToVolumes;
TRestAnalysisTree * fAnalysisTree
void SetObservableValue(const std::string &name, const T &value)
Set observable value for AnalysisTree.
A base class for any REST event.
A pure analysis process to extract information from a TRestGeant4Event.
std::vector< std::string > fPerProcessParticle
The particle restriction of each PerProcessXxx observable (empty means any particle).
void Initialize() override
Function to initialize input/output event members and define the section name.
std::vector< std::string > fEnergyInObservables
It stores the name of observables xxxVolumeEDep related to the energy deposition in volume xxx.
std::vector< std::string > fDirID
std::string GetGeant4ProcessName(const std::string &name) const
It returns the Geant4 process name corresponding to name.
void InitProcess() override
Process initialization. Observable names are interpreted and auxiliar observable members,...
TRestGeant4Event * fInputG4Event
A pointer to the specific TRestGeant4Event input.
void LoadConfig(const std::string &configFilename, const std::string &name="")
Function to load the configuration from an external configuration file.
TRestGeant4Metadata * fG4Metadata
A pointer to the simulation metadata information accessible to TRestRun.
~TRestGeant4AnalysisProcess()
Default destructor.
std::vector< std::string > fTracksEDepObservables
A std::vector storing the observable name xxxTracksEDep for a given xxx particle.
std::vector< std::string > fParticleTrackCounter
A std::vector storing the xxx particle name extracted from xxxTracksCounter.
std::vector< std::string > fProcessObservables
std::vector< Int_t > fVolumeID2
A std::vector storing the active volume ids corresponding mean position observable xxxMeanPosX,...
Bool_t fPerProcessSensitiveEnergyNorm
If true, PerProcessXxx observables are normalized to the total energy in the sensitive volume.
std::vector< std::string > fProcessVolumeName
A std::vector storing the volume name corresponding to each process observable.
void LoadDefaultConfig()
Function to load the default config in absence of RML input.
std::vector< std::string > fPerProcessObservables
A std::vector storing the observable names PerProcessXxx (only if fPerProcessSensitiveEnergy).
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
The main processing event function.
std::vector< std::string > fContainsProcessObservables
A std::vector storing the observable names containsProcessXxx.
std::vector< Int_t > fVolumeID
A std::vector storing the active volume ids of observables xxxVolumeEDep.
Bool_t fPerProcessSensitiveEnergy
TRestGeant4Event * fOutputG4Event
A pointer to the specific TRestGeant4Event output.
std::vector< std::string > fTrackCounterObservables
A std::vector storing the observable name xxxTracksCounter for a given xxx particle.
std::vector< std::vector< std::string > > fPerProcessG4Names
The Geant4 process names contributing to each PerProcessXxx observable.
std::vector< Int_t > fVolumeID3
A std::vector storing the active volume ids corresponding process observable .
static const std::map< std::string, std::string > & GetRestToGeant4ProcessNameMap()
It returns the map between the process names used in REST observables (<volume><Process>Process) and ...
TRestGeant4AnalysisProcess()
Default constructor.
std::vector< std::string > fMeanPosObservables
A std::vector storing the name of active volumes.
std::vector< std::string > fProcessName
A std::vector storing the Geant4 name of the process corresponding to each process observable.
void EndProcess() override
Function to include required actions after all events have been processed.
std::vector< std::string > fContainsProcessG4Name
A std::vector storing the Geant4 process name corresponding to each containsProcessXxx observable.
std::vector< std::string > fParticleTrackEdep
A std::vector storing the xxx particle name extracted from xxxTracksEDep.
void PrintNotActiveVolumeWarning(const TString &volumeName)
It prints a warning when the volume used by an observable is not an active volume.
An event class to store geant4 generated event information.
Double_t GetBoundingBoxSize()
This method returns the event size as the size of the bounding box enclosing all hits.
@ REST_Debug
+show the defined debug messages
std::string ToUpper(std::string in)
Convert string to its upper case. Alternative of TString::ToUpper.