File indexing completed on 2025-01-18 09:14:26
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #include <DD4hep/Printout.h>
0016 #include <DD4hep/InstanceCount.h>
0017 #include <DDG4/Geant4Random.h>
0018 #include <DDG4/Geant4IsotropeGenerator.h>
0019
0020 using namespace dd4hep::sim;
0021
0022
0023 Geant4IsotropeGenerator::Geant4IsotropeGenerator(Geant4Context* ctxt, const std::string& nam)
0024 : Geant4ParticleGenerator(ctxt, nam)
0025 {
0026 InstanceCount::increment(this);
0027 declareProperty("PhiMin", m_phiMin = 0.0);
0028 declareProperty("PhiMax", m_phiMax = 2.0*M_PI);
0029 declareProperty("ThetaMin", m_thetaMin = 0.0);
0030 declareProperty("ThetaMax", m_thetaMax = M_PI);
0031 declareProperty("Distribution", m_distribution = "uniform" );
0032 }
0033
0034
0035 Geant4IsotropeGenerator::~Geant4IsotropeGenerator() {
0036 InstanceCount::decrement(this);
0037 }
0038
0039
0040 void Geant4IsotropeGenerator::getParticleDirectionUniform(int, ROOT::Math::XYZVector& direction, double& momentum) const {
0041 Geant4Event& evt = context()->event();
0042 Geant4Random& rnd = evt.random();
0043 double phi = m_phiMin+(m_phiMax-m_phiMin)*rnd.rndm();
0044 double theta = m_thetaMin+(m_thetaMax-m_thetaMin)*rnd.rndm();
0045 double x1 = std::sin(theta)*std::cos(phi);
0046 double x2 = std::sin(theta)*std::sin(phi);
0047 double x3 = std::cos(theta);
0048
0049 direction.SetXYZ(x1,x2,x3);
0050 getParticleMomentumUniform(momentum);
0051 }
0052
0053
0054 void Geant4IsotropeGenerator::getParticleDirectionCosTheta(int, ROOT::Math::XYZVector& direction, double& momentum) const {
0055 Geant4Event& evt = context()->event();
0056 Geant4Random& rnd = evt.random();
0057 double phi = m_phiMin+(m_phiMax-m_phiMin)*rnd.rndm();
0058 double cos_theta = std::cos(m_thetaMin)+(std::cos(m_thetaMax)-std::cos(m_thetaMin))*rnd.rndm();
0059 double sin_theta = std::sqrt(1.0-cos_theta*cos_theta);
0060 double x1 = sin_theta*std::cos(phi);
0061 double x2 = sin_theta*std::sin(phi);
0062 double x3 = cos_theta;
0063
0064 direction.SetXYZ(x1,x2,x3);
0065 getParticleMomentumUniform(momentum);
0066 }
0067
0068
0069 void Geant4IsotropeGenerator::getParticleDirectionEta(int, ROOT::Math::XYZVector& direction, double& momentum) const {
0070 struct Distribution {
0071 static double eta(double x) { return -1.0*std::log(std::tan(x/2.0)); }
0072 };
0073 Geant4Event& evt = context()->event();
0074 Geant4Random& rnd = evt.random();
0075
0076 const double dmin = std::numeric_limits<double>::epsilon();
0077 double phi = m_phiMin+(m_phiMax-m_phiMin)*rnd.rndm();
0078 double eta_max = Distribution::eta(m_thetaMin>dmin ? m_thetaMin : dmin);
0079 double eta_min = Distribution::eta(m_thetaMax>(M_PI-dmin) ? M_PI-dmin : m_thetaMax);
0080 double eta = eta_min + (eta_max-eta_min)*rnd.rndm();
0081 double x1 = std::cos(phi);
0082 double x2 = std::sin(phi);
0083 double x3 = std::sinh(eta);
0084 double r = std::sqrt(1.0+x3*x3);
0085 direction.SetXYZ(x1/r,x2/r,x3/r);
0086 getParticleMomentumUniform(momentum);
0087 }
0088
0089
0090 void Geant4IsotropeGenerator::getParticleDirectionFFbar(int, ROOT::Math::XYZVector& direction, double& momentum) const {
0091 struct Distribution {
0092 static double ffbar(double x) { double c = std::cos(x); return 1 + c*c; }
0093
0094 };
0095 Geant4Event& evt = context()->event();
0096 Geant4Random& rnd = evt.random();
0097 double phi = m_phiMin+(m_phiMax-m_phiMin)*rnd.rndm();
0098
0099
0100
0101 double v1 = Distribution::ffbar(m_thetaMin), v2 = Distribution::ffbar(m_thetaMax);
0102 double vmax = std::max(v1,v2);
0103 while(1) {
0104 double dice = rnd.rndm()*vmax;
0105 double theta = m_thetaMin+(m_thetaMax-m_thetaMin)*rnd.rndm();
0106 double dist = Distribution::ffbar(theta);
0107 if ( dice <= dist ) {
0108 double x1 = std::sin(theta)*std::cos(phi);
0109 double x2 = std::sin(theta)*std::sin(phi);
0110 double x3 = std::cos(theta);
0111 direction.SetXYZ(x1,x2,x3);
0112 getParticleMomentumUniform(momentum);
0113 return;
0114 }
0115 }
0116 }
0117
0118
0119 void Geant4IsotropeGenerator::getParticleDirection(int num, ROOT::Math::XYZVector& direction, double& momentum) const {
0120 switch(::toupper(m_distribution[0])) {
0121 case 'C':
0122 return getParticleDirectionCosTheta(num, direction, momentum);
0123 case 'F':
0124 return getParticleDirectionFFbar(num, direction, momentum);
0125 case 'E':
0126 case 'P':
0127 case 'R':
0128 return getParticleDirectionEta(num, direction, momentum);
0129 case 'U':
0130 return getParticleDirectionUniform(num, direction, momentum);
0131 default:
0132 break;
0133 }
0134 except("Unknown distribution densitiy: %s. Cannot generate primaries.",
0135 m_distribution.c_str());
0136 }