ATLAS Offline Software
Loading...
Searching...
No Matches
L1DynamicPedestalProviderTxt.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3*/
5// L1DynamicPedestalProviderTxt.cxx
7
9
11
12#include <algorithm>
13#include <cmath>
14#include <initializer_list>
15#include <iterator>
16#include <fstream>
17#include <sstream>
18
19using std::make_unique;
20
21namespace {
23static constexpr bcid_t MAX_BCID = BunchCrossingCondData::m_MAX_BCID;
24}
25
26namespace LVL1
27{
28
30public:
31 virtual double operator()(double mu) = 0;
32 virtual ~ParamFunc() {}
33};
34
36public:
37 ParamFuncPol2(double p0, double p1, double p2) : m_p{{p0, p1, p2}} {}
38 virtual double operator()(double mu) { return m_p[0] + m_p[1]*mu + m_p[2]*mu*mu; }
39private:
40 std::array<double, 3> m_p;
41};
42
44public:
45 ParamFuncExp(double p0, double p1, double p2) : m_p{{p0, p1, p2}} {}
46 virtual double operator()(double mu) { return m_p[0]*(1-exp(-m_p[1]*mu)) + m_p[2]*mu; }
47private:
48 std::array<double, 3> m_p;
49};
50
51//================ Constructor ================================================
53 const std::string& n,
54 const IInterface* p)
55 : AthAlgTool(t, n, p)
56{
57 declareInterface<IL1DynamicPedestalProvider>(this);
58
59 // fill the vectors with default values - didn't find a more clever way due to move-only unique_ptr
60 m_emParameterizations[0] = std::vector<std::vector<std::unique_ptr<ParamFunc>>>(s_nElements);
61 m_emParameterizations[1] = std::vector<std::vector<std::unique_ptr<ParamFunc>>>(s_nElements);
62 m_hadParameterizations[0] = std::vector<std::vector<std::unique_ptr<ParamFunc>>>(s_nElements);
63 m_hadParameterizations[1] = std::vector<std::vector<std::unique_ptr<ParamFunc>>>(s_nElements);
64 for(std::size_t i = 0; i < s_nElements; ++i) {
65 m_emParameterizations[0][i] = std::vector<std::unique_ptr<ParamFunc>>(s_nBCIDPerTrain);
66 m_emParameterizations[1][i] = std::vector<std::unique_ptr<ParamFunc>>(s_nBCIDPerTrain);
67 m_hadParameterizations[0][i] = std::vector<std::unique_ptr<ParamFunc>>(s_nBCIDPerTrain);
68 m_hadParameterizations[1][i] = std::vector<std::unique_ptr<ParamFunc>>(s_nBCIDPerTrain);
69 }
70
71 // Input files containing the parameters for the electromagnetic and hadronic
72 // layer, respectively.
73 declareProperty("InputFileEM_ShortGap", m_inputFileEMShort);
74 declareProperty("InputFileHAD_ShortGap", m_inputFileHADShort);
75 declareProperty("InputFileEM_LongGap", m_inputFileEMLong);
76 declareProperty("InputFileHAD_LongGap", m_inputFileHADLong);
77}
78
79//================ Destructor =================================================
81{
82 // keep destructor in .cxx file since ~unique_ptr needs full type
83}
84
85
86//================ Initialisation =============================================
88{
89 ATH_CHECK( m_bcDataKey.initialize() );
90
91 // parse parameterization for the electromagnetic layer
92 std::string fileNameEMShort = PathResolver::find_file(m_inputFileEMShort, "DATAPATH");
93 if(fileNameEMShort.empty()) {
94 ATH_MSG_FATAL("Could not resolve input file: " << m_inputFileEMShort);
95 return StatusCode::FAILURE;
96 }
97 ATH_MSG_VERBOSE("::initialize: resolved input file: " << fileNameEMShort);
98
99 try {
100 parseInputFile(fileNameEMShort, m_emParameterizations[0]);
101 } catch (const ParseException& e) {
102 ATH_MSG_FATAL("Could not parse input file: " << fileNameEMShort << "; error: " << e.what());
103 return StatusCode::FAILURE;
104 }
105
106 std::string fileNameEMLong = PathResolver::find_file(m_inputFileEMLong, "DATAPATH");
107 if(fileNameEMLong.empty()) {
108 ATH_MSG_FATAL("Could not resolve input file: " << m_inputFileEMLong);
109 return StatusCode::FAILURE;
110 }
111 ATH_MSG_VERBOSE("::initialize: resolved input file: " << fileNameEMLong);
112
113 try {
114 parseInputFile(fileNameEMLong, m_emParameterizations[1]);
115 } catch (const ParseException& e) {
116 ATH_MSG_FATAL("Could not parse input file: " << fileNameEMLong << "; error: " << e.what());
117 return StatusCode::FAILURE;
118 }
119
120 // parse parameterization for the hadronic layer
121 std::string fileNameHADShort = PathResolver::find_file(m_inputFileHADShort, "DATAPATH");
122 if(fileNameHADShort.empty()) {
123 ATH_MSG_FATAL("Could not resolve input file: " << m_inputFileHADShort);
124 return StatusCode::FAILURE;
125 }
126 ATH_MSG_VERBOSE("::initialize: resolved input file: " << fileNameHADShort);
127
128 try {
129 parseInputFile(fileNameHADShort, m_hadParameterizations[0]);
130 } catch (const ParseException& e) {
131 ATH_MSG_FATAL("Could not parse input file: " << fileNameHADShort << "; error: " << e.what());
132 return StatusCode::FAILURE;
133 }
134
135 std::string fileNameHADLong = PathResolver::find_file(m_inputFileHADLong, "DATAPATH");
136 if(fileNameHADLong.empty()) {
137 ATH_MSG_FATAL("Could not resolve input file: " << m_inputFileHADLong);
138 return StatusCode::FAILURE;
139 }
140 ATH_MSG_VERBOSE("::initialize: resolved input file: " << fileNameHADLong);
141
142 try {
143 parseInputFile(fileNameHADLong, m_hadParameterizations[1]);
144 } catch (const ParseException& e) {
145 ATH_MSG_FATAL("Could not parse input file: " << fileNameHADLong << "; error: " << e.what());
146 return StatusCode::FAILURE;
147 }
148
149 return StatusCode::SUCCESS;
150}
151
152namespace {
153
154// Display results of the parsing for debugging purposes
155template<typename ResultVector>
156void printPatternParsingInfo(MsgStream& log, const BunchCrossingCondData& bcData, const ResultVector& result) {
157
158 for(bcid_t bcid = 0; bcid < MAX_BCID; bcid += 20) {
159 // print 20 items at once
160
161 log << MSG::VERBOSE << "Filled ";
162 for(bcid_t j = bcid; j != std::min(MAX_BCID, bcid+20); ++j) log << std::setw(3) << bcData.isFilled(j) << " ";
163 log << endmsg;
164
165 log << MSG::VERBOSE << "Distance ";
166 for(bcid_t j = bcid; j != std::min(MAX_BCID, bcid+20); ++j) log << std::setw(3) << result[j].second << " ";
167 log << endmsg;
168
169 log << MSG::VERBOSE << "LongGap? ";
170 for(bcid_t j = bcid; j != std::min(MAX_BCID, bcid+20); ++j) log << std::setw(3) << result[j].first << " ";
171 log << endmsg;
172 }
173}
174
175} // namespace [anonymous]
176
177
178// "Parse" the beam intensity pattern to get the bunch train structure.
180{
182
184
185 if(bcData->isFilled(bcid) || bcData->bcType(bcid) == BunchCrossingCondData::MiddleEmpty) {
186 return {bcData->gapBeforeTrain(bcid) > 250, bcData->distanceFromFront(bcid, BC)};
187 } else {
188 if(bcData->gapAfterBunch(bcid, BC) == 0) {
189 const bcid_t head = ((bcid + 1) == MAX_BCID ? 0 : bcid + 1); // wrap around
190 return {bcData->gapBeforeTrain(head) > 250, -1};
191 } else if(bcData->gapBeforeBunch(bcid, BC) == 0) {
192 const bcid_t tail = bcid ? bcid - 1 : MAX_BCID - 1; // wrap around
193 return {bcData->gapBeforeTrain(tail) > 250,
194 bcData->distanceFromFront(tail, BC) + 1};
195 } else {
196 return {false, -10};
197 }
198 }
199}
200
201//================ dynamic pedestal ==============================================
202// Return the dynamic pedestal.
203// In case no correction is available or applicable this function
204// returns the uncorrected pedestal.
205int L1DynamicPedestalProviderTxt::dynamicPedestal(int iElement, int layer, int pedestal, int iBCID, float mu) const
206{
207 /*
208 * Uncomment this for debugging/printing the full bunch train pattern
209 *
210 static bool first=true;
211 if (first) {
212 SG::ReadCondHandle<BunchCrossingCondData> bcData(m_bcDataKey);
213 first = false;
214 std::vector<std::pair<bool, int16_t>> dist;
215 dist.assign(MAX_BCID, std::make_pair(false, -10));
216 for(bcid_t bcid = 0; bcid != MAX_BCID; ++bcid) {
217 dist[bcid] = distanceFromHeadOfTrain(bcid);
218 }
219 printPatternParsingInfo(msg(), *bcData.retrieve(), dist);
220 }
221 */
222
223 if(iBCID < 0 || (unsigned)iBCID >= MAX_BCID) return pedestal;
224
225 // Only one bunch train is parameterized. Thus the BCID needs to be mapped
226 // to the first train. The train starts at bcid = 1, thus the '+ 1'.
227 // Bunches without available parameterization will have a value of -9 and a value of 0 is returned.
228 auto bcidInfo = distanceFromHeadOfTrain(iBCID);
229 bool longGap = bcidInfo.first;
230 int bcid = bcidInfo.second + 1;
231
232 if(bcid < 0) return pedestal;
233
234 // The parameterization is done for the dynamic pedestal correction,
235 // i.e. correction = (dynamic_pedestal - pedestal).
236 // Since the return value is expected to be the dynamic_pedestal itself, the
237 // pedestal is added to the value obtained from the parameterization.
238 int correction = 0;
239 if(layer == 0) {
240 correction = std::round((*m_emParameterizations[longGap][iElement][bcid])(mu));
241 } else if(layer == 1) {
242 correction = std::round((*m_hadParameterizations[longGap][iElement][bcid])(mu));
243 } else {
244 ATH_MSG_ERROR("Wrong layer index. Give 0 for Em, 1 for Had.");
245 }
246
247 // Hardware cannot calculate a dynamic pedestal < 0, but it is possible the parameterisation can
248 int dynamic_pedestal = correction + pedestal;
249 if (dynamic_pedestal < 0) dynamic_pedestal = 0;
250
251 return dynamic_pedestal;
252}
253
254// helpers for parsing in anonymous namespace
255namespace {
256 struct Context {
257 enum ParserState {
258 Element,
259 Poly,
260 Exp,
261 BCID
262 } P = Element;
263
264 size_t E = 999;
265 std::vector<size_t> poly;
266 std::vector<size_t> exp;
267 size_t N = 0;
268
269 void reset() {
270 N = 0;
271 E = 999;
272 poly.clear();
273 exp.clear();
274 P = Element;
275 }
276 };
277} // namespace anonymous
278//================ Parse input file ============================================
279// parses the input file @fileName and fills the parameterizations into @params
280// Each file is built out of block with the following format:
281// element [element]
282// poly [BCIDx] [BCID] ...
283// exp [BCIDy] [BCID] ...
284// [BCIDx] [P0(BCIDx)] [P1(BCIDx)] [P2(BCIDx)]
285// .
286// .
287// .
288// [BCIDy] [a0(BCIDy)] [a1(BCIDy)] [a2(BCIDy)]
289//
290// where [] is a placeholder for actual numbers.
291//
292// The fits have the form:
293// poly: F(mu) = P0 + P1 * mu + P2 * mu * mu
294// exp: F(mu) = -a0 * (1 - exp(-a1 * mu)) + a2 * mu
295void L1DynamicPedestalProviderTxt::parseInputFile(const std::string& fileName,
296 std::vector<std::vector<std::unique_ptr<ParamFunc>>>& params)
297{
298 using std::istream_iterator;
299
300 std::ifstream F(fileName);
301 Context ctx;
302
303 // read file line-by-line
304 const std::set<char> whitespaces{'\t',' ','\n','\r'};
305 for(std::string L; std::getline(F, L); ) {
306 while ((!L.empty()) && whitespaces.count(L.back())) L.pop_back();
307 if(L.empty()) continue; // ignore empty lines
308 if(L[0] == '#') continue; // ignore comments
309
310 std::istringstream S(L);
311
312 // parsing
313 if(ctx.P == Context::Element) {
314 // start parsing a new element block
315 std::string C = "";
316 S >> C >> ctx.E;
317 if(C != "element")
318 throw ParseException("got '" + C + "' expected 'element'.");
319 if(ctx.E > s_nElements)
320 throw ParseException("element number (" + std::to_string(ctx.E) + ") out-of-range.");
321
322 ctx.P = Context::Poly; // advance state
323 } else if(ctx.P == Context::Poly) {
324 // start parsing a poly line
325 std::string C = "";
326 S >> C;
327 if(C != "poly") throw ParseException("got '" + C + "' expected 'poly'.");
328 std::copy(istream_iterator<size_t>(S), istream_iterator<size_t>(), std::back_inserter(ctx.poly));
329
330 ctx.P = Context::Exp; // advance state
331 } else if(ctx.P == Context::Exp) {
332 // start parsing a exp line
333 std::string C = "";
334 S >> C;
335 if(C != "exp") throw ParseException("got '" + C + "' expected 'exp'.");
336 std::copy(istream_iterator<size_t>(S), istream_iterator<size_t>(), std::back_inserter(ctx.exp));
337
338 ctx.P = Context::BCID; // advance state
339 } else if(ctx.P == Context::BCID) {
340 size_t B;
341 std::vector<float> P;
342 S >> B; // bcid
343 std::copy(istream_iterator<float>(S), istream_iterator<float>(), back_inserter(P)); // parameters
344 if(P.size() != 3) {
345 throw ParseException("BCID=" + std::to_string(B) +
346 ": expected 3 parameters got " + std::to_string(P.size()));
347 }
348 if(std::binary_search(ctx.poly.begin(), ctx.poly.end(), B)) {
349 params[ctx.E][B] = make_unique<ParamFuncPol2>(P[0], P[1], P[2]);
350 } else if(std::binary_search(ctx.exp.begin(), ctx.exp.end(), B)) {
351 params[ctx.E][B] = make_unique<ParamFuncExp>(P[0], P[1], P[2]);
352 } else {
353 throw ParseException("BCID '" + std::to_string(B) + "' didn't appear in 'poly' or 'exp' for element '" +
354 std::to_string(ctx.E) + "'.");
355 }
356
357 if(++ctx.N == (ctx.poly.size() + ctx.exp.size())) {
358 // all bcids exhausted block is finished
359 if(ctx.N != s_nBCIDPerTrain) {
360 throw ParseException("Not all BCIDs filled");
361 }
362
363 ctx.reset();
364 }
365 }
366 }
367
368 for(auto& V : params) {
369 if(std::find_if(V.begin(), V.end(), [](std::unique_ptr<ParamFunc>& p) { return p == nullptr; }) != V.end()) {
370 throw ParseException("Not all elements and bcids filled!");
371 }
372 }
373}
374
375} // end of namespace LVL1
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
static Double_t P(Double_t *tt, Double_t *par)
#define F(x, y, z)
Definition MD5.cxx:112
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
@ BunchCrossings
Distance in units of 25 nanoseconds.
static constexpr int m_MAX_BCID
bool isFilled(const bcid_type bcid) const
The simplest query: Is the bunch crossing filled or not?
@ MiddleEmpty
An empty BCID in the middle of a train.
virtual double operator()(double mu)=0
void parseInputFile(const std::string &fileName, std::vector< std::vector< std::unique_ptr< ParamFunc > > > &params)
virtual int dynamicPedestal(int iEta, int layer, int pedestal, int iBCID, float mu) const override
retrieve the bcidCorrection value
L1DynamicPedestalProviderTxt(const std::string &, const std::string &, const IInterface *)
constructor
virtual StatusCode initialize() override
standard Athena-Algorithm method
virtual ~L1DynamicPedestalProviderTxt()
default destructor
std::pair< bool, int > distanceFromHeadOfTrain(int bcid) const
std::array< std::vector< std::vector< std::unique_ptr< ParamFunc > > >, 2 > m_emParameterizations
SG::ReadCondHandleKey< BunchCrossingCondData > m_bcDataKey
std::array< std::vector< std::vector< std::unique_ptr< ParamFunc > > >, 2 > m_hadParameterizations
virtual double operator()(double mu)
ParamFuncExp(double p0, double p1, double p2)
ParamFuncPol2(double p0, double p1, double p2)
virtual double operator()(double mu)
static std::string find_file(const std::string &logical_file_name, const std::string &search_path)
std::string tail(std::string s, const std::string &pattern)
tail of a string
std::string head(std::string s, const std::string &pattern)
head of a string
struct color C
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...
cool::Int16 bcid_t