ATLAS Offline Software
Loading...
Searching...
No Matches
Samplers.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Helper for MultiParticleGunPileup
6// Olivier Arnaez, started 17/12/15
7// adapted from Generators/ParticleGun/python/samplers.py
8
10
11#include "TLorentzVector.h"
12#include "TRandom.h"
13#include "TMath.h"
14#include <map>
15#include <vector>
16#include <iostream>
17#include <string>
18
19//Base class for all samplers
20class Sampler {
21 public:
22 Sampler() = default;
23 explicit Sampler(float val):m_val(val){}
24 virtual ~Sampler()= default;
25 virtual float shoot() {return m_val;};
26 float m_val{};
27 TRandom m_random;
28};
29
30//A special-case sampler which just returns one value rather than sampling.
31class ConstSampler : public Sampler {
32 public:
33 ConstSampler() =default;
34 explicit ConstSampler(float val): Sampler(val) {};
35 ~ConstSampler() = default;
36 virtual float shoot() { return m_val;};
37};
38
40 public:
41 MomSampler() = default;
42 ~MomSampler() = default;
43 virtual TLorentzVector shoot() {return m_val;};
44 TLorentzVector m_val;
46};
47
48//--------------------------------
49//Continuous distribution samplers
50//--------------------------------
51
52//Uniformly sample in the range [low,high).
53class UniformSampler : public Sampler {
54 public:
55 UniformSampler()= default;
56 UniformSampler(float low, float high) {
57 assert(low <= high);
58 m_low = float(low);
59 m_high = float(high);
60 };
62 float shoot() { return Sampler::m_random.Uniform(m_low, m_high); };
63 float m_low{}, m_high{1.0};
64};
65
66//Uniformly sample in the modulus range (-high,low]+[low,high).
68 public:
70 ModUniformSampler(float low, float high) : UniformSampler (low, high){
71 assert(low == fabs(low) && high == fabs(high));
72 assert(low <= high);
73 m_low = float(low);
74 m_high = float(high);
75 };
76
77 float shoot() {
78 m_val = m_random.Uniform(m_low, m_high);
79 if (m_random.Uniform() > 0.5)
80 m_val *= -1;
81 return m_val;
82 };
83};
84
85//Uniformly sample from a set of disjoint intervals.
87 /* The ranges variable can either be a list of increasing numbers or a
88 list of pairs of numbers.
89
90 The former case will be treated as
91 defining alternating on/off ranges for sampling, starting with an active
92 one (i.e. it's a list of bin edges). The latter way specifically lists
93 the 'on' regions only, with their start and end values in the pairs.
94
95 The behaviour is undefined if the numbers are not ordered or overlap --
96 i.e. it might work but hasn't been designed that way and might change in
97 future. Don't rely on this behaviour!
98 */
99 public:
101 DisjointUniformSampler(const std::vector<float> & ranges) {
102 for (unsigned int i=0; i<ranges.size();) {
103 std::pair<float,float> p(ranges[i],ranges[i+1]);
104 i+=2;
105 m_ranges.push_back(p);
106 }
107 _setRanges();
108 };
109 DisjointUniformSampler(const std::vector< std::pair<float,float> > & ranges): m_ranges(ranges){ _setRanges();}
110
111 const std::vector< std::pair<float,float> > & _getRanges() { return m_ranges; };
112
113 void _setRanges() {
114 for (unsigned int i=0; i<m_ranges.size(); i++) {
115 m_totalwidth += m_ranges[i].second - m_ranges[i].first;
116 };
117 float runningwidth = 0.0;
118 m_divisions.push_back(0.0);
119 for (unsigned int i=0; i<m_ranges.size(); i++) {
120 assert(m_ranges[i].second >= m_ranges[i].first);
121 runningwidth += float(m_ranges[i].second - m_ranges[i].first);
122 m_divisions.push_back(runningwidth);
123 }
124 m_totalwidth = runningwidth;
125 for (unsigned int i=0; i<m_ranges.size(); i++)
126 m_divisions[i] = float(m_divisions[i]) / float(m_totalwidth);
127 };
128
129 float _map_unit_to_val(float x){
130 assert(x >= 0 && x <= 1);
131 unsigned int idx = -1, rem = 0;
132 for (unsigned int i=0; i<m_divisions.size()-1; i++)
133 if (x >= m_divisions[i] and x < m_divisions[i+1]) {
134 idx = i;
135 rem = x - m_divisions[i];
136 break;
137 }
138 float val = m_ranges[idx].first + m_totalwidth * rem;
139 return val;
140 };
141
142 float shoot(){
143 float rand = m_random.Uniform();
144 float val = _map_unit_to_val(rand);
145 return val;
146 };
147 private:
148 std::vector< std::pair<float,float> > m_ranges;
150 std::vector<float> m_divisions;
151};
152
153//Randomly sample from an exponential distribution (i.e. uniformly on a log scale).
155 public:
156 LogSampler(float low, float high): UniformSampler (low, high){
157 m_low = low;
158 m_high = high;
159 };
161
162 float shoot(){
163 float rand = m_random.Uniform();
164 float logval = rand * TMath::Log(m_high) + (1 - rand) * TMath::Log(m_low);
165 float val = TMath::Exp(logval);
166 return val;
167 };
168};
169
170//Randomly sample from a 1D Gaussian distribution.
172 public:
174 GaussianSampler(float mean, float sigma): UniformSampler (0, 1){
175 m_mean = mean;
176 m_sigma = sigma;
177 }
178
179 float shoot() { return m_random.Gaus(m_mean, m_sigma);};
180 private:
181 float m_mean{},m_sigma{};
182};
183
184
185//Sequentially sample from a list of values, returning to the beginning once exhausted.
186class CyclicSeqSampler : public Sampler {
187 public:
190 CyclicSeqSampler(std::string s) {
191 size_t pos = 0;
192 std::string token;
193 std::cout << "Initializing CyclicSeqSampler..." << std::endl;
194 while ((pos = s.find(',')) != std::string::npos) {
195 token = s.substr(0, pos);
196 m_sequence.push_back(std::stoi(token));
197 s.erase(0, pos + 1);
198 std::cout << " adding " << m_sequence[m_sequence.size()-1] << " from " << token.c_str() << std::endl;
199 }
200 m_index = 0;
201 };
202 float shoot() {
203 m_index = (m_index + 1) % m_sequence.size();
204 std::cout << "CyclicSeqSampler returning " << m_sequence[m_index] << std::endl;
205 return m_sequence[m_index];
206 };
207 private:
208 std::vector<int> m_sequence;
209 int m_index{};
210};
211
212// Convenience function for sampler-making from Python literals
213/*
214Sampler mksampler(x){
215
216// Automatically cast the provided object to a sampler type. This is used
217// extensively inside the particle and position samplers, so that the user
218// can pass in a primitive type like a number or list and it will be
219// treated as if the more verbose sampler constructors had been called.
220//
221// Behaviour:
222// - if x can be called, i.e. x() is valid, we just return x;
223// - a Python list (square brackets) will be converted to a continuous
224// UniformSampler or DisjointUniformSampler;
225// - TODO: a Python tuple (round brackets/parentheses) will be treated
226// as a discrete CyclicSeqSampler;
227// - TODO: a Python set (curly brackets/braces) will be treated
228// as a discrete RandomSeqSampler;
229// - otherwise a ConstSampler will be created from x, so that x is
230// returned when the sampler is called.
231
232 if hasattr(x, "__call__"):
233 return x
234 elif type(x) is list:
235 # NB: disjoint ranges can be given as nested lists, e.g. [(1,2), (4,5)]
236 if len(x) == 2 and type(x[0]) in (int,float) and type(x[1]) in (int,float):
237 #print "MKSAMPLER: Casting %s to UniformSampler" % str(x)
238 return UniformSampler(*x)
239 elif len(x) > 2 or (len(x) > 0 and type(x[0]) not in (int,float)):
240 #print "MKSAMPLER: Casting %s to DisjointUniformSampler" % str(x)
241 return DisjointUniformSampler(x)
242 if len(x) < 2:
243 raise Exception("Supplied list could not be converted to a continuous sampler")
244 elif type(x) is tuple:
245 #print "MKSAMPLER: Casting %s to CyclicSeqSampler" % str(x)
246 return CyclicSeqSampler(*x)
247 elif type(x) is set:
248 #print "MKSAMPLER: Casting %s to RandomSeqSampler" % str(x)
249 return RandomSeqSampler(*x)
250 else:
251 #print "MKSAMPLER: Casting %s to ConstSampler" % str(x)
252 return ConstSampler(x)
253*/
254
255
256// Beam-spot (origin vertex) sampling
257//Sampler of position 3-vectors, for modelling a beamspot.
259 public:
260 ~PosSampler() = default;
261 PosSampler() = default;
262 PosSampler(float x, float y, float z, float t=0):
264 //nop
265 }
266
267 TLorentzVector shoot(){
268 float x = m_x.shoot();
269 float y = m_y.shoot();
270 float z = m_z.shoot();
271 float t = m_t.shoot();
272 return TLorentzVector(x, y, z, t);
273 }
274 private:
275 Sampler m_x{0.f}, m_y{0.f}, m_z{0.f}, m_t{0.f};
276};
277
278// Momentum sampling
279//A momentum sampler which just returns a null vector with the given mass.
281 public:
283 explicit NullMomSampler(float mass=0.0) { m_mass = new ConstSampler(mass);};
284
285 TLorentzVector shoot() {
286 return TLorentzVector(0, 0, 0, m_mass->shoot());
287 }
288};
289
290
291
292//Create a 4-momentum vector from pt, eta, m and phi distributions/samplers.
294 public:
295 ~PtEtaMPhiSampler() { delete m_pt; delete m_eta; delete m_phi;};
296 PtEtaMPhiSampler(const PtEtaMPhiSampler & other ) = delete;
298 PtEtaMPhiSampler(float ptmin, float ptmax, float etamin, float etamax, float mass=0.0, float phimin=0, float phimax=2.*TMath::Pi()){
299 if (ptmin==ptmax)
300 m_pt = new ConstSampler(ptmin);
301 else
302 m_pt = new UniformSampler(ptmin,ptmax);
303 if (etamin==etamax)
304 m_eta = new ConstSampler(etamin);
305 else
306 m_eta = new UniformSampler(etamin,etamax);
307 m_mass = new ConstSampler(mass);
308 if (phimin==phimax)
309 m_phi = new ConstSampler(phimin);
310 else
311 m_phi = new UniformSampler(phimin,phimax);
312 };
313
314 TLorentzVector shoot() {
315 float eta = m_eta->shoot();
316 float pt = m_pt->shoot();
317 float phi = m_phi->shoot();
318 float m = m_mass->shoot();
319 TLorentzVector tlv; tlv.SetPtEtaPhiM(pt,eta,phi,m);
320 return tlv;
321 };
322
323 private:
324 Sampler * m_pt{}, * m_eta{}, * m_phi{};
325};
326
327// Combined samplers returning a particle configuration
328
329// A particle object for use as a return value from the particle samplers
331 public:
333 SampledParticle(int pid=0, TLorentzVector mom=TLorentzVector(0,0,0,0), TLorentzVector pos= TLorentzVector(0,0,0,0)) :
334 m_pid (pid), m_mom(mom), m_pos(pos), m_mass(0.f){
335 // Constructor/initializer: PID is the (int) PDG particle ID code
336 // of this particle, mom is its momentum 4-vector, and pos is
337 // the vertex 4-position (both as ROOT.TLorentzVector, in MeV).
338 }
339 int m_pid{};
340 TLorentzVector m_mom, m_pos;
341 float m_mass{};
342};
343
344// A simple N-independent-particle sampler.
346 public:
347 ~ParticleSampler() = default;
365
366 //Return a vector of sampled particles
367 std::vector<SampledParticle> shoot() {
368 int numparticles = m_n.shoot();
369 std::cout << "ParticleSampler throwing " << numparticles << " particles" << std::endl;
370 std::vector<SampledParticle> rtn;
371 for (int i=0; i<numparticles ; i++){
372 //Sample the particle ID and create a particle
373 int pid = m_pid->shoot();
374 std::cout << " shot pid=" << pid << std::endl;
376 // Pass mass info to the v4 sampler and set same generated mass
377 if (m_mass_override && m_massdict.find(abs(pid))!=m_massdict.end()){
378 float m = m_massdict[abs(pid)];
379 m_mom->m_mass = new ConstSampler(m);
380 p.m_mass = m;
381 }
382 // Sample momentum and vertex positions into the particle
383 p.m_mom = m_mom->shoot();
384 p.m_pos = m_pos.shoot();
385 std::cout << " (" << p.m_mom.Eta() << ", " << p.m_mom.Phi() << ", " << p.m_mom.E() << ", " << p.m_mom.M() << ")" << std::endl;
386 // Add particle to output list
387 rtn.push_back(p);
388 }
389 return rtn;
390 }
391 private:
397 std::map<unsigned int,float> m_massdict;
398};
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
A number of constexpr particle constants to avoid hardcoding them directly in various places.
#define y
#define x
#define z
virtual float shoot()
Definition Samplers.h:36
ConstSampler(float val)
Definition Samplers.h:34
~ConstSampler()=default
ConstSampler()=default
CyclicSeqSampler(std::string s)
Definition Samplers.h:190
std::vector< int > m_sequence
Definition Samplers.h:208
CyclicSeqSampler(const CyclicSeqSampler &orig)
Definition Samplers.h:189
DisjointUniformSampler(const std::vector< std::pair< float, float > > &ranges)
Definition Samplers.h:109
const std::vector< std::pair< float, float > > & _getRanges()
Definition Samplers.h:111
std::vector< float > m_divisions
Definition Samplers.h:150
std::vector< std::pair< float, float > > m_ranges
Definition Samplers.h:148
DisjointUniformSampler(const std::vector< float > &ranges)
Definition Samplers.h:101
float _map_unit_to_val(float x)
Definition Samplers.h:129
GaussianSampler(float mean, float sigma)
Definition Samplers.h:174
float shoot()
Definition Samplers.h:179
LogSampler(float low, float high)
Definition Samplers.h:156
float shoot()
Definition Samplers.h:162
ModUniformSampler(float low, float high)
Definition Samplers.h:70
TLorentzVector m_val
Definition Samplers.h:44
~MomSampler()=default
virtual TLorentzVector shoot()
Definition Samplers.h:43
MomSampler()=default
ConstSampler * m_mass
Definition Samplers.h:45
NullMomSampler(float mass=0.0)
Definition Samplers.h:283
TLorentzVector shoot()
Definition Samplers.h:285
ParticleSampler(Sampler *pid, MomSampler *mom, int n=1)
Definition Samplers.h:348
MomSampler * m_mom
Definition Samplers.h:392
std::map< unsigned int, float > m_massdict
Definition Samplers.h:397
~ParticleSampler()=default
ConstSampler m_n
Definition Samplers.h:395
bool m_mass_override
Definition Samplers.h:396
Sampler * m_pid
Definition Samplers.h:394
PosSampler m_pos
Definition Samplers.h:393
std::vector< SampledParticle > shoot()
Definition Samplers.h:367
Sampler m_t
Definition Samplers.h:275
PosSampler()=default
TLorentzVector shoot()
Definition Samplers.h:267
Sampler m_y
Definition Samplers.h:275
Sampler m_z
Definition Samplers.h:275
Sampler m_x
Definition Samplers.h:275
~PosSampler()=default
PosSampler(float x, float y, float z, float t=0)
Definition Samplers.h:262
Sampler * m_pt
Definition Samplers.h:324
Sampler * m_phi
Definition Samplers.h:324
PtEtaMPhiSampler & operator=(const PtEtaMPhiSampler &other)=delete
Sampler * m_eta
Definition Samplers.h:324
PtEtaMPhiSampler(const PtEtaMPhiSampler &other)=delete
PtEtaMPhiSampler(float ptmin, float ptmax, float etamin, float etamax, float mass=0.0, float phimin=0, float phimax=2.*TMath::Pi())
Definition Samplers.h:298
TLorentzVector shoot()
Definition Samplers.h:314
TLorentzVector m_pos
Definition Samplers.h:340
SampledParticle(int pid=0, TLorentzVector mom=TLorentzVector(0, 0, 0, 0), TLorentzVector pos=TLorentzVector(0, 0, 0, 0))
Definition Samplers.h:333
TLorentzVector m_mom
Definition Samplers.h:340
virtual ~Sampler()=default
Sampler(float val)
Definition Samplers.h:23
TRandom m_random
Definition Samplers.h:27
float m_val
Definition Samplers.h:26
virtual float shoot()
Definition Samplers.h:25
Sampler()=default
UniformSampler()=default
float shoot()
Definition Samplers.h:62
UniformSampler(float low, float high)
Definition Samplers.h:56
void mean(std::vector< double > &bins, std::vector< double > &values, const std::vector< std::string > &files, const std::string &histname, const std::string &tplotname, const std::string &label="")
double ptmax
constexpr double etaMassInMeV
the mass of the eta meson (in MeV)
constexpr double muonMassInMeV
the mass of the muon (in MeV)
constexpr double chargedKaonMassInMeV
the mass of the charged kaon (in MeV)
constexpr double protonMassInMeV
the mass of the proton (in MeV)
constexpr double tauMassInMeV
the mass of the tau (in MeV)
constexpr double KZeroMassInMeV
the mass of the neutral kaon (K0) (in MeV)
constexpr double chargedPionMassInMeV
the mass of the charged pion (in MeV)
constexpr double electronMassInMeV
the mass of the electron (in MeV)
constexpr double piZeroMassInMeV
the mass of the pi zero (in MeV)
constexpr double neutronMassInMeV
the mass of the neutron (in MeV)
constexpr double photonMassInMeV
various mass-less particles
constexpr double electronNeutrinoMassInMeV
constexpr double tauNeutrinoMassInMeV
constexpr double muonNeutrinoMassInMeV