735#include "TRestGeant4Metadata.h"
738#include <TGeoManager.h>
739#include <TObjString.h>
741#include <TRestGDMLParser.h>
744#include "TRestGeant4ParticleSourceCosmics.h"
745#include "TRestGeant4PrimaryGeneratorInfo.h"
748using namespace TRestGeant4PrimaryGeneratorTypes;
803 fMagneticField = Get3DVectorParameterWithUnits(
"magneticField", TVector3(0, 0, 0));
811 cout <<
"\"gdmlFile\" parameter is not defined!" << endl;
818 cout <<
"Error downloading geometry file from URL: " <<
fGdmlFilename << endl;
828 if (
ToUpper(seedString) ==
"RANDOM" ||
ToUpper(seedString) ==
"RAND" ||
ToUpper(seedString) ==
"AUTO" ||
830 auto dd =
new double();
831 fSeed = (uintptr_t)dd + (uintptr_t)
this;
836 gRandom->SetSeed(
fSeed);
840 if ((((
string)
fGdmlFilename).find_first_not_of(
"./~") == 0 ||
850 Double_t defaultTime = 1. / REST_Units::s;
854 if (nEventsString == PARAMETER_NOT_FOUND_STR) {
862 const auto fNRequestedEntriesString =
GetParameter(
"nRequestedEntries");
864 fNRequestedEntriesString == PARAMETER_NOT_FOUND_STR ? 0 :
StringToInteger(fNRequestedEntriesString);
883 RESTWarning <<
"IMPORTANT: *maxTargetStepSize* parameter is now obsolete!" <<
RESTendl;
884 RESTWarning <<
"The sensitive volume will not define any integration step limit" <<
RESTendl;
886 RESTWarning <<
"In order to avoid this warning REMOVE the *maxTargetStepSize* definition,"
888 RESTWarning <<
"and replace it by the following statement at the <storage> section" <<
RESTendl;
890 RESTWarning <<
"<activeVolume name=\"" << this->
GetSensitiveVolume() <<
"\" maxStepSize=\""
893 RESTInfo <<
"Now, any active volume is allowed to define a maxStepSize" <<
RESTendl;
895 RESTInfo <<
"It is also possible to define a default step size for all active volumes," <<
RESTendl;
896 RESTInfo <<
"so that in case no step is defined, the default will be used." <<
RESTendl;
898 RESTInfo <<
"<storage sensitiveVolume=\"" << this->
GetSensitiveVolume() <<
"\" maxStepSize=\""
929 double countsPerSecondPerCm2 = 0;
930 if (TRestGeant4PrimaryGeneratorTypes::StringToEnergyDistributionTypes(
931 source->GetEnergyDistributionType().Data()) ==
932 TRestGeant4PrimaryGeneratorTypes::EnergyDistributionTypes::FORMULA2 &&
933 TRestGeant4PrimaryGeneratorTypes::StringToAngularDistributionTypes(
934 source->GetAngularDistributionType().Data()) ==
935 TRestGeant4PrimaryGeneratorTypes::AngularDistributionTypes::FORMULA2) {
936 const auto energyRange = source->GetEnergyDistributionRange();
937 const auto angularRange = source->GetAngularDistributionRange();
938 auto function = (TF2*)source->GetEnergyAndAngularDistributionFunction()->Clone();
940 countsPerSecondPerCm2 =
941 function->Integral(energyRange.X(), energyRange.Y(), angularRange.X(), angularRange.Y(), 1E-9);
944 else if (std::string(source->GetName()) ==
"TRestGeant4ParticleSourceCosmics") {
946 const auto names = cosmicSource->GetParticleNames();
947 const auto histograms = cosmicSource->GetHistogramsTransformed();
948 for (
const auto& name : names) {
949 countsPerSecondPerCm2 += histograms.at(name)->Integral();
951 }
else if (TRestGeant4PrimaryGeneratorTypes::StringToEnergyDistributionTypes(
952 source->GetEnergyDistributionType().Data()) ==
953 TRestGeant4PrimaryGeneratorTypes::EnergyDistributionTypes::TH2D &&
954 TRestGeant4PrimaryGeneratorTypes::StringToAngularDistributionTypes(
955 source->GetAngularDistributionType().Data()) ==
956 TRestGeant4PrimaryGeneratorTypes::AngularDistributionTypes::TH2D) {
957 const auto filename = source->GetEnergyDistributionFilename();
958 const auto name = source->GetEnergyDistributionNameInFile();
959 TFile* file = TFile::Open(filename);
960 auto energyAndAngularDistributionHistogram =
961 file->Get<TH2D>(name);
962 if (energyAndAngularDistributionHistogram ==
nullptr) {
963 throw std::runtime_error(
"Histogram not found in file");
965 countsPerSecondPerCm2 = energyAndAngularDistributionHistogram->Integral();
971 throw std::runtime_error(
"Cosmic flux calculation is only supported for TFormula2 or TH2D sources");
974 return countsPerSecondPerCm2;
977Double_t TRestGeant4Metadata::GetCosmicIntensityInCountsPerSecond()
const {
979 const auto surface = GetGeneratorSurfaceCm2();
980 const auto countsPerSecond = countsPerSecondPerCm2 * surface;
981 return countsPerSecond;
987 double scalingFactor = 1.0;
988 if (type ==
"cosmic") {
991 if (cosmicSource !=
nullptr) {
994 ->GetEnergyRangeScalingFactor();
995 if (scalingFactor < 0 || scalingFactor > 1) {
996 throw std::runtime_error(
"Energy range scaling factor must be between 0 and 1");
1002 const auto countsPerSecond = GetCosmicIntensityInCountsPerSecond() * scalingFactor;
1003 const auto seconds = double(
fNEvents) / countsPerSecond;
1008void TRestGeant4Metadata::ReadBiasing() {
1009 TiXmlElement* biasingDefinition =
GetElement(
"biasing");
1010 if (biasingDefinition ==
nullptr) {
1014 TString biasEnabled =
GetFieldValue(
"value", biasingDefinition);
1015 TString biasType =
GetFieldValue(
"type", biasingDefinition);
1017 RESTDebug <<
"Bias: " << biasEnabled <<
RESTendl;
1019 if (biasEnabled ==
"on" || biasEnabled ==
"ON" || biasEnabled ==
"On" || biasEnabled ==
"oN") {
1020 RESTInfo <<
"Biasing is enabled" <<
RESTendl;
1022 TiXmlElement* biasVolumeDefinition =
GetElement(
"biasingVolume", biasingDefinition);
1024 while (biasVolumeDefinition) {
1026 RESTDebug <<
"Def: " << biasVolumeDefinition <<
RESTendl;
1028 biasVolume.SetBiasingVolumePosition(
1029 Get3DVectorParameterWithUnits(
"position", biasVolumeDefinition));
1031 biasVolume.SetBiasingVolumeSize(GetDblParameterWithUnits(
"size", biasVolumeDefinition));
1032 biasVolume.SetEnergyRange(Get2DVectorParameterWithUnits(
"energyRange", biasVolumeDefinition));
1033 biasVolume.SetBiasingVolumeType(biasType);
1081 TiXmlElement* generatorDefinition =
GetElement(
"generator");
1084 SpatialGeneratorTypesToString(StringToSpatialGeneratorTypes(
GetParameter(
1085 "type", generatorDefinition, SpatialGeneratorTypesToString(SpatialGeneratorTypes::VOLUME))));
1087 SpatialGeneratorShapesToString(StringToSpatialGeneratorShapes(
GetParameter(
1088 "shape", generatorDefinition, SpatialGeneratorShapesToString(SpatialGeneratorShapes::BOX))));
1092 SpatialGeneratorShapesToString(SpatialGeneratorShapes::GDML);
1095 Get3DVectorParameterWithUnits(
"size", generatorDefinition, {0, 0, 0});
1097 Get3DVectorParameterWithUnits(
"position", generatorDefinition, {0, 0, 0});
1099 Get3DVectorParameterWithUnits(
"rotationAxis", generatorDefinition, {0, 0, 1});
1101 GetDblParameterWithUnits(
"rotationAngle", generatorDefinition, 0);
1105 TiXmlElement* sourceDefinition =
GetElement(
"source", generatorDefinition);
1106 while (sourceDefinition) {
1107 string use =
GetParameter(
"use", sourceDefinition,
"");
1113 if (
string(source->GetName()) ==
"TRestGeant4ParticleSourceCosmics") {
1114 TRestGeant4ParticleSourceCosmics::SetSeed(
GetSeed());
1122 RESTError <<
"No sources are added inside generator!" <<
RESTendl;
1131 TiXmlElement* sourceDefinition = definition;
1133 source->SetParticleName(
GetParameter(
"particle", sourceDefinition));
1137 TString fullChain =
GetParameter(
"fullChain", sourceDefinition);
1139 if (fullChain.EqualTo(
"on", TString::ECaseCompare::kIgnoreCase)) {
1143 const TString fullChainStopIsotopesString =
GetParameter(
"fullChainStopIsotopes", sourceDefinition,
"");
1144 if (fullChainStopIsotopesString !=
"") {
1145 TObjArray* fullChainStopIsotopesArray = fullChainStopIsotopesString.Tokenize(
",");
1146 for (
int i = 0; i < fullChainStopIsotopesArray->GetEntries(); i++) {
1147 TString isotope = ((TObjString*)fullChainStopIsotopesArray->At(i))->String();
1153 TiXmlElement* angularDefinition =
GetElement(
"angular", sourceDefinition);
1154 if (angularDefinition ==
nullptr) {
1155 angularDefinition =
GetElement(
"angularDist", sourceDefinition);
1158 "type", angularDefinition, AngularDistributionTypesToString(AngularDistributionTypes::FLUX)));
1159 if ((StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1160 AngularDistributionTypes::TH1D) ||
1161 (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1162 AngularDistributionTypes::TH2D)) {
1165 if (name ==
"NO_SUCH_PARA") {
1168 source->SetAngularDistributionNameInFile(name);
1170 source->SetAngularDistributionRange(
1171 Get2DVectorParameterWithUnits(
"range", angularDefinition, {0, TMath::Pi()}));
1172 if (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1173 AngularDistributionTypes::FORMULA) {
1174 source->SetAngularDistributionFormula(
GetParameter(
"name", angularDefinition));
1176 const auto function = source->GetAngularDistributionFunction();
1177 if (source->GetAngularDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1178 source->SetAngularDistributionRange(
1179 {function->GetXaxis()->GetXmin(), source->GetAngularDistributionRangeMax()});
1181 if (source->GetAngularDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1182 source->SetAngularDistributionRange(
1183 {source->GetAngularDistributionRangeMin(), function->GetXaxis()->GetXmax()});
1186 if ((StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1187 AngularDistributionTypes::FORMULA) ||
1188 (StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1189 AngularDistributionTypes::FORMULA2)) {
1190 source->SetAngularDistributionFormulaNPoints(
static_cast<size_t>(GetDblParameterWithUnits(
1191 "nPoints", angularDefinition, source->GetAngularDistributionFormulaNPoints())));
1194 StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1195 AngularDistributionTypes::BACK_TO_BACK) {
1196 cout <<
"WARNING: First source cannot be backtoback. Setting it to isotropic" << endl;
1197 source->SetAngularDistributionType(
1198 AngularDistributionTypesToString(AngularDistributionTypes::ISOTROPIC));
1202 if ((StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1203 AngularDistributionTypes::ISOTROPIC)) {
1204 source->SetAngularDistributionRange({0, TMath::Pi()});
1205 const double coneHalfAngle = GetDblParameterWithUnits(
"coneHalfAngle", angularDefinition, 0);
1206 source->SetAngularDistributionIsotropicConeHalfAngle(coneHalfAngle);
1209 TiXmlElement* energyDefinition =
GetElement(
"energy", sourceDefinition);
1210 if (energyDefinition ==
nullptr) {
1211 energyDefinition =
GetElement(
"energyDist", sourceDefinition);
1214 "type", energyDefinition, EnergyDistributionTypesToString(EnergyDistributionTypes::MONO)));
1215 if ((StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1216 EnergyDistributionTypes::TH1D) ||
1217 (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1218 EnergyDistributionTypes::TH2D)) {
1221 if (name ==
"NO_SUCH_PARA") {
1224 source->SetEnergyDistributionNameInFile(name);
1226 source->SetEnergyDistributionRange(Get2DVectorParameterWithUnits(
"range", energyDefinition, {0, 1E20}));
1227 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1228 EnergyDistributionTypes::MONO) {
1230 energy = GetDblParameterWithUnits(
"energy", energyDefinition, 0);
1231 source->SetEnergyDistributionRange({energy, energy});
1232 source->SetEnergy(energy);
1234 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1235 EnergyDistributionTypes::FORMULA) {
1236 source->SetEnergyDistributionFormula(
GetParameter(
"name", energyDefinition));
1238 const auto function = source->GetEnergyDistributionFunction();
1239 if (source->GetEnergyDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1240 source->SetEnergyDistributionRange(
1241 {function->GetXaxis()->GetXmin(), source->GetEnergyDistributionRangeMax()});
1243 if (source->GetEnergyDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1244 source->SetEnergyDistributionRange(
1245 {source->GetEnergyDistributionRangeMin(), function->GetXaxis()->GetXmax()});
1248 if ((StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1249 EnergyDistributionTypes::FORMULA) ||
1250 (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1251 EnergyDistributionTypes::FORMULA2)) {
1252 source->SetEnergyDistributionFormulaNPoints(
static_cast<size_t>(GetDblParameterWithUnits(
1253 "nPoints", energyDefinition, source->GetEnergyDistributionFormulaNPoints())));
1255 if (StringToEnergyDistributionTypes(source->GetEnergyDistributionType().Data()) ==
1256 EnergyDistributionTypes::FORMULA2 &&
1257 StringToAngularDistributionTypes(source->GetAngularDistributionType().Data()) ==
1258 AngularDistributionTypes::FORMULA2) {
1259 const auto empty = TString(
"");
1260 auto energyDistName =
GetParameter(
"name", energyDefinition, empty);
1261 auto angularDistName =
GetParameter(
"name", energyDefinition, empty);
1263 if (energyDistName == empty && angularDistName == empty) {
1264 RESTError <<
"No name specified for energy and angular distribution" <<
RESTendl;
1267 if (energyDistName == empty) {
1268 angularDistName = energyDistName;
1269 RESTWarning <<
"No name specified for energy distribution. Using angular distribution name: "
1272 if (angularDistName == empty) {
1273 energyDistName = energyDistName;
1274 RESTWarning <<
"No name specified for angular distribution. Using energy distribution name: "
1278 if (energyDistName == empty || angularDistName == empty) {
1280 RESTError <<
"When using 'formula2' the name of energy and angular dist must match" <<
RESTendl;
1283 const auto energyAndAngularDistName = energyDistName;
1284 source->SetEnergyAndAngularDistributionFormula(energyAndAngularDistName);
1286 const auto function = source->GetEnergyAndAngularDistributionFunction();
1289 if (source->GetEnergyDistributionRangeMin() < function->GetXaxis()->GetXmin()) {
1290 source->SetEnergyDistributionRange(
1291 {function->GetXaxis()->GetXmin(), source->GetEnergyDistributionRangeMax()});
1293 if (source->GetEnergyDistributionRangeMax() > function->GetXaxis()->GetXmax()) {
1294 source->SetEnergyDistributionRange(
1295 {source->GetEnergyDistributionRangeMin(), function->GetXaxis()->GetXmax()});
1299 if (source->GetAngularDistributionRangeMin() < function->GetYaxis()->GetXmin()) {
1300 source->SetAngularDistributionRange(
1301 {function->GetYaxis()->GetXmin(), source->GetAngularDistributionRangeMax()});
1303 if (source->GetAngularDistributionRangeMax() > function->GetYaxis()->GetXmax()) {
1304 source->SetAngularDistributionRange(
1305 {source->GetAngularDistributionRangeMin(), function->GetYaxis()->GetXmax()});
1339 RESTInfo <<
"TRestGeant4Metadata: Processing detector section" <<
RESTendl;
1340 TiXmlElement* detectorDefinition =
GetElement(
"detector");
1341 if (detectorDefinition ==
nullptr) {
1342 RESTError <<
"Detector section (<detector>) is not present in metadata!" <<
RESTendl;
1346 const bool activateAllVolumes =
1347 StringToBool(
GetParameter(
"activateAllVolumes", detectorDefinition,
"true"));
1351 TiXmlElement* removeUnwantedTracksDefinition =
GetElement(
"removeUnwantedTracks", detectorDefinition);
1352 if (removeUnwantedTracksDefinition !=
nullptr) {
1355 StringToBool(
GetParameter(
"keepZeroEnergyTracks", removeUnwantedTracksDefinition,
"false"));
1361 Double_t defaultStep = GetDblParameterWithUnits(
"maxStepSize", detectorDefinition);
1362 if (defaultStep < 0) {
1366 TiXmlElement* volumeDefinition =
GetElement(
"volume", detectorDefinition);
1367 while (volumeDefinition !=
nullptr) {
1369 if (name.empty() || name ==
"Not defined") {
1370 RESTError <<
"volume inside detector section defined without name" <<
RESTendl;
1373 vector<string> physicalVolumes;
1377 physicalVolumes.emplace_back(
1382 if (physicalVolumes.empty()) {
1383 for (
const auto& physical :
1385 physicalVolumes.emplace_back(
1389 if (physicalVolumes.empty()) {
1390 for (
const auto& logical :
fGeant4GeometryInfo.GetAllLogicalVolumesMatchingExpression(name)) {
1391 for (
const auto& physical :
1393 physicalVolumes.emplace_back(
1399 physicalVolumes.push_back(name);
1402 if (physicalVolumes.empty()) {
1404 <<
"volume '" << name
1405 <<
"' is not defined in the geometry. Could not match to a physical, logical volume or regex"
1410 bool isSensitive =
false;
1411 const string isSensitiveValue =
GetFieldValue(
"sensitive", volumeDefinition);
1412 if (isSensitiveValue !=
"Not defined") {
1413 isSensitive = StringToBool(isSensitiveValue);
1416 bool isKeepTracks = isSensitive;
1417 const string isKeepTracksValue =
GetFieldValue(
"keepTracks", volumeDefinition);
1418 if (isKeepTracksValue !=
"Not defined") {
1419 isKeepTracks = StringToBool(isKeepTracksValue);
1422 bool isKill =
false;
1423 const string isKillValue =
GetFieldValue(
"kill", volumeDefinition);
1424 if (isKillValue !=
"Not defined") {
1425 isKill = StringToBool(isKillValue);
1429 if (chance == -1 || chance < 0) {
1432 Double_t maxStep = GetDblParameterWithUnits(
"maxStepSize", volumeDefinition);
1434 maxStep = defaultStep;
1437 for (
const auto& physical : physicalVolumes) {
1438 RESTInfo <<
"Adding " << (isSensitive ?
"sensitive" :
"active") <<
" volume from RML: '"
1439 << physical << (chance != 1 ?
" with change: " + to_string(chance) :
" ") <<
RESTendl;
1448 fKillVolumes.insert(physical);
1455 cout <<
"No sensitive volumes defined in detector section. Adding 'gas' as sensitive volume" << endl;
1485 if (!IsActiveVolume(name)) {
1487 RESTInfo <<
"Automatically adding active volume: '" << name <<
"' with chance: " << 1
1494 RESTError <<
"No active volumes defined. Please check the detector section" <<
RESTendl;
1514 RESTMetadata <<
"Magnetic field: (" << mx <<
", " << my <<
", " << mz <<
") T" <<
RESTendl;
1517 RESTMetadata <<
"Register empty tracks was enabled" <<
RESTendl;
1519 RESTMetadata <<
"Register empty tracks was NOT enabled" <<
RESTendl;
1523 RESTMetadata <<
" ++++++++++ Generator +++++++++++ " <<
RESTendl;
1530 RESTMetadata <<
" ++++++++++ Detector +++++++++++ " <<
RESTendl;
1533 RESTMetadata <<
"Number of sensitive volumes: " << GetNumberOfSensitiveVolumes() <<
RESTendl;
1535 RESTMetadata <<
"Sensitive volume: " << sensitiveVolume <<
RESTendl;
1549 if (GetRemoveUnwantedTracks()) {
1550 RESTMetadata <<
"removeUnwantedTracks is enabled "
1552 <<
" keeping zero energy tracks" <<
RESTendl;
1562 RESTMetadata <<
"+++++" <<
RESTendl;
1592 if (name == activeVolumeName) {
1601 fActiveVolumesSet.insert(name.Data());
1604double TRestGeant4Metadata::GetGeneratorSurfaceCm2()
const {
1608 if (type ==
"surface" && shape ==
"circle") {
1610 return TMath::Pi() * radius * radius * 0.01;
1611 }
else if (type ==
"cosmic") {
1615 throw std::runtime_error(
1616 "TRestGeant4Metadata::GetGeneratorSurfaceCm2: Can only be called for 'cosmic' and 'surface/circle' "
1645 RESTWarning <<
"TRestGeant4Metadata::GetStorageChance. Volume " << volume <<
" not found" <<
RESTendl;
1659 RESTWarning <<
"TRestGeant4Metadata::GetMaxStepSize. Volume " << volume <<
" not found" <<
RESTendl;
1664size_t TRestGeant4Metadata::GetGeant4VersionMajor()
const {
1665 TString majorVersion =
"";
1673 return std::stoi(majorVersion.Data());
1690 fIsMerge = metadata.fIsMerge;
1717 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...
TVector3 GetSpatialGeneratorSize() const
Returns the main spatial dimension of virtual generator. It is the size of a virtualBox.
TString GetSpatialGeneratorShape() const
Returns a std::string specifying the generator shape (point, wall, box, etc )
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.
std::string ToLower(std::string in)
Convert string to its lower case. Alternative of TString::ToLower.
TVector3 StringTo3DVector(std::string in)
Gets a 3D-vector from a string. Format should be : (X,Y,Z).