727#include "TRestGeant4Metadata.h"
730#include <TGeoManager.h>
732#include <TRestGDMLParser.h>
735#include "TRestGeant4PrimaryGeneratorInfo.h"
738using namespace TRestGeant4PrimaryGeneratorTypes;
793 fMagneticField = Get3DVectorParameterWithUnits(
"magneticField", TVector3(0, 0, 0));
801 cout <<
"\"gdmlFile\" parameter is not defined!" << endl;
808 if (
ToUpper(seedString) ==
"RANDOM" ||
ToUpper(seedString) ==
"RAND" ||
ToUpper(seedString) ==
"AUTO" ||
810 auto dd =
new double();
811 fSeed = (uintptr_t)dd + (uintptr_t)
this;
816 gRandom->SetSeed(
fSeed);
820 if ((((
string)
fGdmlFilename).find_first_not_of(
"./~") == 0 ||
830 Double_t defaultTime = 1. / REST_Units::s;
834 if (nEventsString == PARAMETER_NOT_FOUND_STR) {
839 const auto fNRequestedEntriesString =
GetParameter(
"nRequestedEntries");
841 fNRequestedEntriesString == PARAMETER_NOT_FOUND_STR ? 0 :
StringToInteger(fNRequestedEntriesString);
860 RESTWarning <<
"IMPORTANT: *maxTargetStepSize* parameter is now obsolete!" <<
RESTendl;
861 RESTWarning <<
"The sensitive volume will not define any integration step limit" <<
RESTendl;
863 RESTWarning <<
"In order to avoid this warning REMOVE the *maxTargetStepSize* definition,"
865 RESTWarning <<
"and replace it by the following statement at the <storage> section" <<
RESTendl;
867 RESTWarning <<
"<activeVolume name=\"" << this->
GetSensitiveVolume() <<
"\" maxStepSize=\""
870 RESTInfo <<
"Now, any active volume is allowed to define a maxStepSize" <<
RESTendl;
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;
875 RESTInfo <<
"<storage sensitiveVolume=\"" << this->
GetSensitiveVolume() <<
"\" maxStepSize=\""
904 if (TRestGeant4PrimaryGeneratorTypes::StringToSpatialGeneratorTypes(
906 TRestGeant4PrimaryGeneratorTypes::SpatialGeneratorTypes::COSMIC) {
908 <<
"TRestGeant4Metadata::GetEquivalentSimulatedTime can only be called for 'cosmic' generator"
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"
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"
930 const auto energyRange = source->GetEnergyDistributionRange();
931 const auto angularRange = source->GetAngularDistributionRange();
932 auto function = (TF2*)source->GetEnergyAndAngularDistributionFunction()->Clone();
934 const auto countsPerSecondPerCm2 =
935 function->Integral(energyRange.X(), energyRange.Y(), angularRange.X(), angularRange.Y(), 1E-9);
936 return countsPerSecondPerCm2;
939Double_t TRestGeant4Metadata::GetCosmicIntensityInCountsPerSecond()
const {
942 const auto countsPerSecond = countsPerSecondPerCm2 * surface;
943 return countsPerSecond;
946Double_t TRestGeant4Metadata::GetEquivalentSimulatedTime()
const {
947 const auto countsPerSecond = GetCosmicIntensityInCountsPerSecond();
948 const auto seconds =
fNEvents / countsPerSecond;
952void TRestGeant4Metadata::ReadBiasing() {
953 TiXmlElement* biasingDefinition =
GetElement(
"biasing");
954 if (biasingDefinition ==
nullptr) {
958 TString biasEnabled =
GetFieldValue(
"value", biasingDefinition);
961 RESTDebug <<
"Bias: " << biasEnabled <<
RESTendl;
963 if (biasEnabled ==
"on" || biasEnabled ==
"ON" || biasEnabled ==
"On" || biasEnabled ==
"oN") {
964 RESTInfo <<
"Biasing is enabled" <<
RESTendl;
966 TiXmlElement* biasVolumeDefinition =
GetElement(
"biasingVolume", biasingDefinition);
968 while (biasVolumeDefinition) {
970 RESTDebug <<
"Def: " << biasVolumeDefinition <<
RESTendl;
972 biasVolume.SetBiasingVolumePosition(
973 Get3DVectorParameterWithUnits(
"position", biasVolumeDefinition));
975 biasVolume.SetBiasingVolumeSize(GetDblParameterWithUnits(
"size", biasVolumeDefinition));
976 biasVolume.SetEnergyRange(Get2DVectorParameterWithUnits(
"energyRange", biasVolumeDefinition));
977 biasVolume.SetBiasingVolumeType(biasType);
1025 TiXmlElement* generatorDefinition =
GetElement(
"generator");
1028 SpatialGeneratorTypesToString(StringToSpatialGeneratorTypes(
GetParameter(
1029 "type", generatorDefinition, SpatialGeneratorTypesToString(SpatialGeneratorTypes::VOLUME))));
1031 SpatialGeneratorShapesToString(StringToSpatialGeneratorShapes(
GetParameter(
1032 "shape", generatorDefinition, SpatialGeneratorShapesToString(SpatialGeneratorShapes::BOX))));
1036 SpatialGeneratorShapesToString(SpatialGeneratorShapes::GDML);
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);
1049 TiXmlElement* sourceDefinition =
GetElement(
"source", generatorDefinition);
1050 while (sourceDefinition) {
1051 string use =
GetParameter(
"use", sourceDefinition,
"");
1062 RESTError <<
"No sources are added inside generator!" <<
RESTendl;
1071 TiXmlElement* sourceDefinition = definition;
1073 source->SetParticleName(
GetParameter(
"particle", sourceDefinition));
1077 TString fullChain =
GetParameter(
"fullChain", sourceDefinition);
1079 if (fullChain.EqualTo(
"on", TString::ECaseCompare::kIgnoreCase)) {
1084 TiXmlElement* angularDefinition =
GetElement(
"angular", sourceDefinition);
1085 if (angularDefinition ==
nullptr) {
1086 angularDefinition =
GetElement(
"angularDist", sourceDefinition);
1089 "type", angularDefinition, AngularDistributionTypesToString(AngularDistributionTypes::FLUX)));
1090 if (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1091 AngularDistributionTypes::TH1D) {
1094 if (name ==
"NO_SUCH_PARA") {
1097 source->SetAngularDistributionNameInFile(name);
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));
1105 const auto function = source->GetAngularDistributionFunction();
1106 if (source->GetAngularDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1107 source->SetAngularDistributionRange(
1108 {function->GetXaxis()->GetXmin(), source->GetAngularDistributionRangeMax()});
1110 if (source->GetAngularDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1111 source->SetAngularDistributionRange(
1112 {source->GetAngularDistributionRangeMin(), function->GetXaxis()->GetXmax()});
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())));
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));
1132 TiXmlElement* energyDefinition =
GetElement(
"energy", sourceDefinition);
1133 if (energyDefinition ==
nullptr) {
1134 energyDefinition =
GetElement(
"energyDist", sourceDefinition);
1137 "type", energyDefinition, EnergyDistributionTypesToString(EnergyDistributionTypes::MONO)));
1138 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1139 EnergyDistributionTypes::TH1D) {
1142 if (name ==
"NO_SUCH_PARA") {
1145 source->SetEnergyDistributionNameInFile(name);
1147 source->SetEnergyDistributionRange(Get2DVectorParameterWithUnits(
"range", energyDefinition, {0, 1E20}));
1148 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1149 EnergyDistributionTypes::MONO) {
1151 energy = GetDblParameterWithUnits(
"energy", energyDefinition, 0);
1152 source->SetEnergyDistributionRange({energy, energy});
1153 source->SetEnergy(energy);
1155 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1156 EnergyDistributionTypes::FORMULA) {
1157 source->SetEnergyDistributionFormula(
GetParameter(
"name", energyDefinition));
1159 const auto function = source->GetEnergyDistributionFunction();
1160 if (source->GetEnergyDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1161 source->SetEnergyDistributionRange(
1162 {function->GetXaxis()->GetXmin(), source->GetEnergyDistributionRangeMax()});
1164 if (source->GetEnergyDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1165 source->SetEnergyDistributionRange(
1166 {source->GetEnergyDistributionRangeMin(), function->GetXaxis()->GetXmax()});
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())));
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);
1184 if (energyDistName == empty && angularDistName == empty) {
1185 RESTError <<
"No name specified for energy and angular distribution" <<
RESTendl;
1188 if (energyDistName == empty) {
1189 angularDistName = energyDistName;
1190 RESTWarning <<
"No name specified for energy distribution. Using angular distribution name: "
1193 if (angularDistName == empty) {
1194 energyDistName = energyDistName;
1195 RESTWarning <<
"No name specified for angular distribution. Using energy distribution name: "
1199 if (energyDistName == empty || angularDistName == empty) {
1201 RESTError <<
"When using 'formula2' the name of energy and angular dist must match" <<
RESTendl;
1204 const auto energyAndAngularDistName = energyDistName;
1205 source->SetEnergyAndAngularDistributionFormula(energyAndAngularDistName);
1207 const auto function = source->GetEnergyAndAngularDistributionFunction();
1210 if (source->GetEnergyDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1211 source->SetEnergyDistributionRange(
1212 {function->GetXaxis()->GetXmin(), source->GetEnergyDistributionRangeMax()});
1214 if (source->GetEnergyDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1215 source->SetEnergyDistributionRange(
1216 {source->GetEnergyDistributionRangeMin(), function->GetXaxis()->GetXmax()});
1220 if (source->GetAngularDistributionRangeMin() < function->GetYaxis()->GetXmin()) {
1221 source->SetAngularDistributionRange(
1222 {function->GetYaxis()->GetXmin(), source->GetAngularDistributionRangeMax()});
1224 if (source->GetAngularDistributionRangeMax() > function->GetYaxis()->GetXmax()) {
1225 source->SetAngularDistributionRange(
1226 {source->GetAngularDistributionRangeMin(), function->GetYaxis()->GetXmax()});
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;
1267 const bool activateAllVolumes =
1268 StringToBool(
GetParameter(
"activateAllVolumes", detectorDefinition,
"true"));
1272 TiXmlElement* removeUnwantedTracksDefinition =
GetElement(
"removeUnwantedTracks", detectorDefinition);
1273 if (removeUnwantedTracksDefinition !=
nullptr) {
1276 StringToBool(
GetParameter(
"keepZeroEnergyTracks", removeUnwantedTracksDefinition,
"false"));
1282 Double_t defaultStep = GetDblParameterWithUnits(
"maxStepSize", detectorDefinition);
1283 if (defaultStep < 0) {
1287 TiXmlElement* volumeDefinition =
GetElement(
"volume", detectorDefinition);
1288 while (volumeDefinition !=
nullptr) {
1290 if (name.empty() || name ==
"Not defined") {
1291 RESTError <<
"volume inside detector section defined without name" <<
RESTendl;
1294 vector<string> physicalVolumes;
1298 physicalVolumes.emplace_back(
1303 if (physicalVolumes.empty()) {
1304 for (
const auto& physical :
1306 physicalVolumes.emplace_back(
1310 if (physicalVolumes.empty()) {
1311 for (
const auto& logical :
fGeant4GeometryInfo.GetAllLogicalVolumesMatchingExpression(name)) {
1312 for (
const auto& physical :
1314 physicalVolumes.emplace_back(
1320 physicalVolumes.push_back(name);
1323 if (physicalVolumes.empty()) {
1325 <<
"volume '" << name
1326 <<
"' is not defined in the geometry. Could not match to a physical, logical volume or regex"
1331 bool isSensitive =
false;
1332 const string isSensitiveValue =
GetFieldValue(
"sensitive", volumeDefinition);
1333 if (isSensitiveValue !=
"Not defined") {
1334 isSensitive = StringToBool(isSensitiveValue);
1337 bool isKeepTracks = isSensitive;
1338 const string isKeepTracksValue =
GetFieldValue(
"keepTracks", volumeDefinition);
1339 if (isKeepTracksValue !=
"Not defined") {
1340 isKeepTracks = StringToBool(isKeepTracksValue);
1343 bool isKill =
false;
1344 const string isKillValue =
GetFieldValue(
"kill", volumeDefinition);
1345 if (isKillValue !=
"Not defined") {
1346 isKill = StringToBool(isKillValue);
1350 if (chance == -1 || chance < 0) {
1353 Double_t maxStep = GetDblParameterWithUnits(
"maxStepSize", volumeDefinition);
1355 maxStep = defaultStep;
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;
1369 fKillVolumes.insert(physical);
1376 cout <<
"No sensitive volumes defined in detector section. Adding 'gas' as sensitive volume" << endl;
1406 if (!IsActiveVolume(name)) {
1408 RESTInfo <<
"Automatically adding active volume: '" << name <<
"' with chance: " << 1
1415 RESTError <<
"No active volumes defined. Please check the detector section" <<
RESTendl;
1435 RESTMetadata <<
"Magnetic field: (" << mx <<
", " << my <<
", " << mz <<
") T" <<
RESTendl;
1438 RESTMetadata <<
"Register empty tracks was enabled" <<
RESTendl;
1440 RESTMetadata <<
"Register empty tracks was NOT enabled" <<
RESTendl;
1444 RESTMetadata <<
" ++++++++++ Generator +++++++++++ " <<
RESTendl;
1451 RESTMetadata <<
" ++++++++++ Detector +++++++++++ " <<
RESTendl;
1454 RESTMetadata <<
"Number of sensitive volumes: " << GetNumberOfSensitiveVolumes() <<
RESTendl;
1456 RESTMetadata <<
"Sensitive volume: " << sensitiveVolume <<
RESTendl;
1470 if (GetRemoveUnwantedTracks()) {
1471 RESTMetadata <<
"removeUnwantedTracks is enabled "
1473 <<
" keeping zero energy tracks" <<
RESTendl;
1483 RESTMetadata <<
"+++++" <<
RESTendl;
1513 if (name == activeVolumeName) {
1522 fActiveVolumesSet.insert(name.Data());
1544 RESTWarning <<
"TRestGeant4Metadata::GetStorageChance. Volume " << volume <<
" not found" <<
RESTendl;
1558 RESTWarning <<
"TRestGeant4Metadata::GetMaxStepSize. Volume " << volume <<
" not found" <<
RESTendl;
1563size_t TRestGeant4Metadata::GetGeant4VersionMajor()
const {
1564 TString majorVersion =
"";
1572 return std::stoi(majorVersion.Data());
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)
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).