ATLAS Offline Software
Loading...
Searching...
No Matches
ArrayBM.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include <algorithm> /*count_if,max_element*/
6#include <cassert>
7#include <cmath> /*ceil,floor*/
8#include <numeric> /*accumulate*/
9
10// Random Number Generation
12#include "CLHEP/Random/RandomEngine.h"
13#include "CLHEP/Random/RandGeneral.h"
14
16
17#include "UtilityFuncs.h"
18#include "ArrayBM.h"
19
20ArrayBM::ArrayBM(const std::string& name,ISvcLocator* svc)
21 : base_class(name,svc)
23 , m_t0Offset(0)
25 , m_ipLength(1)
26 , m_intensityPattern(new double[m_ipLength])
27 , m_biRandom(nullptr)
29 , m_signalPattern(nullptr)
30{
31 declareProperty("MaxBunchCrossingPerOrbit", m_maxBunchCrossingPerOrbit, "The number of slots in each LHC beam. Default: 3564.");
32 declareProperty("IntensityPattern", m_intensityPatternProp,
33 "An array of floats containing the beam intensity distribution as a function of time in bins of 25ns. ArrayBM normalizes the distribution and uses it as a stencil to determine the relative intensity at each beam xing in the simulated range"
34 );
35 declareProperty("EmptyBunchOption", m_emptyBunches=0, "Option for empty bunches. 0: normal treatment. Positive N: first N BCIDs after filled. Negative N: any empty BCID is allowed.");
36 m_intensityPattern[0]=1.0;
37}
38
40{
41 delete [] m_intensityPattern;
42 delete m_biRandom;
43}
44
46{
47 if (m_seed == 0u) {
48 // Only need AthRNGSvc if seed is set to 0
49 ATH_CHECK(m_randomSvc.retrieve());
50 m_rngWrapper = m_randomSvc->getEngine(this);
51 }
52
53 // Need to copy to make modifications for empty bunches
54 const std::vector<float>& rProp(m_intensityPatternProp.value());
55 std::vector<float>::const_iterator pBegin(rProp.begin());
56 std::vector<float>::const_iterator pEnd(rProp.end());
57 m_ipLength = rProp.size();
58 // Consistency checks
60 {
61 ATH_MSG_ERROR("IntensityPattern length (" << m_ipLength << "), exceeds the maximum number of bunch crossings per orbit (" << m_maxBunchCrossingPerOrbit << ").");
62 return StatusCode::FAILURE;
63 }
64
65 // Initialize the signal pattern if we need one different from the intensity pattern
66 if (m_signalPattern) delete [] m_signalPattern;
67 if (m_emptyBunches!=0){
68 m_signalPattern = new double[m_ipLength];
69 }
70 // Modification for empty bunches option
71 if (m_emptyBunches<0 || std::abs(m_emptyBunches)>static_cast<int>(m_ipLength)){
72 // Easy case: Just flip all the bunches
73 for (size_t i=0;i<m_ipLength;++i){
74 if (rProp[i]>0.) m_signalPattern[i]=0.;
75 else m_signalPattern[i]=1.;
76 } // Loop over all bunches in the pattern
77 } else if (m_emptyBunches>0){
78 // Harder case: N BCIDs after filled
79 int sinceFilled=0;
80 // Set sinceFilled for the beginning of the pattern; assume we will not wrap (otherwise caught above)
81 for (size_t i=m_ipLength-m_emptyBunches;i<m_ipLength;++i){
82 if (rProp[i]>0) sinceFilled=0;
83 else sinceFilled+=1;
84 } // Done with the loop over previous BCIDs
85 // Now do the loop setting the intensity pattern
86 for (size_t i=0;i<m_ipLength;++i){
87 if (rProp[i]>0){
88 // Filled BCID. Reset count, don't allow signal.
89 sinceFilled=0;
90 m_signalPattern[i]=0.;
91 } else if (sinceFilled<m_emptyBunches){
92 // First N BCIDs. Increment count, allow signal.
93 sinceFilled+=1;
94 m_signalPattern[i]=1.;
95 } else {
96 // Beyond N BCIDs. Increment count, don't allow signal.
97 sinceFilled+=1;
98 m_signalPattern[i]=0.;
99 }
100 } // Done with loop over previous BCIDs
101 }
102
103 // Normalise the pattern so that the non-zero elements average to 1.0
104 float nonZeroElementCount(static_cast<float>(std::count_if(pBegin, pEnd, IsNonZero)));
105 if(nonZeroElementCount<1.0)
106 {
107 ATH_MSG_ERROR("IntensityPattern has no non-zero elements!");
108 return StatusCode::FAILURE;
109 }
110 float elementSum(static_cast<float>(std::accumulate(pBegin, pEnd,0.0)));
111 float denominator(elementSum/nonZeroElementCount);
112
113 // Normalise the pattern so that the highest element value is 1.0
114 float maxElement(*(std::max_element(pBegin, pEnd)));
115 float inv_maxElement = maxElement != 0 ? 1. / maxElement : 1;
116
117 // Copy normalized intensity pattern from the property
118 delete [] m_intensityPattern;
119 m_intensityPattern = new double[m_ipLength];
120 for (unsigned int i=0; i<m_ipLength; ++i)
121 {
122 if (rProp[i]<0.0)
123 {
124 ATH_MSG_ERROR("All IntensityPattern elements must be >=0. Please fix element #" << i );
125 return StatusCode::FAILURE;
126 }
127 m_intensityPattern[i] = rProp[i] * inv_maxElement; // this ensures that the elements are all in the range [0,1]
128 }
129 // If we don't want to have signal in empty crossings, then our signal pattern is just the intensity pattern
130 if (m_emptyBunches==0){
132 }
133
134 // Will be used to convert values in the m_intensityPattern
135 // from having max value 1.0 to having mean value 1.0
136 if (denominator != 0) {
137 m_largestElementInPattern = (maxElement/denominator);
138 }
139
140 // FIXME add a check that entry 0 is zero? In data, BCID=1 is always the
141 // first filled bunch.
142
143 if (m_seed == 0u) {
144 delete m_biRandom;
145 // the engine is created if not there already
146 m_biRandom =
147 new CLHEP::RandGeneral(m_signalPattern, m_ipLength,
148 /*IntType=*/1); // discrete distribution
149 } else {
150 m_t0Dist =
151 std::make_unique<std::discrete_distribution<unsigned int>>(
153 }
154 return StatusCode::SUCCESS;
155}
156
157void ArrayBM::selectT0(unsigned int run, unsigned long long event)
158{
159 if (m_seed == 0u) {
160 // Use AthRNGSvc
161 const EventContext& ctx =
162 Gaudi::Hive::currentContext(); // not ideal, but seems the cleanest
163 // solution for now, as this call is
164 // once per event.
165 m_rngWrapper->setSeed("BEAMINT", ctx.slot(), event, run, ctx.evt());
166 CLHEP::HepRandomEngine* rndmEngine = m_rngWrapper->getEngine(ctx);
167 // m_biRandom->shoot() returns in range [0,1]
168 m_t0Offset = static_cast<unsigned int>(
169 floor((m_biRandom->shoot(rndmEngine) * m_ipLength) + 0.5));
170 } else {
171 FastReseededPRNG prng{m_seed.value(), run, event};
172 m_t0Offset = (*m_t0Dist)(prng);
173 }
174 assert(m_intensityPattern[m_t0Offset % m_ipLength] > 0.0); // just in case
175 ATH_MSG_DEBUG("selectT0 offset for this event " << m_t0Offset);
176 return;
177}
178
179float ArrayBM::normFactor(int iXing) const
180{
181 unsigned int index = static_cast<unsigned int>((((iXing + static_cast<int>(m_t0Offset)) % static_cast<int>(m_ipLength)) + static_cast<int>(m_ipLength) ) % static_cast<int>(m_ipLength));
182 //The array itself has max-value 1.0, but we want it to have mean value 1.0 (for filled bunch crossings), so we multiple by the m_largestElementInPattern.
183 ATH_MSG_VERBOSE("normFactor for BCID " << iXing
184 << " (offset " << m_t0Offset
185 << " index " << index
188}
A IBeamIntensity service configured with an intensity array The Gaudi::Property<std::vector<float>> d...
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
Holds helper functions used by FixedArrayBM and ArrayBM.
static bool IsNonZero(float lumi)
double * m_intensityPattern
normalized intensity pattern. C array to make clhep RandGeneral happy
Definition ArrayBM.h:65
virtual StatusCode initialize() override final
Definition ArrayBM.cxx:45
int m_emptyBunches
Empty bunch option.
Definition ArrayBM.h:82
Gaudi::Property< std::uint64_t > m_seed
seed for FastReseededPRNG. Non-zero switches to using FastReseededPRNG.
Definition ArrayBM.h:59
CLHEP::RandGeneral * m_biRandom
shoot random number proportionally to m_intensityPattern
Definition ArrayBM.h:67
float m_largestElementInPattern
The largest value in the pattern assuming that the pattern has mean value 1.0.
Definition ArrayBM.h:77
unsigned int m_maxBunchCrossingPerOrbit
max bunch crossings per orbit
Definition ArrayBM.h:55
virtual float normFactor(int iXing) const override final
Definition ArrayBM.cxx:179
ArrayBM(const std::string &name, ISvcLocator *svc)
Definition ArrayBM.cxx:20
virtual void selectT0(unsigned int run, unsigned long long event) override final
Definition ArrayBM.cxx:157
virtual ~ArrayBM()
Definition ArrayBM.cxx:39
Gaudi::Property< std::vector< float > > m_intensityPatternProp
user-defined intensity pattern
Definition ArrayBM.h:61
Gaudi::Hive::ContextSpecificData< unsigned int > m_t0Offset
offset of the t0 wrto our intensity pattern
Definition ArrayBM.h:57
unsigned int m_ipLength
length of the intensity pattern
Definition ArrayBM.h:63
std::unique_ptr< std::discrete_distribution< unsigned int > > m_t0Dist
as with m_biRandom, but for FastReseededPRNG
Definition ArrayBM.h:69
double * m_signalPattern
Additional array for keeping the locations we want signal in By default, will match the intensity pat...
Definition ArrayBM.h:85
ServiceHandle< IAthRNGSvc > m_randomSvc
the service managing our random seeds/sequences
Definition ArrayBM.h:71
Definition index.py:1
Definition run.py:1