DD4hep  1.36.0
Detector Description Toolkit for High Energy Physics
Geant4IsotropeGenerator.cpp
Go to the documentation of this file.
1 //==========================================================================
2 // AIDA Detector description implementation
3 //--------------------------------------------------------------------------
4 // Copyright (C) Organisation europeenne pour la Recherche nucleaire (CERN)
5 // All rights reserved.
6 //
7 // For the licensing terms see $DD4hepINSTALL/LICENSE.
8 // For the list of contributors see $DD4hepINSTALL/doc/CREDITS.
9 //
10 // Author : M.Frank
11 //
12 //==========================================================================
13 
14 // Framework include files
15 #include <DD4hep/Printout.h>
16 #include <DD4hep/InstanceCount.h>
17 #include <DDG4/Geant4Random.h>
19 
20 using namespace dd4hep::sim;
21 
24  : Geant4ParticleGenerator(ctxt, nam)
25 {
27  declareProperty("PhiMin", m_phiMin = 0.0);
28  declareProperty("PhiMax", m_phiMax = 2.0*M_PI);
29  declareProperty("ThetaMin", m_thetaMin = 0.0);
30  declareProperty("ThetaMax", m_thetaMax = M_PI);
31  declareProperty("Distribution", m_distribution = "uniform" );
32  declareProperty("Halton", m_halton = false);
33  declareProperty("HaltonOffset", m_haltonOffset = 0ULL);
34  m_haltonIndex = 0;
35  m_haltonShift = {0.0, 0.0, 0.0};
36 }
37 
41 }
42 
45  for (auto& s : m_haltonShift) s = rnd.rndm();
47 }
48 
50 double Geant4IsotropeGenerator::haltonValue(uint64_t index, int base) {
51  uint64_t num = 0;
52  uint64_t denom = 1;
53  while ( index > 0 ) {
54  denom *= base;
55  num = num * base + (index % base);
56  index /= base;
57  }
58  return static_cast<double>(num) / static_cast<double>(denom);
59 }
60 
62 double Geant4IsotropeGenerator::haltonScrambled(uint64_t index, unsigned int dim) const {
63  static constexpr std::array<int,3> bases = {2, 3, 5};
64  if ( dim >= bases.size() ) {
65  except("haltonScrambled: dimension %u out of range [0,%zu].", dim, bases.size()-1);
66  }
67  return std::fmod(haltonValue(index, bases[dim]) + m_haltonShift[dim], 1.0);
68 }
69 
71 std::function<double(unsigned int)> Geant4IsotropeGenerator::makeSampler(Geant4Random& rnd) const {
72  if ( m_halton ) {
73  std::call_once(m_haltonOnce, &Geant4IsotropeGenerator::initHalton, this, std::ref(rnd));
74  uint64_t idx = m_haltonIndex++;
75  return [this, idx](unsigned int dim) { return haltonScrambled(idx, dim); };
76  }
77  return [&rnd](unsigned int) { return rnd.rndm(); };
78 }
79 
81 void Geant4IsotropeGenerator::sampleMomentum(double h, double& momentum) const {
82  if ( m_energy != -1 ) {
83  momentum = m_energy;
84  return;
85  }
87  momentum = m_momentumMin + (momentum - m_momentumMin) * h;
88  else
89  momentum = m_momentumMin + (m_momentumMax - m_momentumMin) * h;
90 }
91 
93 void Geant4IsotropeGenerator::getParticleDirectionUniform(int, const std::function<double(unsigned int)>& sample,
94  ROOT::Math::XYZVector& direction, double& momentum) const {
95  double phi = m_phiMin + (m_phiMax - m_phiMin) * sample(0);
96  double theta = m_thetaMin + (m_thetaMax - m_thetaMin) * sample(1);
97  direction.SetXYZ(std::sin(theta)*std::cos(phi), std::sin(theta)*std::sin(phi), std::cos(theta));
98  sampleMomentum(sample(2), momentum);
99 }
100 
102 void Geant4IsotropeGenerator::getParticleDirectionCosTheta(int, const std::function<double(unsigned int)>& sample,
103  ROOT::Math::XYZVector& direction, double& momentum) const {
104  double phi = m_phiMin + (m_phiMax - m_phiMin) * sample(0);
105  double cos_theta = std::cos(m_thetaMin) + (std::cos(m_thetaMax) - std::cos(m_thetaMin)) * sample(1);
106  double sin_theta = std::sqrt(1.0 - cos_theta*cos_theta);
107  direction.SetXYZ(sin_theta*std::cos(phi), sin_theta*std::sin(phi), cos_theta);
108  sampleMomentum(sample(2), momentum);
109 }
110 
112 void Geant4IsotropeGenerator::getParticleDirectionEta(int, const std::function<double(unsigned int)>& sample,
113  ROOT::Math::XYZVector& direction, double& momentum) const {
114  struct Distribution {
115  static double eta(double x) { return -1.0*std::log(std::tan(x/2.0)); }
116  };
117  const double dmin = std::numeric_limits<double>::epsilon();
118  double phi = m_phiMin + (m_phiMax - m_phiMin) * sample(0);
119  double eta_max = Distribution::eta(m_thetaMin > dmin ? m_thetaMin : dmin);
120  double eta_min = Distribution::eta(m_thetaMax > (M_PI - dmin) ? M_PI - dmin : m_thetaMax);
121  double eta = eta_min + (eta_max - eta_min) * sample(1);
122  double x1 = std::cos(phi);
123  double x2 = std::sin(phi);
124  double x3 = std::sinh(eta);
125  double r = std::sqrt(1.0+x3*x3);
126  direction.SetXYZ(x1/r,x2/r,x3/r);
127  sampleMomentum(sample(2), momentum);
128 }
129 
131 void Geant4IsotropeGenerator::getParticleDirectionFFbar(int, ROOT::Math::XYZVector& direction, double& momentum) const {
132  struct Distribution {
133  static double ffbar(double x) { double c = std::cos(x); return 1 + c*c; }
134  //static double integral(double x) { return 1.5*x + sin(2.*x)/4.0; }
135  };
136  Geant4Event& evt = context()->event();
137  Geant4Random& rnd = evt.random();
138  double phi = m_phiMin+(m_phiMax-m_phiMin)*rnd.rndm();
139 
140  // 1 + cos^2(theta) cannot be integrated and then inverted.
141  // We have to throw the dice until it fits.....
142  double v1 = Distribution::ffbar(m_thetaMin), v2 = Distribution::ffbar(m_thetaMax);
143  double vmax = std::max(v1,v2); // ffbar symmetric and monotonic in |x|.
144  while(1) {
145  double dice = rnd.rndm()*vmax;
146  double theta = m_thetaMin+(m_thetaMax-m_thetaMin)*rnd.rndm();
147  if ( dice <= Distribution::ffbar(theta) ) {
148  direction.SetXYZ(std::sin(theta)*std::cos(phi), std::sin(theta)*std::sin(phi), std::cos(theta));
149  sampleMomentum(rnd.rndm(), momentum);
150  return;
151  }
152  }
153 }
154 
156 void Geant4IsotropeGenerator::getParticleDirection(int num, ROOT::Math::XYZVector& direction, double& momentum) const {
157  if ( m_halton && ::toupper(m_distribution[0]) == 'F' ) {
158  except("Halton mode is incompatible with the 'ffbar' distribution: "
159  "acceptance-rejection cannot be driven by a fixed per-particle Halton point. "
160  "Use distribution='uniform', 'cos(theta)', or 'eta' with Halton mode.");
161  }
162  Geant4Event& evt = context()->event();
163  Geant4Random& rnd = evt.random();
164  auto sample = makeSampler(rnd);
165  switch(::toupper(m_distribution[0])) {
166  case 'C': // cos(theta)
167  return getParticleDirectionCosTheta(num, sample, direction, momentum);
168  case 'F': // ffbar: ~ 1 + cos^2(theta)
169  return getParticleDirectionFFbar(num, direction, momentum);
170  case 'E': // eta, rapidity, pseudorapidity
171  case 'P':
172  case 'R':
173  return getParticleDirectionEta(num, sample, direction, momentum);
174  case 'U': // uniform
175  return getParticleDirectionUniform(num, sample, direction, momentum);
176  default:
177  break;
178  }
179  except("Unknown distribution density: %s. Cannot generate primaries.",
180  m_distribution.c_str());
181 }
dd4hep::sim::Geant4IsotropeGenerator::~Geant4IsotropeGenerator
virtual ~Geant4IsotropeGenerator()
Default destructor.
Definition: Geant4IsotropeGenerator.cpp:39
Geant4IsotropeGenerator.h
dd4hep::sim::Geant4Random::rndm
double rndm(int i=0)
Create flat distributed random numbers in the interval ]0,1].
Definition: Geant4Random.cpp:268
dd4hep::sim::Geant4IsotropeGenerator::m_phiMax
double m_phiMax
Property: Maximal phi angular value.
Definition: Geant4IsotropeGenerator.h:61
M_PI
#define M_PI
Definition: Handle.h:31
dd4hep::sim::Geant4IsotropeGenerator::m_distribution
std::string m_distribution
Property: Distribution name. Default: "uniform". Allowed: "uniform", "cos(theta)",...
Definition: Geant4IsotropeGenerator.h:57
dd4hep::sim::Geant4IsotropeGenerator::m_haltonIndex
uint64_t m_haltonIndex
Current Halton sequence index (incremented per generated particle)
Definition: Geant4IsotropeGenerator.h:71
dd4hep::sim::Geant4ParticleGenerator::m_momentumMin
double m_momentumMin
Property: Minimal momentum value.
Definition: Geant4ParticleGenerator.h:52
dd4hep::InstanceCount::increment
static void increment(T *)
Increment count according to type information.
Definition: InstanceCount.h:98
dd4hep::sim::Geant4Context::event
Geant4Event & event() const
Access the geant4 event – valid only between BeginEvent() and EndEvent()!
Definition: Geant4Context.cpp:84
dd4hep::sim::Geant4Event::random
Geant4Random & random() const
Access the random number generator.
Definition: Geant4Context.h:137
dd4hep::sim::Geant4IsotropeGenerator::m_phiMin
double m_phiMin
Property: Minimal phi angular value.
Definition: Geant4IsotropeGenerator.h:59
dd4hep::sim::Geant4IsotropeGenerator::m_thetaMax
double m_thetaMax
Property: Maximal theta angular value.
Definition: Geant4IsotropeGenerator.h:65
dd4hep::sim::Geant4IsotropeGenerator::m_haltonOffset
uint64_t m_haltonOffset
Property: Starting index in the Halton sequence (use for parallel-job partitioning)
Definition: Geant4IsotropeGenerator.h:69
dd4hep::sim::Geant4ParticleGenerator::m_energy
double m_energy
Property: Fixed momentum value, overwrites momentumMin and momentumMax if set.
Definition: Geant4ParticleGenerator.h:50
dd4hep::sim::Geant4IsotropeGenerator::m_thetaMin
double m_thetaMin
Property: Minimal theta angular value.
Definition: Geant4IsotropeGenerator.h:63
epsilon
const double epsilon
Definition: test_cellid_position_converter.cpp:41
dd4hep::sim::Geant4IsotropeGenerator::makeSampler
std::function< double(unsigned int)> makeSampler(Geant4Random &rnd) const
Build a per-particle sampler: PRNG or Halton depending on m_halton.
Definition: Geant4IsotropeGenerator.cpp:71
dd4hep::sim::Geant4IsotropeGenerator::haltonScrambled
double haltonScrambled(uint64_t index, unsigned int dim) const
Return the scrambled Halton sample for dimension dim (0=phi,1=theta,2=momentum)
Definition: Geant4IsotropeGenerator.cpp:62
dd4hep::sim::Geant4IsotropeGenerator::sampleMomentum
void sampleMomentum(double h, double &momentum) const
Sample momentum from [m_momentumMin, m_momentumMax] using a pre-computed [0,1) value h.
Definition: Geant4IsotropeGenerator.cpp:81
dd4hep::sim::Geant4Action::except
void except(const char *fmt,...) const
Support of exceptions: Print fatal message and throw runtime_error.
Definition: Geant4Action.cpp:256
Geant4Random.h
dd4hep::sim::Geant4IsotropeGenerator::initHalton
void initHalton(Geant4Random &rnd) const
Initialize Cranley-Patterson shifts using rnd; set m_haltonIndex = m_haltonOffset.
Definition: Geant4IsotropeGenerator.cpp:44
dd4hep::sim::Geant4ParticleGenerator::m_momentumMax
double m_momentumMax
Property: Maximal momentum value.
Definition: Geant4ParticleGenerator.h:54
dd4hep::sim::Geant4IsotropeGenerator::getParticleDirectionFFbar
void getParticleDirectionFFbar(int num, ROOT::Math::XYZVector &direction, double &momentum) const
e+e- --> ffbar particle distribution ~ 1 + cos^2(theta) (PRNG only; incompatible with Halton)
Definition: Geant4IsotropeGenerator.cpp:131
dd4hep::sim::Geant4Action::declareProperty
Geant4Action & declareProperty(const std::string &nam, T &val)
Declare property.
Definition: Geant4Action.h:366
dd4hep::InstanceCount::decrement
static void decrement(T *)
Decrement count according to type information.
Definition: InstanceCount.h:102
dd4hep::sim::Geant4IsotropeGenerator::Geant4IsotropeGenerator
Geant4IsotropeGenerator()=delete
Inhibit default constructor.
dd4hep::sim::Geant4IsotropeGenerator::m_haltonOnce
std::once_flag m_haltonOnce
Ensures initHalton() runs exactly once across all events.
Definition: Geant4IsotropeGenerator.h:75
dd4hep::sim::Geant4Random
Mini interface to THE random generator of the application.
Definition: Geant4Random.h:59
dd4hep::sim::Geant4ParticleGenerator
Generate particles isotrop in space around origine (0,0,0)
Definition: Geant4ParticleGenerator.h:38
dd4hep::sim::Geant4IsotropeGenerator::haltonValue
static double haltonValue(uint64_t index, int base)
Compute the radical inverse of index in the given base (standard Halton value)
Definition: Geant4IsotropeGenerator.cpp:50
dd4hep::sim
Namespace for the Geant4 based simulation part of the AIDA detector description toolkit.
Definition: EDM4hepFileReader.cpp:46
dd4hep::sim::Geant4IsotropeGenerator::getParticleDirection
virtual void getParticleDirection(int num, ROOT::Math::XYZVector &direction, double &momentum) const override
Particle modification. Caller presets defaults to: ( direction = m_direction, momentum = [m_momentumM...
Definition: Geant4IsotropeGenerator.cpp:156
InstanceCount.h
dd4hep::sim::Geant4IsotropeGenerator::getParticleDirectionEta
void getParticleDirectionEta(int num, const std::function< double(unsigned int)> &sample, ROOT::Math::XYZVector &direction, double &momentum) const
Flat pseudorapidity (eta) distribution.
Definition: Geant4IsotropeGenerator.cpp:112
dd4hep::sim::Geant4IsotropeGenerator::getParticleDirectionCosTheta
void getParticleDirectionCosTheta(int num, const std::function< double(unsigned int)> &sample, ROOT::Math::XYZVector &direction, double &momentum) const
Particle distribution ~ cos(theta)
Definition: Geant4IsotropeGenerator.cpp:102
dd4hep::sim::Geant4Event
User event context for DDG4.
Definition: Geant4Context.h:121
Printout.h
dd4hep::sim::Geant4IsotropeGenerator::getParticleDirectionUniform
void getParticleDirectionUniform(int num, const std::function< double(unsigned int)> &sample, ROOT::Math::XYZVector &direction, double &momentum) const
Uniform particle distribution.
Definition: Geant4IsotropeGenerator.cpp:93
dd4hep::sim::Geant4Context
Generic context to extend user, run and event information.
Definition: Geant4Context.h:201
dd4hep::sim::Geant4IsotropeGenerator::m_haltonShift
std::array< double, 3 > m_haltonShift
Per-dimension additive scramble shifts in [0,1), sampled from Geant4Random on first use.
Definition: Geant4IsotropeGenerator.h:73
dd4hep::sim::Geant4Action::context
Geant4Context * context() const
Access the context.
Definition: Geant4Action.h:270
dd4hep::sim::Geant4IsotropeGenerator::m_halton
bool m_halton
Property: Enable scrambled Halton sequence sampling (RQMC mode)
Definition: Geant4IsotropeGenerator.h:67