REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
src/TRestGeant4Metadata.cxx
1/*************************************************************************
2 * This file is part of the REST software framework. *
3 * *
4 * Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) *
5 * For more information see http://gifna.unizar.es/trex *
6 * *
7 * REST is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * REST is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have a copy of the GNU General Public License along with *
18 * REST in $REST_PATH/LICENSE. *
19 * If not, see http://www.gnu.org/licenses/. *
20 * For the list of contributors see $REST_PATH/CREDITS. *
21 *************************************************************************/
22
726
727#include "TRestGeant4Metadata.h"
728
729#include <TAxis.h>
730#include <TGeoManager.h>
731#include <TRandom.h>
732#include <TRestGDMLParser.h>
733#include <TRestRun.h>
734
735#include "TRestGeant4PrimaryGeneratorInfo.h"
736
737using namespace std;
738using namespace TRestGeant4PrimaryGeneratorTypes;
739
740ClassImp(TRestGeant4Metadata);
741
746
761TRestGeant4Metadata::TRestGeant4Metadata(const char* configFilename, const string& name)
762 : TRestMetadata(configFilename) {
763 Initialize();
764
766}
767
772
777 SetSectionName(this->ClassName());
778 SetLibraryVersion(LIBRARY_VERSION);
779
780 fChance.clear();
781 fActiveVolumes.clear();
782 fBiasingVolumes.clear();
783
785}
786
791 this->Initialize();
792
793 fMagneticField = Get3DVectorParameterWithUnits("magneticField", TVector3(0, 0, 0));
794
795 // Initialize the metadata members from a configfile
796 fGdmlFilename = GetParameter("gdmlFile");
797 if (fGdmlFilename == PARAMETER_NOT_FOUND_STR) {
798 fGdmlFilename = GetParameter("gdml_file"); // old name
799 }
800 if (fGdmlFilename == PARAMETER_NOT_FOUND_STR) {
801 cout << "\"gdmlFile\" parameter is not defined!" << endl;
802 exit(1);
803 }
804
805 fGeometryPath = GetParameter("geometryPath", "");
806
807 string seedString = GetParameter("seed", "0");
808 if (ToUpper(seedString) == "RANDOM" || ToUpper(seedString) == "RAND" || ToUpper(seedString) == "AUTO" ||
809 seedString == "0") {
810 auto dd = new double();
811 fSeed = (uintptr_t)dd + (uintptr_t)this;
812 delete dd;
813 } else {
814 fSeed = (Long_t)StringToInteger(seedString);
815 }
816 gRandom->SetSeed(fSeed);
817
818 // if "gdmlFile" is purely a file (without any path) and "geometryPath" is
819 // defined, we recombine them together
820 if ((((string)fGdmlFilename).find_first_not_of("./~") == 0 ||
821 ((string)fGdmlFilename).find("/") == string::npos) &&
822 fGeometryPath != "") {
823 if (fGeometryPath[fGeometryPath.Length() - 1] == '/') {
825 } else {
826 fGdmlFilename = fGeometryPath + "/" + GetParameter("gdmlFile");
827 }
828 }
829
830 Double_t defaultTime = 1. / REST_Units::s;
831 fSubEventTimeDelay = GetDblParameterWithUnits("subEventTimeDelay", defaultTime);
832
833 auto nEventsString = GetParameter("nEvents");
834 if (nEventsString == PARAMETER_NOT_FOUND_STR) {
835 nEventsString = GetParameter("Nevents"); // old name
836 }
837 fNEvents = nEventsString == PARAMETER_NOT_FOUND_STR ? 0 : StringToInteger(nEventsString);
838
839 const auto fNRequestedEntriesString = GetParameter("nRequestedEntries");
841 fNRequestedEntriesString == PARAMETER_NOT_FOUND_STR ? 0 : StringToInteger(fNRequestedEntriesString);
842
843 fSaveAllEvents = ToUpper(GetParameter("saveAllEvents", "false")) == "TRUE" ||
844 ToUpper(GetParameter("saveAllEvents", "off")) == "ON";
845
846 fPrintProgress = ToUpper(GetParameter("printProgress", "true")) == "TRUE" ||
847 ToUpper(GetParameter("printProgress", "on")) == "ON";
848
849 fRegisterEmptyTracks = ToUpper(GetParameter("registerEmptyTracks", "false")) == "TRUE" ||
850 ToUpper(GetParameter("registerEmptyTracks", "off")) == "ON";
851
853 // Detector (old storage) section is processed after initializing geometry info in Detector Construction
854 // This allows to use regular expression to match logical or physical volumes etc.
855 ReadBiasing();
856
857 fMaxTargetStepSize = GetDblParameterWithUnits("maxTargetStepSize", -1);
858 if (fMaxTargetStepSize > 0) {
859 cout << " " << endl;
860 RESTWarning << "IMPORTANT: *maxTargetStepSize* parameter is now obsolete!" << RESTendl;
861 RESTWarning << "The sensitive volume will not define any integration step limit" << RESTendl;
862 cout << " " << endl;
863 RESTWarning << "In order to avoid this warning REMOVE the *maxTargetStepSize* definition,"
864 << RESTendl;
865 RESTWarning << "and replace it by the following statement at the <storage> section" << RESTendl;
866 cout << " " << endl;
867 RESTWarning << "<activeVolume name=\"" << this->GetSensitiveVolume() << "\" maxStepSize=\""
868 << fMaxTargetStepSize << "mm\" />" << RESTendl;
869 cout << " " << endl;
870 RESTInfo << "Now, any active volume is allowed to define a maxStepSize" << RESTendl;
871 cout << " " << endl;
872 RESTInfo << "It is also possible to define a default step size for all active volumes," << RESTendl;
873 RESTInfo << "so that in case no step is defined, the default will be used." << RESTendl;
874 cout << " " << endl;
875 RESTInfo << "<storage sensitiveVolume=\"" << this->GetSensitiveVolume() << "\" maxStepSize=\""
876 << fMaxTargetStepSize << "mm\" />" << RESTendl;
877 cout << " " << endl;
878 GetChar();
879 }
880
881 // should return success or fail
882}
883
902
904 if (TRestGeant4PrimaryGeneratorTypes::StringToSpatialGeneratorTypes(
906 TRestGeant4PrimaryGeneratorTypes::SpatialGeneratorTypes::COSMIC) {
907 RESTError
908 << "TRestGeant4Metadata::GetEquivalentSimulatedTime can only be called for 'cosmic' generator"
909 << RESTendl;
910 exit(1);
911 }
912 const auto source = GetParticleSource();
913 if (TRestGeant4PrimaryGeneratorTypes::StringToEnergyDistributionTypes(
914 source->GetEnergyDistributionType().Data()) !=
915 TRestGeant4PrimaryGeneratorTypes::EnergyDistributionTypes::FORMULA2) {
916 RESTError << "TRestGeant4Metadata::GetEquivalentSimulatedTime can only be called for 'formula2' "
917 "energy distribution"
918 << RESTendl;
919 exit(1);
920 }
921 if (TRestGeant4PrimaryGeneratorTypes::StringToAngularDistributionTypes(
922 source->GetAngularDistributionType().Data()) !=
923 TRestGeant4PrimaryGeneratorTypes::AngularDistributionTypes::FORMULA2) {
924 RESTError << "TRestGeant4Metadata::GetEquivalentSimulatedTime can only be called for 'formula' "
925 "angular distribution"
926 << RESTendl;
927 exit(1);
928 }
929
930 const auto energyRange = source->GetEnergyDistributionRange();
931 const auto angularRange = source->GetAngularDistributionRange();
932 auto function = (TF2*)source->GetEnergyAndAngularDistributionFunction()->Clone();
933 // counts per second per cm2 (distribution is already integrated over uniform phi)
934 const auto countsPerSecondPerCm2 =
935 function->Integral(energyRange.X(), energyRange.Y(), angularRange.X(), angularRange.Y(), 1E-9);
936 return countsPerSecondPerCm2;
937}
938
939Double_t TRestGeant4Metadata::GetCosmicIntensityInCountsPerSecond() const {
940 const auto countsPerSecondPerCm2 = GetCosmicFluxInCountsPerCm2PerSecond();
942 const auto countsPerSecond = countsPerSecondPerCm2 * surface;
943 return countsPerSecond;
944}
945
946Double_t TRestGeant4Metadata::GetEquivalentSimulatedTime() const {
947 const auto countsPerSecond = GetCosmicIntensityInCountsPerSecond();
948 const auto seconds = fNEvents / countsPerSecond;
949 return seconds;
950}
951
952void TRestGeant4Metadata::ReadBiasing() {
953 TiXmlElement* biasingDefinition = GetElement("biasing");
954 if (biasingDefinition == nullptr) {
956 return;
957 }
958 TString biasEnabled = GetFieldValue("value", biasingDefinition);
959 TString biasType = GetFieldValue("type", biasingDefinition);
960
961 RESTDebug << "Bias: " << biasEnabled << RESTendl;
962
963 if (biasEnabled == "on" || biasEnabled == "ON" || biasEnabled == "On" || biasEnabled == "oN") {
964 RESTInfo << "Biasing is enabled" << RESTendl;
965
966 TiXmlElement* biasVolumeDefinition = GetElement("biasingVolume", biasingDefinition);
967 Int_t n = 0;
968 while (biasVolumeDefinition) {
969 TRestGeant4BiasingVolume biasVolume;
970 RESTDebug << "Def: " << biasVolumeDefinition << RESTendl;
971
972 biasVolume.SetBiasingVolumePosition(
973 Get3DVectorParameterWithUnits("position", biasVolumeDefinition));
974 biasVolume.SetBiasingFactor(StringToDouble(GetParameter("factor", biasVolumeDefinition)));
975 biasVolume.SetBiasingVolumeSize(GetDblParameterWithUnits("size", biasVolumeDefinition));
976 biasVolume.SetEnergyRange(Get2DVectorParameterWithUnits("energyRange", biasVolumeDefinition));
977 biasVolume.SetBiasingVolumeType(biasType); // For the moment all the volumes should be same type
978
979 /* TODO check that values are right if not printBiasingVolume with
980 getchar() biasVolume.PrintBiasingVolume(); getchar();
981 */
982
983 fBiasingVolumes.push_back(biasVolume);
984 biasVolumeDefinition = GetNextElement(biasVolumeDefinition);
985 n++;
986 }
988 }
989}
990
1016 // TODO if some fields are defined in the generator but not finally used
1017 // i.e. <generator type="volume" from="gasTarget" position="(100,0,-100)
1018 // here position is irrelevant since the event will be generated from the
1019 // volume defined in the geometry we should take care of these values so they
1020 // are not stored in metadata (to avoid future confusion) In the particular
1021 // case of position, the value is overwritten in DetectorConstruction by the
1022 // center of the volume (i.e. gasTarget) but if i.e rotation or side are
1023 // defined and not relevant we should set it to -1
1024
1025 TiXmlElement* generatorDefinition = GetElement("generator");
1026
1028 SpatialGeneratorTypesToString(StringToSpatialGeneratorTypes(GetParameter(
1029 "type", generatorDefinition, SpatialGeneratorTypesToString(SpatialGeneratorTypes::VOLUME))));
1031 SpatialGeneratorShapesToString(StringToSpatialGeneratorShapes(GetParameter(
1032 "shape", generatorDefinition, SpatialGeneratorShapesToString(SpatialGeneratorShapes::BOX))));
1033 fGeant4PrimaryGeneratorInfo.fSpatialGeneratorFrom = GetParameter("from", generatorDefinition);
1034 if (fGeant4PrimaryGeneratorInfo.fSpatialGeneratorFrom != PARAMETER_NOT_FOUND_STR) {
1036 SpatialGeneratorShapesToString(SpatialGeneratorShapes::GDML);
1037 }
1039 Get3DVectorParameterWithUnits("size", generatorDefinition, {0, 0, 0});
1041 Get3DVectorParameterWithUnits("position", generatorDefinition, {0, 0, 0});
1043 Get3DVectorParameterWithUnits("rotationAxis", generatorDefinition, {0, 0, 1});
1045 GetDblParameterWithUnits("rotationAngle", generatorDefinition, 0);
1047 GetParameter("densityFunc", generatorDefinition, "1");
1048
1049 TiXmlElement* sourceDefinition = GetElement("source", generatorDefinition);
1050 while (sourceDefinition) {
1051 string use = GetParameter("use", sourceDefinition, "");
1052
1053 TRestGeant4ParticleSource* source = TRestGeant4ParticleSource::instantiate(use);
1054 ReadParticleSource(source, sourceDefinition);
1055 AddParticleSource(source);
1056
1057 sourceDefinition = GetNextElement(sourceDefinition);
1058 }
1059
1060 // check if the generator is valid.
1061 if (GetNumberOfSources() == 0) {
1062 RESTError << "No sources are added inside generator!" << RESTendl;
1063 exit(1);
1064 }
1065}
1066
1071 TiXmlElement* sourceDefinition = definition;
1072
1073 source->SetParticleName(GetParameter("particle", sourceDefinition));
1074 source->SetExcitationLevel(StringToDouble(GetParameter("excitedLevel", sourceDefinition)));
1075 source->SetParticleCharge(StringToInteger(GetParameter("charge", sourceDefinition, "0")));
1076
1077 TString fullChain = GetParameter("fullChain", sourceDefinition);
1078 SetFullChain(false);
1079 if (fullChain.EqualTo("on", TString::ECaseCompare::kIgnoreCase)) {
1080 SetFullChain(true);
1081 }
1082
1083 // Angular distribution parameters
1084 TiXmlElement* angularDefinition = GetElement("angular", sourceDefinition);
1085 if (angularDefinition == nullptr) {
1086 angularDefinition = GetElement("angularDist", sourceDefinition); // old name
1087 }
1088 source->SetAngularDistributionType(GetParameter(
1089 "type", angularDefinition, AngularDistributionTypesToString(AngularDistributionTypes::FLUX)));
1090 if (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1091 AngularDistributionTypes::TH1D) {
1092 source->SetAngularDistributionFilename(SearchFile(GetParameter("file", angularDefinition)));
1093 auto name = GetParameter("name", angularDefinition);
1094 if (name == "NO_SUCH_PARA") {
1095 name = GetParameter("spctName", angularDefinition); // old name
1096 }
1097 source->SetAngularDistributionNameInFile(name);
1098 }
1099 source->SetAngularDistributionRange(
1100 Get2DVectorParameterWithUnits("range", angularDefinition, {0, TMath::Pi()}));
1101 if (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1102 AngularDistributionTypes::FORMULA) {
1103 source->SetAngularDistributionFormula(GetParameter("name", angularDefinition));
1104 // We cannot use an angular range bigger than the range of the formula
1105 const auto function = source->GetAngularDistributionFunction();
1106 if (source->GetAngularDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1107 source->SetAngularDistributionRange(
1108 {function->GetXaxis()->GetXmin(), source->GetAngularDistributionRangeMax()});
1109 }
1110 if (source->GetAngularDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1111 source->SetAngularDistributionRange(
1112 {source->GetAngularDistributionRangeMin(), function->GetXaxis()->GetXmax()});
1113 }
1114 }
1115 if ((StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1116 AngularDistributionTypes::FORMULA) ||
1117 (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1118 AngularDistributionTypes::FORMULA2)) {
1119 source->SetAngularDistributionFormulaNPoints(static_cast<size_t>(GetDblParameterWithUnits(
1120 "nPoints", angularDefinition, source->GetAngularDistributionFormulaNPoints())));
1121 }
1122 if (GetNumberOfSources() == 0 &&
1123 StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1124 AngularDistributionTypes::BACK_TO_BACK) {
1125 cout << "WARNING: First source cannot be backtoback. Setting it to isotropic" << endl;
1126 source->SetAngularDistributionType(
1127 AngularDistributionTypesToString(AngularDistributionTypes::ISOTROPIC));
1128 }
1129 source->SetDirection(StringTo3DVector(GetParameter("direction", angularDefinition, "(1,0,0)")));
1130
1131 // Energy distribution parameters
1132 TiXmlElement* energyDefinition = GetElement("energy", sourceDefinition);
1133 if (energyDefinition == nullptr) {
1134 energyDefinition = GetElement("energyDist", sourceDefinition); // old name
1135 }
1136 source->SetEnergyDistributionType(GetParameter(
1137 "type", energyDefinition, EnergyDistributionTypesToString(EnergyDistributionTypes::MONO)));
1138 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1139 EnergyDistributionTypes::TH1D) {
1140 source->SetEnergyDistributionFilename(SearchFile(GetParameter("file", energyDefinition)));
1141 auto name = GetParameter("name", energyDefinition);
1142 if (name == "NO_SUCH_PARA") {
1143 name = GetParameter("spctName", energyDefinition); // old name
1144 }
1145 source->SetEnergyDistributionNameInFile(name);
1146 }
1147 source->SetEnergyDistributionRange(Get2DVectorParameterWithUnits("range", energyDefinition, {0, 1E20}));
1148 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1149 EnergyDistributionTypes::MONO) {
1150 Double_t energy;
1151 energy = GetDblParameterWithUnits("energy", energyDefinition, 0);
1152 source->SetEnergyDistributionRange({energy, energy});
1153 source->SetEnergy(energy);
1154 }
1155 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1156 EnergyDistributionTypes::FORMULA) {
1157 source->SetEnergyDistributionFormula(GetParameter("name", energyDefinition));
1158 // We cannot use an energy range bigger than the range of the formula
1159 const auto function = source->GetEnergyDistributionFunction();
1160 if (source->GetEnergyDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1161 source->SetEnergyDistributionRange(
1162 {function->GetXaxis()->GetXmin(), source->GetEnergyDistributionRangeMax()});
1163 }
1164 if (source->GetEnergyDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1165 source->SetEnergyDistributionRange(
1166 {source->GetEnergyDistributionRangeMin(), function->GetXaxis()->GetXmax()});
1167 }
1168 }
1169 if ((StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1170 EnergyDistributionTypes::FORMULA) ||
1171 (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1172 EnergyDistributionTypes::FORMULA2)) {
1173 source->SetEnergyDistributionFormulaNPoints(static_cast<size_t>(GetDblParameterWithUnits(
1174 "nPoints", energyDefinition, source->GetEnergyDistributionFormulaNPoints())));
1175 }
1176 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1177 EnergyDistributionTypes::FORMULA2 &&
1178 StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1179 AngularDistributionTypes::FORMULA2) {
1180 const auto empty = TString("");
1181 auto energyDistName = GetParameter("name", energyDefinition, empty);
1182 auto angularDistName = GetParameter("name", energyDefinition, empty);
1183
1184 if (energyDistName == empty && angularDistName == empty) {
1185 RESTError << "No name specified for energy and angular distribution" << RESTendl;
1186 exit(1);
1187 }
1188 if (energyDistName == empty) {
1189 angularDistName = energyDistName;
1190 RESTWarning << "No name specified for energy distribution. Using angular distribution name: "
1191 << angularDistName << RESTendl;
1192 }
1193 if (angularDistName == empty) {
1194 energyDistName = energyDistName;
1195 RESTWarning << "No name specified for angular distribution. Using energy distribution name: "
1196 << energyDistName << RESTendl;
1197 }
1198
1199 if (energyDistName == empty || angularDistName == empty) {
1200 // we should never enter here, just leave this as a check
1201 RESTError << "When using 'formula2' the name of energy and angular dist must match" << RESTendl;
1202 exit(1);
1203 }
1204 const auto energyAndAngularDistName = energyDistName;
1205 source->SetEnergyAndAngularDistributionFormula(energyAndAngularDistName);
1206
1207 const auto function = source->GetEnergyAndAngularDistributionFunction();
1208
1209 // Set energy range
1210 if (source->GetEnergyDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1211 source->SetEnergyDistributionRange(
1212 {function->GetXaxis()->GetXmin(), source->GetEnergyDistributionRangeMax()});
1213 }
1214 if (source->GetEnergyDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1215 source->SetEnergyDistributionRange(
1216 {source->GetEnergyDistributionRangeMin(), function->GetXaxis()->GetXmax()});
1217 }
1218
1219 // Set angular range
1220 if (source->GetAngularDistributionRangeMin() < function->GetYaxis()->GetXmin()) {
1221 source->SetAngularDistributionRange(
1222 {function->GetYaxis()->GetXmin(), source->GetAngularDistributionRangeMax()});
1223 }
1224 if (source->GetAngularDistributionRangeMax() > function->GetYaxis()->GetXmax()) {
1225 source->SetAngularDistributionRange(
1226 {source->GetAngularDistributionRangeMin(), function->GetYaxis()->GetXmax()});
1227 }
1228 }
1229 // allow custom configuration from the class
1230 source->LoadConfigFromElement(sourceDefinition, fElementGlobal, fVariables);
1231 // AddParticleSource(source);
1232}
1233
1235 for (auto source : fParticleSource) {
1236 delete source;
1237 }
1238 fParticleSource.clear();
1239}
1240
1242 fParticleSource.push_back(src);
1243}
1244
1260 RESTInfo << "TRestGeant4Metadata: Processing detector section" << RESTendl;
1261 TiXmlElement* detectorDefinition = GetElement("detector");
1262 if (detectorDefinition == nullptr) {
1263 RESTError << "Detector section (<detector>) is not present in metadata!" << RESTendl;
1264 exit(1);
1265 }
1266
1267 const bool activateAllVolumes =
1268 StringToBool(GetParameter("activateAllVolumes", detectorDefinition, "true"));
1269 RESTInfo << "TRestGeant4Metadata: Setting 'fActivateAllVolumes' to " << fActivateAllVolumes << RESTendl;
1270 fActivateAllVolumes = activateAllVolumes;
1271
1272 TiXmlElement* removeUnwantedTracksDefinition = GetElement("removeUnwantedTracks", detectorDefinition);
1273 if (removeUnwantedTracksDefinition != nullptr) {
1274 fRemoveUnwantedTracks = StringToBool(GetParameter("enabled", removeUnwantedTracksDefinition, "true"));
1276 StringToBool(GetParameter("keepZeroEnergyTracks", removeUnwantedTracksDefinition, "false"));
1277 RESTInfo << "TRestGeant4Metadata: Setting 'fRemoveUnwantedTracks' to " << fRemoveUnwantedTracks
1278 << " with 'keepZeroEnergyTracks' option set to " << fRemoveUnwantedTracksKeepZeroEnergyTracks
1279 << RESTendl;
1280 }
1281
1282 Double_t defaultStep = GetDblParameterWithUnits("maxStepSize", detectorDefinition);
1283 if (defaultStep < 0) {
1284 defaultStep = 0;
1285 }
1286
1287 TiXmlElement* volumeDefinition = GetElement("volume", detectorDefinition);
1288 while (volumeDefinition != nullptr) {
1289 string name = GetFieldValue("name", volumeDefinition);
1290 if (name.empty() || name == "Not defined") {
1291 RESTError << "volume inside detector section defined without name" << RESTendl;
1292 exit(1);
1293 }
1294 vector<string> physicalVolumes;
1295 if (!fGeant4GeometryInfo.IsValidGdmlName(name)) {
1296 if (fGeant4GeometryInfo.IsValidLogicalVolume(name)) {
1297 for (const auto& physical : fGeant4GeometryInfo.GetAllPhysicalVolumesFromLogical(name)) {
1298 physicalVolumes.emplace_back(
1299 fGeant4GeometryInfo.GetAlternativeNameFromGeant4PhysicalName(physical));
1300 }
1301 }
1302 // does not match a explicit (gdml) physical name or a logical name, perhaps its a regular exp
1303 if (physicalVolumes.empty()) {
1304 for (const auto& physical :
1305 fGeant4GeometryInfo.GetAllPhysicalVolumesMatchingExpression(name)) {
1306 physicalVolumes.emplace_back(
1307 fGeant4GeometryInfo.GetAlternativeNameFromGeant4PhysicalName(physical));
1308 }
1309 }
1310 if (physicalVolumes.empty()) {
1311 for (const auto& logical : fGeant4GeometryInfo.GetAllLogicalVolumesMatchingExpression(name)) {
1312 for (const auto& physical :
1313 fGeant4GeometryInfo.GetAllPhysicalVolumesFromLogical(logical)) {
1314 physicalVolumes.emplace_back(
1315 fGeant4GeometryInfo.GetAlternativeNameFromGeant4PhysicalName(physical));
1316 }
1317 }
1318 }
1319 } else {
1320 physicalVolumes.push_back(name);
1321 }
1322
1323 if (physicalVolumes.empty()) {
1324 RESTError
1325 << "volume '" << name
1326 << "' is not defined in the geometry. Could not match to a physical, logical volume or regex"
1327 << RESTendl;
1328 exit(1);
1329 }
1330
1331 bool isSensitive = false;
1332 const string isSensitiveValue = GetFieldValue("sensitive", volumeDefinition);
1333 if (isSensitiveValue != "Not defined") {
1334 isSensitive = StringToBool(isSensitiveValue);
1335 }
1336
1337 bool isKeepTracks = isSensitive;
1338 const string isKeepTracksValue = GetFieldValue("keepTracks", volumeDefinition);
1339 if (isKeepTracksValue != "Not defined") {
1340 isKeepTracks = StringToBool(isKeepTracksValue);
1341 }
1342
1343 bool isKill = false;
1344 const string isKillValue = GetFieldValue("kill", volumeDefinition);
1345 if (isKillValue != "Not defined") {
1346 isKill = StringToBool(isKillValue);
1347 }
1348
1349 Double_t chance = StringToDouble(GetFieldValue("chance", volumeDefinition));
1350 if (chance == -1 || chance < 0) {
1351 chance = 1.0;
1352 }
1353 Double_t maxStep = GetDblParameterWithUnits("maxStepSize", volumeDefinition);
1354 if (maxStep < 0) {
1355 maxStep = defaultStep;
1356 }
1357
1358 for (const auto& physical : physicalVolumes) {
1359 RESTInfo << "Adding " << (isSensitive ? "sensitive" : "active") << " volume from RML: '"
1360 << physical << (chance != 1 ? " with change: " + to_string(chance) : " ") << RESTendl;
1361 SetActiveVolume(physical, chance, maxStep);
1362 if (isSensitive) {
1363 InsertSensitiveVolume(physical);
1364 }
1365 if (fRemoveUnwantedTracks && isKeepTracks) {
1366 fRemoveUnwantedTracksVolumesToKeep.insert(physical);
1367 }
1368 if (isKill) {
1369 fKillVolumes.insert(physical);
1370 }
1371 }
1372 volumeDefinition = GetNextElement(volumeDefinition);
1373 }
1374
1375 if (fSensitiveVolumes.empty()) {
1376 cout << "No sensitive volumes defined in detector section. Adding 'gas' as sensitive volume" << endl;
1377 InsertSensitiveVolume("gas");
1378 }
1379
1380 fEnergyRangeStored = Get2DVectorParameterWithUnits("energyRange", detectorDefinition, fEnergyRangeStored);
1381 // TODO: Place this as a generic method
1382 if (fEnergyRangeStored.X() < 0) {
1384 }
1385 if (fEnergyRangeStored.Y() < 0) {
1387 }
1388 if (fEnergyRangeStored.Y() > fEnergyRangeStored.Y()) {
1390 }
1391 if (fEnergyRangeStored.Y() <= 0) {
1392 RESTError << "Energy range is not valid: (" << fEnergyRangeStored.X() << ", "
1393 << fEnergyRangeStored.Y() << ") keV" << RESTendl;
1394 exit(1);
1395 }
1396
1397 auto gdml = new TRestGDMLParser();
1398 gdml->Load(GetGdmlFilename().Data());
1399
1400 fGeant4GeometryInfo.PopulateFromGdml(gdml->GetOutputGDMLFile());
1401
1402 // If the user did not add explicitly any volume to the storage section we understand
1403 // the user wants to register all the volumes
1404 if (fActivateAllVolumes) {
1405 for (const auto& name : fGeant4GeometryInfo.GetAllPhysicalVolumes()) {
1406 if (!IsActiveVolume(name)) {
1407 SetActiveVolume(name, 1, defaultStep);
1408 RESTInfo << "Automatically adding active volume: '" << name << "' with chance: " << 1
1409 << RESTendl;
1410 }
1411 }
1412 }
1413
1414 if (GetNumberOfActiveVolumes() == 0) {
1415 RESTError << "No active volumes defined. Please check the detector section" << RESTendl;
1416 exit(1);
1417 }
1418}
1419
1426
1427 RESTMetadata << "Geant4 version: " << GetGeant4Version() << RESTendl;
1428 RESTMetadata << "Random seed: " << GetSeed() << RESTendl;
1429 RESTMetadata << "GDML geometry: " << GetGdmlReference() << RESTendl;
1430 RESTMetadata << "GDML materials reference: " << GetMaterialsReference() << RESTendl;
1431 RESTMetadata << "Sub-event time delay: " << GetSubEventTimeDelay() << " us" << RESTendl;
1432 Double_t mx = GetMagneticField().X();
1433 Double_t my = GetMagneticField().Y();
1434 Double_t mz = GetMagneticField().Z();
1435 RESTMetadata << "Magnetic field: (" << mx << ", " << my << ", " << mz << ") T" << RESTendl;
1436 if (fSaveAllEvents) RESTMetadata << "Save all events was enabled!" << RESTendl;
1438 RESTMetadata << "Register empty tracks was enabled" << RESTendl;
1439 } else {
1440 RESTMetadata << "Register empty tracks was NOT enabled" << RESTendl;
1441 }
1442
1443 RESTMetadata << " " << RESTendl;
1444 RESTMetadata << " ++++++++++ Generator +++++++++++ " << RESTendl;
1445 RESTMetadata << "Number of generated events: " << GetNumberOfEvents() << RESTendl;
1447
1448 for (int i = 0; i < GetNumberOfSources(); i++) GetParticleSource(i)->PrintParticleSource();
1449
1450 RESTMetadata << " " << RESTendl;
1451 RESTMetadata << " ++++++++++ Detector +++++++++++ " << RESTendl;
1452 RESTMetadata << "Energy range (keV): (" << GetMinimumEnergyStored() << ", " << GetMaximumEnergyStored()
1453 << ")" << RESTendl;
1454 RESTMetadata << "Number of sensitive volumes: " << GetNumberOfSensitiveVolumes() << RESTendl;
1455 for (const auto& sensitiveVolume : fSensitiveVolumes) {
1456 RESTMetadata << "Sensitive volume: " << sensitiveVolume << RESTendl;
1457 }
1458 RESTMetadata << "Number of active volumes: " << GetNumberOfActiveVolumes() << RESTendl;
1459 for (unsigned int n = 0; n < GetNumberOfActiveVolumes(); n++) {
1460 RESTMetadata << "Name: " << GetActiveVolumeName(n)
1461 << ", ID: " << GetActiveVolumeID(GetActiveVolumeName(n))
1462 << ", maxStep: " << GetMaxStepSize(GetActiveVolumeName(n)) << "mm "
1463 << ", chance: " << GetStorageChance(GetActiveVolumeName(n)) << RESTendl;
1464 }
1465
1466 for (unsigned int n = 0; n < GetNumberOfBiasingVolumes(); n++) {
1467 GetBiasingVolume(n).PrintBiasingVolume();
1468 }
1469
1470 if (GetRemoveUnwantedTracks()) {
1471 RESTMetadata << "removeUnwantedTracks is enabled "
1472 << (fRemoveUnwantedTracksKeepZeroEnergyTracks ? "with" : "without")
1473 << " keeping zero energy tracks" << RESTendl;
1474
1475 /*
1476 RESTMetadata << "keep volumes for removeUnwantedTracks:" << RESTendl;
1477 for (const auto& volume : fRemoveUnwantedTracksVolumesToKeep) {
1478 RESTMetadata << "\t" << volume << RESTendl;
1479 }
1480 */
1481 }
1482
1483 RESTMetadata << "+++++" << RESTendl;
1484}
1485
1489 Int_t id;
1490 for (id = 0; id < (Int_t)fActiveVolumes.size(); id++) {
1491 if (fActiveVolumes[id] == name) return id;
1492 }
1493 return -1;
1494}
1495
1510void TRestGeant4Metadata::SetActiveVolume(const TString& name, Double_t chance, Double_t maxStep) {
1511 for (size_t i = 0; i < fActiveVolumes.size(); i++) {
1512 const auto activeVolumeName = fActiveVolumes[i];
1513 if (name == activeVolumeName) {
1514 fChance[i] = chance;
1515 fMaxStepSize[i] = maxStep;
1516 return;
1517 }
1518 }
1519 fActiveVolumes.push_back(name);
1520 fChance.push_back(chance);
1521 fMaxStepSize.push_back(maxStep);
1522 fActiveVolumesSet.insert(name.Data());
1523}
1524
1529Bool_t TRestGeant4Metadata::isVolumeStored(const TString& volume) const {
1530 for (unsigned int n = 0; n < GetNumberOfActiveVolumes(); n++)
1531 if (GetActiveVolumeName(n) == volume) return true;
1532
1533 return false;
1534}
1535
1540 Int_t id;
1541 for (id = 0; id < (Int_t)fActiveVolumes.size(); id++) {
1542 if (fActiveVolumes[id] == volume) return fChance[id];
1543 }
1544 RESTWarning << "TRestGeant4Metadata::GetStorageChance. Volume " << volume << " not found" << RESTendl;
1545
1546 return 0;
1547}
1548
1552Double_t TRestGeant4Metadata::GetMaxStepSize(const TString& volume) {
1553 for (Int_t i = 0; i < (Int_t)fActiveVolumes.size(); i++) {
1554 if (volume.EqualTo(fActiveVolumes[i], TString::kIgnoreCase)) {
1555 return fMaxStepSize[i];
1556 }
1557 }
1558 RESTWarning << "TRestGeant4Metadata::GetMaxStepSize. Volume " << volume << " not found" << RESTendl;
1559
1560 return 0;
1561}
1562
1563size_t TRestGeant4Metadata::GetGeant4VersionMajor() const {
1564 TString majorVersion = "";
1565 for (int i = 0; i < fGeant4Version.Length(); i++) {
1566 auto c = fGeant4Version[i];
1567 if (c == '.') {
1568 break;
1569 }
1570 majorVersion += c;
1571 }
1572 return std::stoi(majorVersion.Data());
1573}
The main class to store the Geant4 simulation conditions that will be used by restG4.
std::vector< TString > fSensitiveVolumes
The volume that serves as trigger for data storage. Only events that deposit a non-zero energy on thi...
void ReadGenerator()
Reads the generator section defined inside TRestGeant4Metadata.
Long_t GetSeed() const
// Used for faster lookup
std::vector< TRestGeant4BiasingVolume > fBiasingVolumes
A std::vector containing the biasing volume properties.
size_t GetNumberOfBiasingVolumes() const
Returns the number of biasing volumes defined.
void ReadDetector()
Reads the storage section defined inside TRestGeant4Metadata.
Bool_t fActivateAllVolumes
Sets all volume as active without having to explicitly list them.
TString fGeometryPath
The local path to the GDML geometry.
TString GetSensitiveVolume(int n=0) const
Returns a std::string with the name of the sensitive volume.
TVector3 GetMagneticField() const
Returns the world magnetic field in Tesla.
void AddParticleSource(TRestGeant4ParticleSource *src)
Adds a new particle source.
TRestGeant4Metadata()
Default constructor.
void InitFromConfigFile() override
Initialization of TRestGeant4Metadata members through a RML file.
TString GetGdmlReference() const
Returns the reference provided at the GDML file header.
Int_t fNBiasingVolumes
The number of biasing volumes used in the simulation. If zero, no biasing technique is used.
void Initialize() override
Initialization of TRestGeant4Metadata members.
void PrintMetadata() override
Prints on screen the details about the Geant4 simulation conditions, stored in TRestGeant4Metadata.
void SetActiveVolume(const TString &name, Double_t chance, Double_t maxStep=0)
Adds a geometry volume to the list of active volumes.
Double_t GetMinimumEnergyStored() const
Returns the minimum event energy required for an event to be stored.
TRestGeant4GeometryInfo fGeant4GeometryInfo
Class used to store and retrieve geometry info.
unsigned int GetNumberOfActiveVolumes() const
Returns the number of active volumes, or geometry volumes that have been selected for data storage.
Double_t GetSubEventTimeDelay() const
Returns the time gap, in us, required to consider a Geant4 hit as a new independent event....
Double_t GetMaxStepSize(const TString &volume)
Returns the maximum step at a particular active volume.
Int_t fNEvents
The number of events simulated, or to be simulated.
~TRestGeant4Metadata()
Default destructor.
std::vector< Double_t > fMaxStepSize
A std::vector to store the maximum step size at a particular volume.
std::set< std::string > fRemoveUnwantedTracksVolumesToKeep
A container related to fRemoveUnwantedTracks.
TVector2 fEnergyRangeStored
A 2d-std::vector storing the energy range, in keV, to decide if a particular event should be written ...
TVector3 fMagneticField
The world magnetic field.
Int_t GetActiveVolumeID(TString name)
Returns the id of an active volume giving as parameter its name.
TRestGeant4BiasingVolume GetBiasingVolume(int n)
Return the biasing volume with index n.
TString fGeant4Version
The version of Geant4 used to generate the data.
TString GetActiveVolumeName(Int_t n) const
Returns a std::string with the name of the active volume with index n.
Int_t GetNumberOfEvents() const
Returns the number of events to be simulated.
std::vector< TString > fActiveVolumes
A std::vector to store the names of the active volumes.
TString GetGeant4Version() const
Returns a std::string with the version of Geant4 used on the event data simulation.
Int_t fNRequestedEntries
The number of events the user requested to be on the file.
Long_t fSeed
The seed value used for Geant4 random event generator. If it is zero its value will be assigned using...
void SetFullChain(Bool_t fullChain)
Enables/disables the full chain decay generation.
Int_t GetNumberOfSources() const
Returns the number of primary event sources defined in the generator.
void RemoveParticleSources()
Remove all the particle sources.
std::vector< Double_t > fChance
A std::vector to store the probability value to write to disk the hits in a particular event.
Double_t GetCosmicFluxInCountsPerCm2PerSecond() const
Reads the biasing section defined inside TRestGeant4Metadata.
Bool_t fPrintProgress
If this parameter is set to 'true' it will print out on screen every time 10k events are reached.
Bool_t fSaveAllEvents
If this parameter is set to 'true' it will save all events even if they leave no energy in the sensit...
Double_t fMaxTargetStepSize
The maximum target step size, in mm, allowed in Geant4 for the target volume (usually the gas volume)...
Double_t GetMaximumEnergyStored() const
Returns the maximum event energy required for an event to be stored.
std::vector< TRestGeant4ParticleSource * > fParticleSource
It the defines the primary source properties, particle type, momentum, energy, etc.
Bool_t fRegisterEmptyTracks
If this parameter is enabled it will register tracks with no hits inside. This is the default behavio...
Double_t GetStorageChance(Int_t n) const
Returns the probability per event to register (write to disk) hits in the storage volume with index n...
Double_t fSubEventTimeDelay
A time gap, in us, determining if an energy hit should be considered (and stored) as an independent e...
TString fGdmlFilename
The filename of the GDML geometry.
Bool_t fRemoveUnwantedTracks
If activated will remove tracks not present in volumes marked as "keep" or "sensitive".
void ReadParticleSource(TRestGeant4ParticleSource *src, TiXmlElement *sourceDefinition)
It reads the <source definition given by argument.
TRestGeant4PrimaryGeneratorInfo fGeant4PrimaryGeneratorInfo
Class used to store and retrieve Geant4 primary generator info.
TString GetGdmlFilename() const
Returns the main filename of the GDML geometry.
Bool_t isVolumeStored(const TString &volume) const
Returns true if the volume named volName has been registered for data storage.
TRestGeant4ParticleSource * GetParticleSource(size_t n=0) const
Returns the name of the particle source with index n (Geant4 based names).
void InsertSensitiveVolume(const TString &volume)
Sets the name of the sensitive volume.
Bool_t fRemoveUnwantedTracksKeepZeroEnergyTracks
Option for 'removeUnwantedTracks', if enabled tracks with hits in volumes will be kept event if they ...
TString GetMaterialsReference() const
Returns the reference provided at the materials file header.
TVector3 fSpatialGeneratorSize
The size of the generator. Stores up to three dimensions according to the shape box: length,...
TString GetSpatialGeneratorType() const
Returns a std::string specifying the generator type (volume, surface, point, virtualWall,...
TString fSpatialGeneratorFrom
The volume name where the events are generated, in case of volume or surface generator types.
TString fSpatialGeneratorSpatialDensityFunction
Defines density distribution of the generator shape. rho=F(x,y,z), in range 0~1.
Double_t fSpatialGeneratorRotationValue
degrees of rotation for generator virtual shape along the axis
TVector3 fSpatialGeneratorPosition
The position of the generator for virtual, and point, generator types.
Double_t GetSpatialGeneratorCosmicSurfaceTermCm2() const
Returns cosmic surface term (cm2) for simulation time computation.
TVector3 fSpatialGeneratorRotationAxis
A 3d-std::vector with the angles, measured in degrees, of a XYZ rotation applied to the virtual gener...
TString fSpatialGeneratorShape
Shape of spatial generator (wall, GDML, sphere, etc)
TString fSpatialGeneratorType
Type of spatial generator (point, surface, volume, custom)
A base class for any REST metadata class.
Definition: TRestMetadata.h:70
std::map< std::string, std::string > fVariables
Saving a list of rml variables. name-value std::pair.
virtual void PrintMetadata()
Implemented it in the derived metadata class to print out specific metadata information.
endl_t RESTendl
Termination flag object for TRestStringOutput.
TiXmlElement * GetElement(std::string eleDeclare, TiXmlElement *e=nullptr)
Get an xml element from a given parent element, according to its declaration.
Int_t LoadConfigFromFile(const std::string &configFilename, const std::string &sectionName="")
Give the file name, find out the corresponding section. Then call the main starter.
TiXmlElement * fElementGlobal
Saving the global element, to be passed to the resident class, if necessary.
void SetLibraryVersion(TString version)
Set the library version of this metadata class.
std::string GetFieldValue(std::string parName, TiXmlElement *e)
Returns the field value of an xml element which has the specified name.
Int_t LoadConfigFromElement(TiXmlElement *eSectional, TiXmlElement *eGlobal, std::map< std::string, std::string > envs={})
Main starter method.
void SetSectionName(std::string sName)
set the section name, clear the section content
std::string SearchFile(std::string filename)
Search files in current directory and directories specified in "searchPath" section.
std::string fConfigFileName
Full name of the rml file.
TiXmlElement * GetNextElement(TiXmlElement *e)
Get the next sibling xml element of this element, with same eleDeclare.
std::string GetParameter(std::string parName, TiXmlElement *e, TString defaultValue=PARAMETER_NOT_FOUND_STR)
Returns the value for the parameter named parName in the given section.
Int_t GetChar(std::string hint="Press a KEY to continue ...")
Helps to pause the program, printing a message before pausing.
Double_t StringToDouble(std::string in)
Gets a double from a string.
std::string ToUpper(std::string in)
Convert string to its upper case. Alternative of TString::ToUpper.
Int_t StringToInteger(std::string in)
Gets an integer from a string.
TVector3 StringTo3DVector(std::string in)
Gets a 3D-vector from a string. Format should be : (X,Y,Z).