730 #include "TRestGeant4Metadata.h"
733 #include <TGeoManager.h>
735 #include <TRestGDMLParser.h>
736 #include <TRestRun.h>
738 #include "TRestGeant4PrimaryGeneratorInfo.h"
741 using namespace TRestGeant4PrimaryGeneratorTypes;
796 fMagneticField = Get3DVectorParameterWithUnits(
"magneticField", TVector3(0, 0, 0));
804 cout <<
"\"gdmlFile\" parameter is not defined!" << endl;
811 cout <<
"Error downloading geometry file from URL: " <<
fGdmlFilename << endl;
819 if (
ToUpper(seedString) ==
"RANDOM" ||
ToUpper(seedString) ==
"RAND" ||
ToUpper(seedString) ==
"AUTO" ||
821 auto dd =
new double();
822 fSeed = (uintptr_t)dd + (uintptr_t)
this;
827 gRandom->SetSeed(
fSeed);
831 if ((((
string)
fGdmlFilename).find_first_not_of(
"./~") == 0 ||
841 Double_t defaultTime = 1. / REST_Units::s;
845 if (nEventsString == PARAMETER_NOT_FOUND_STR) {
850 const auto fNRequestedEntriesString =
GetParameter(
"nRequestedEntries");
852 fNRequestedEntriesString == PARAMETER_NOT_FOUND_STR ? 0 :
StringToInteger(fNRequestedEntriesString);
871 RESTWarning <<
"IMPORTANT: *maxTargetStepSize* parameter is now obsolete!" <<
RESTendl;
872 RESTWarning <<
"The sensitive volume will not define any integration step limit" <<
RESTendl;
874 RESTWarning <<
"In order to avoid this warning REMOVE the *maxTargetStepSize* definition,"
876 RESTWarning <<
"and replace it by the following statement at the <storage> section" <<
RESTendl;
878 RESTWarning <<
"<activeVolume name=\"" << this->
GetSensitiveVolume() <<
"\" maxStepSize=\""
881 RESTInfo <<
"Now, any active volume is allowed to define a maxStepSize" <<
RESTendl;
883 RESTInfo <<
"It is also possible to define a default step size for all active volumes," <<
RESTendl;
884 RESTInfo <<
"so that in case no step is defined, the default will be used." <<
RESTendl;
886 RESTInfo <<
"<storage sensitiveVolume=\"" << this->
GetSensitiveVolume() <<
"\" maxStepSize=\""
915 if (TRestGeant4PrimaryGeneratorTypes::StringToSpatialGeneratorTypes(
917 TRestGeant4PrimaryGeneratorTypes::SpatialGeneratorTypes::COSMIC) {
919 <<
"TRestGeant4Metadata::GetEquivalentSimulatedTime can only be called for 'cosmic' generator"
924 if (TRestGeant4PrimaryGeneratorTypes::StringToEnergyDistributionTypes(
925 source->GetEnergyDistributionType().Data()) !=
926 TRestGeant4PrimaryGeneratorTypes::EnergyDistributionTypes::FORMULA2) {
927 RESTError <<
"TRestGeant4Metadata::GetEquivalentSimulatedTime can only be called for 'formula2' "
928 "energy distribution"
932 if (TRestGeant4PrimaryGeneratorTypes::StringToAngularDistributionTypes(
933 source->GetAngularDistributionType().Data()) !=
934 TRestGeant4PrimaryGeneratorTypes::AngularDistributionTypes::FORMULA2) {
935 RESTError <<
"TRestGeant4Metadata::GetEquivalentSimulatedTime can only be called for 'formula' "
936 "angular distribution"
941 const auto energyRange = source->GetEnergyDistributionRange();
942 const auto angularRange = source->GetAngularDistributionRange();
943 auto function = (TF2*)source->GetEnergyAndAngularDistributionFunction()->Clone();
945 const auto countsPerSecondPerCm2 =
946 function->Integral(energyRange.X(), energyRange.Y(), angularRange.X(), angularRange.Y(), 1E-9);
947 return countsPerSecondPerCm2;
950 Double_t TRestGeant4Metadata::GetCosmicIntensityInCountsPerSecond()
const {
953 const auto countsPerSecond = countsPerSecondPerCm2 * surface;
954 return countsPerSecond;
957 Double_t TRestGeant4Metadata::GetEquivalentSimulatedTime()
const {
958 const auto countsPerSecond = GetCosmicIntensityInCountsPerSecond();
959 const auto seconds = double(
fNEvents) / countsPerSecond;
963 void TRestGeant4Metadata::ReadBiasing() {
964 TiXmlElement* biasingDefinition =
GetElement(
"biasing");
965 if (biasingDefinition ==
nullptr) {
969 TString biasEnabled =
GetFieldValue(
"value", biasingDefinition);
972 RESTDebug <<
"Bias: " << biasEnabled <<
RESTendl;
974 if (biasEnabled ==
"on" || biasEnabled ==
"ON" || biasEnabled ==
"On" || biasEnabled ==
"oN") {
975 RESTInfo <<
"Biasing is enabled" <<
RESTendl;
977 TiXmlElement* biasVolumeDefinition =
GetElement(
"biasingVolume", biasingDefinition);
979 while (biasVolumeDefinition) {
981 RESTDebug <<
"Def: " << biasVolumeDefinition <<
RESTendl;
983 biasVolume.SetBiasingVolumePosition(
984 Get3DVectorParameterWithUnits(
"position", biasVolumeDefinition));
986 biasVolume.SetBiasingVolumeSize(GetDblParameterWithUnits(
"size", biasVolumeDefinition));
987 biasVolume.SetEnergyRange(Get2DVectorParameterWithUnits(
"energyRange", biasVolumeDefinition));
988 biasVolume.SetBiasingVolumeType(biasType);
1036 TiXmlElement* generatorDefinition =
GetElement(
"generator");
1039 SpatialGeneratorTypesToString(StringToSpatialGeneratorTypes(
GetParameter(
1040 "type", generatorDefinition, SpatialGeneratorTypesToString(SpatialGeneratorTypes::VOLUME))));
1042 SpatialGeneratorShapesToString(StringToSpatialGeneratorShapes(
GetParameter(
1043 "shape", generatorDefinition, SpatialGeneratorShapesToString(SpatialGeneratorShapes::BOX))));
1047 SpatialGeneratorShapesToString(SpatialGeneratorShapes::GDML);
1050 Get3DVectorParameterWithUnits(
"size", generatorDefinition, {0, 0, 0});
1052 Get3DVectorParameterWithUnits(
"position", generatorDefinition, {0, 0, 0});
1054 Get3DVectorParameterWithUnits(
"rotationAxis", generatorDefinition, {0, 0, 1});
1056 GetDblParameterWithUnits(
"rotationAngle", generatorDefinition, 0);
1060 TiXmlElement* sourceDefinition =
GetElement(
"source", generatorDefinition);
1061 while (sourceDefinition) {
1062 string use =
GetParameter(
"use", sourceDefinition,
"");
1073 RESTError <<
"No sources are added inside generator!" <<
RESTendl;
1082 TiXmlElement* sourceDefinition = definition;
1084 source->SetParticleName(
GetParameter(
"particle", sourceDefinition));
1088 TString fullChain =
GetParameter(
"fullChain", sourceDefinition);
1090 if (fullChain.EqualTo(
"on", TString::ECaseCompare::kIgnoreCase)) {
1095 TiXmlElement* angularDefinition =
GetElement(
"angular", sourceDefinition);
1096 if (angularDefinition ==
nullptr) {
1097 angularDefinition =
GetElement(
"angularDist", sourceDefinition);
1100 "type", angularDefinition, AngularDistributionTypesToString(AngularDistributionTypes::FLUX)));
1101 if (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1102 AngularDistributionTypes::TH1D) {
1105 if (name ==
"NO_SUCH_PARA") {
1108 source->SetAngularDistributionNameInFile(name);
1110 source->SetAngularDistributionRange(
1111 Get2DVectorParameterWithUnits(
"range", angularDefinition, {0, TMath::Pi()}));
1112 if (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1113 AngularDistributionTypes::FORMULA) {
1114 source->SetAngularDistributionFormula(
GetParameter(
"name", angularDefinition));
1116 const auto function = source->GetAngularDistributionFunction();
1117 if (source->GetAngularDistributionRangeMin() <
function->GetXaxis()->GetXmin()) {
1118 source->SetAngularDistributionRange(
1119 {
function->GetXaxis()->GetXmin(), source->GetAngularDistributionRangeMax()});
1121 if (source->GetAngularDistributionRangeMax() >
function->GetXaxis()->GetXmax()) {
1122 source->SetAngularDistributionRange(
1123 {source->GetAngularDistributionRangeMin(),
function->GetXaxis()->GetXmax()});
1126 if ((StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1127 AngularDistributionTypes::FORMULA) ||
1128 (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1129 AngularDistributionTypes::FORMULA2)) {
1130 source->SetAngularDistributionFormulaNPoints(
static_cast<size_t>(GetDblParameterWithUnits(
1131 "nPoints", angularDefinition, source->GetAngularDistributionFormulaNPoints())));
1134 StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1135 AngularDistributionTypes::BACK_TO_BACK) {
1136 cout <<
"WARNING: First source cannot be backtoback. Setting it to isotropic" << endl;
1137 source->SetAngularDistributionType(
1138 AngularDistributionTypesToString(AngularDistributionTypes::ISOTROPIC));
1143 TiXmlElement* energyDefinition =
GetElement(
"energy", sourceDefinition);
1144 if (energyDefinition ==
nullptr) {
1145 energyDefinition =
GetElement(
"energyDist", sourceDefinition);
1148 "type", energyDefinition, EnergyDistributionTypesToString(EnergyDistributionTypes::MONO)));
1149 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1150 EnergyDistributionTypes::TH1D) {
1153 if (name ==
"NO_SUCH_PARA") {
1156 source->SetEnergyDistributionNameInFile(name);
1158 source->SetEnergyDistributionRange(Get2DVectorParameterWithUnits(
"range", energyDefinition, {0, 1E20}));
1159 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1160 EnergyDistributionTypes::MONO) {
1162 energy = GetDblParameterWithUnits(
"energy", energyDefinition, 0);
1163 source->SetEnergyDistributionRange({energy, energy});
1164 source->SetEnergy(energy);
1166 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1167 EnergyDistributionTypes::FORMULA) {
1168 source->SetEnergyDistributionFormula(
GetParameter(
"name", energyDefinition));
1170 const auto function = source->GetEnergyDistributionFunction();
1171 if (source->GetEnergyDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1172 source->SetEnergyDistributionRange(
1173 {
function->GetXaxis()->GetXmin(), source->GetEnergyDistributionRangeMax()});
1175 if (source->GetEnergyDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1176 source->SetEnergyDistributionRange(
1177 {source->GetEnergyDistributionRangeMin(), function->GetXaxis()->GetXmax()});
1180 if ((StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1181 EnergyDistributionTypes::FORMULA) ||
1182 (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1183 EnergyDistributionTypes::FORMULA2)) {
1184 source->SetEnergyDistributionFormulaNPoints(
static_cast<size_t>(GetDblParameterWithUnits(
1185 "nPoints", energyDefinition, source->GetEnergyDistributionFormulaNPoints())));
1187 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1188 EnergyDistributionTypes::FORMULA2 &&
1189 StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1190 AngularDistributionTypes::FORMULA2) {
1191 const auto empty = TString(
"");
1192 auto energyDistName =
GetParameter(
"name", energyDefinition, empty);
1193 auto angularDistName =
GetParameter(
"name", energyDefinition, empty);
1195 if (energyDistName == empty && angularDistName == empty) {
1196 RESTError <<
"No name specified for energy and angular distribution" <<
RESTendl;
1199 if (energyDistName == empty) {
1200 angularDistName = energyDistName;
1201 RESTWarning <<
"No name specified for energy distribution. Using angular distribution name: "
1204 if (angularDistName == empty) {
1205 energyDistName = energyDistName;
1206 RESTWarning <<
"No name specified for angular distribution. Using energy distribution name: "
1210 if (energyDistName == empty || angularDistName == empty) {
1212 RESTError <<
"When using 'formula2' the name of energy and angular dist must match" <<
RESTendl;
1215 const auto energyAndAngularDistName = energyDistName;
1216 source->SetEnergyAndAngularDistributionFormula(energyAndAngularDistName);
1218 const auto function = source->GetEnergyAndAngularDistributionFunction();
1221 if (source->GetEnergyDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1222 source->SetEnergyDistributionRange(
1223 {
function->GetXaxis()->GetXmin(), source->GetEnergyDistributionRangeMax()});
1225 if (source->GetEnergyDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1226 source->SetEnergyDistributionRange(
1227 {source->GetEnergyDistributionRangeMin(), function->GetXaxis()->GetXmax()});
1231 if (source->GetAngularDistributionRangeMin() < function->GetYaxis()->GetXmin()) {
1232 source->SetAngularDistributionRange(
1233 {
function->GetYaxis()->GetXmin(), source->GetAngularDistributionRangeMax()});
1235 if (source->GetAngularDistributionRangeMax() > function->GetYaxis()->GetXmax()) {
1236 source->SetAngularDistributionRange(
1237 {source->GetAngularDistributionRangeMin(), function->GetYaxis()->GetXmax()});
1271 RESTInfo <<
"TRestGeant4Metadata: Processing detector section" <<
RESTendl;
1272 TiXmlElement* detectorDefinition =
GetElement(
"detector");
1273 if (detectorDefinition ==
nullptr) {
1274 RESTError <<
"Detector section (<detector>) is not present in metadata!" <<
RESTendl;
1278 const bool activateAllVolumes =
1279 StringToBool(
GetParameter(
"activateAllVolumes", detectorDefinition,
"true"));
1283 TiXmlElement* removeUnwantedTracksDefinition =
GetElement(
"removeUnwantedTracks", detectorDefinition);
1284 if (removeUnwantedTracksDefinition !=
nullptr) {
1287 StringToBool(
GetParameter(
"keepZeroEnergyTracks", removeUnwantedTracksDefinition,
"false"));
1293 Double_t defaultStep = GetDblParameterWithUnits(
"maxStepSize", detectorDefinition);
1294 if (defaultStep < 0) {
1298 TiXmlElement* volumeDefinition =
GetElement(
"volume", detectorDefinition);
1299 while (volumeDefinition !=
nullptr) {
1301 if (name.empty() || name ==
"Not defined") {
1302 RESTError <<
"volume inside detector section defined without name" <<
RESTendl;
1305 vector<string> physicalVolumes;
1309 physicalVolumes.emplace_back(
1314 if (physicalVolumes.empty()) {
1315 for (
const auto& physical :
1317 physicalVolumes.emplace_back(
1321 if (physicalVolumes.empty()) {
1322 for (
const auto& logical :
fGeant4GeometryInfo.GetAllLogicalVolumesMatchingExpression(name)) {
1323 for (
const auto& physical :
1325 physicalVolumes.emplace_back(
1331 physicalVolumes.push_back(name);
1334 if (physicalVolumes.empty()) {
1336 <<
"volume '" << name
1337 <<
"' is not defined in the geometry. Could not match to a physical, logical volume or regex"
1342 bool isSensitive =
false;
1343 const string isSensitiveValue =
GetFieldValue(
"sensitive", volumeDefinition);
1344 if (isSensitiveValue !=
"Not defined") {
1345 isSensitive = StringToBool(isSensitiveValue);
1348 bool isKeepTracks = isSensitive;
1349 const string isKeepTracksValue =
GetFieldValue(
"keepTracks", volumeDefinition);
1350 if (isKeepTracksValue !=
"Not defined") {
1351 isKeepTracks = StringToBool(isKeepTracksValue);
1354 bool isKill =
false;
1355 const string isKillValue =
GetFieldValue(
"kill", volumeDefinition);
1356 if (isKillValue !=
"Not defined") {
1357 isKill = StringToBool(isKillValue);
1361 if (chance == -1 || chance < 0) {
1364 Double_t maxStep = GetDblParameterWithUnits(
"maxStepSize", volumeDefinition);
1366 maxStep = defaultStep;
1369 for (
const auto& physical : physicalVolumes) {
1370 RESTInfo <<
"Adding " << (isSensitive ?
"sensitive" :
"active") <<
" volume from RML: '"
1371 << physical << (chance != 1 ?
" with change: " + to_string(chance) :
" ") <<
RESTendl;
1380 fKillVolumes.insert(physical);
1387 cout <<
"No sensitive volumes defined in detector section. Adding 'gas' as sensitive volume" << endl;
1417 if (!IsActiveVolume(name)) {
1419 RESTInfo <<
"Automatically adding active volume: '" << name <<
"' with chance: " << 1
1426 RESTError <<
"No active volumes defined. Please check the detector section" <<
RESTendl;
1446 RESTMetadata <<
"Magnetic field: (" << mx <<
", " << my <<
", " << mz <<
") T" <<
RESTendl;
1449 RESTMetadata <<
"Register empty tracks was enabled" <<
RESTendl;
1451 RESTMetadata <<
"Register empty tracks was NOT enabled" <<
RESTendl;
1455 RESTMetadata <<
" ++++++++++ Generator +++++++++++ " <<
RESTendl;
1462 RESTMetadata <<
" ++++++++++ Detector +++++++++++ " <<
RESTendl;
1465 RESTMetadata <<
"Number of sensitive volumes: " << GetNumberOfSensitiveVolumes() <<
RESTendl;
1467 RESTMetadata <<
"Sensitive volume: " << sensitiveVolume <<
RESTendl;
1481 if (GetRemoveUnwantedTracks()) {
1482 RESTMetadata <<
"removeUnwantedTracks is enabled "
1484 <<
" keeping zero energy tracks" <<
RESTendl;
1494 RESTMetadata <<
"+++++" <<
RESTendl;
1524 if (name == activeVolumeName) {
1533 fActiveVolumesSet.insert(name.Data());
1555 RESTWarning <<
"TRestGeant4Metadata::GetStorageChance. Volume " << volume <<
" not found" <<
RESTendl;
1569 RESTWarning <<
"TRestGeant4Metadata::GetMaxStepSize. Volume " << volume <<
" not found" <<
RESTendl;
1574 size_t TRestGeant4Metadata::GetGeant4VersionMajor()
const {
1575 TString majorVersion =
"";
1583 return std::stoi(majorVersion.Data());
1598 fIsMerge = metadata.fIsMerge;
1624 fKillVolumes = metadata.fKillVolumes;
virtual void PrintMetadata() override
Implemented it in the derived metadata class to print out specific metadata information.
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).