ATLAS Offline Software
Loading...
Searching...
No Matches
SCEmulation.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "SCEmulation.h"
11#include <memory>
12#include <TFile.h>
13#include <TKey.h>
14#include <TRandom3.h>
15#include <regex>
16#include <set>
17#include <algorithm>
18#include <limits>
19#include <random>
20#include <cstring>
21
22namespace
23{
31 std::size_t getIndex(const std::vector<float> &bins, float value)
32 {
33 auto itr = std::upper_bound(bins.begin(), bins.end(), value);
34 // upper_bound returns an iterator to the first value larger than value
35 // If begin is returned, then value is below the lowest bin edge,
36 // If end is returned, then value is above the highest bin edge
37 if (itr == bins.end())
38 return SIZE_MAX;
39 if (itr == bins.begin())
40 return 0;
41 return std::distance(bins.begin(), itr) - 1;
42 }
43
45 float getRandom(const std::map<float, float> &integrals, std::mt19937_64 &generator)
46 {
47 // The integrals are essentially a binned cdf (though not necessarily properly normalised)
48 // We invert this by constructing a random number uniformly distributed between the
49 // minimum and maximum values of the cumulative integral (the keys of the map).
50 // This allows us to locate the correct bin
51 // The values in the map then correspond to upper edges of each bin, so we can get the
52 // pair of edges from the iterator found by lower_bound and the previous one.
53 // We then perform a simple linear interpolation using how far the random number is into the cdf bin
54 // to approximate the timing to be returned
55 float start = integrals.begin()->first;
56 float end = integrals.rbegin()->first;
57 std::uniform_real_distribution<float> distr(start, end);
58 float r = distr(generator);
59 auto itr = integrals.lower_bound(r);
60 if (itr == integrals.end() || itr == integrals.begin())
61 {
62 // This should never be triggered
63 return -1;
64 }
65 float lowBinEdge, lowBinValue, highBinEdge, highBinValue;
66 std::tie(highBinEdge, highBinValue) = *itr;
67 std::tie(lowBinEdge, lowBinValue) = *(--itr);
68 // Interpolate between the two bin edges
69 float pctDiff = (r - lowBinEdge) / (highBinEdge - lowBinEdge);
70 return lowBinValue + pctDiff * (highBinValue - lowBinValue);
71 }
72} // namespace
73
74namespace LVL1
75{
76 SCEmulation::SCEmulation(const std::string &name, ISvcLocator *pSvcLocator)
77 : AthReentrantAlgorithm(name, pSvcLocator)
78 {
79 declareProperty("InputCells", m_inputCellsKey = "AllCalo");
80 declareProperty("OutputSuperCells", m_outputSuperCellsKey = "SCEmulationNoBCId");
81 declareProperty("EventInfo", m_evtInfoKey = "EventInfo");
82 declareProperty("SCIDTool", m_scidTool);
83 declareProperty("CompensateForNoise", m_useNoise = true);
84 declareProperty("CompensateForBCID", m_useBCID = true);
85 declareProperty("CellTimingFile", m_cellTimingFile = "Run3L1CaloSimulation/SuperCells/CellTimingDistributions.MiddleTrain.r11881.20210211.root");
86 }
87
89
91 {
92 ATH_MSG_INFO("Initializing " << name() << "...");
93 ATH_CHECK(m_evtInfoKey.initialize());
94 ATH_CHECK(m_scidTool.retrieve());
95 ATH_CHECK(m_inputCellsKey.initialize());
96 ATH_CHECK(m_outputSuperCellsKey.initialize());
99
100 ATH_CHECK(m_caloSuperCellMgrKey.initialize());
101 ATH_CHECK(detStore()->retrieve(m_caloIdMgr));
102
103 std::unique_ptr<TFile> timingFile(TFile::Open(PathResolver::find_calib_file(m_cellTimingFile).c_str()));
104 ATH_MSG_INFO("...");
105 if (!timingFile || timingFile->IsZombie())
106 {
107 ATH_MSG_ERROR("Failed to open cell timing file " << m_cellTimingFile);
108 return StatusCode::FAILURE;
109 }
110 TDirectory *tdir = timingFile->GetDirectory("CellTiming");
111 if (!tdir)
112 {
113 ATH_MSG_ERROR(m_cellTimingFile << " has no CellTiming directory!");
114 return StatusCode::FAILURE;
115 }
116
117 // Regex pattern for histogram names
118 std::regex pattern("Layer(\\d+)_([\\d.]+)eta([\\d.]+)_([\\d.-]+)ET([\\d.-]+)_midtrain");
119 std::map<CaloSampling::CaloSample, std::set<std::pair<float, float>>> etaBins;
120 std::map<CaloSampling::CaloSample, std::set<std::pair<float, float>>> etBins;
121 std::map<CaloSampling::CaloSample, std::map<std::pair<std::pair<float, float>, std::pair<float, float>>, TH1F *>> tmpHistMap;
122 std::set<CaloSampling::CaloSample> samples;
123 for (TObject *obj : *tdir->GetListOfKeys())
124 {
125 TKey *key = dynamic_cast<TKey *>(obj);
126 if (!key)
127 {
128 ATH_MSG_ERROR(obj->GetName() << " is not a TKey");
129 return StatusCode::FAILURE;
130 }
131 std::cmatch match;
132 if (!std::regex_match(key->GetName(), match, pattern))
133 {
134 continue;
135 }
136 if (std::strcmp(key->GetClassName(), "TH1F") != 0)
137 {
138 ATH_MSG_ERROR("Object " << key->GetName() << " not histogram as expected!");
139 return StatusCode::FAILURE;
140 }
141 CaloSampling::CaloSample sample = static_cast<CaloSampling::CaloSample>(std::stoi(match.str(1)));
142 samples.insert(sample);
143
144 auto etaBin = std::make_pair(std::stof(match.str(2)), std::stof(match.str(3)));
145 auto etBin = std::make_pair(std::stof(match.str(4)), std::stof(match.str(5)));
146
147 etaBins[sample].insert(etaBin);
148 etBins[sample].insert(etBin);
149 tmpHistMap[sample][std::make_pair(etaBin, etBin)] = (TH1F *)key->ReadObj();
150 }
151 // Now regularise the binning
152 for (CaloSampling::CaloSample sample : samples)
153 {
154 auto itr = etaBins[sample].begin();
155 auto end = etaBins[sample].end();
156 m_etaBins[sample].reserve(std::distance(itr, end) + 1);
157 m_etaBins[sample].push_back(itr->first);
158 m_etaBins[sample].push_back(itr->second);
159 ++itr;
160 for (; itr != end; ++itr)
161 {
162 // Make sure that the bin edges match up
163 if (itr->first != m_etaBins[sample].back())
164 {
165 ATH_MSG_ERROR("Eta bins do not match up for sample " << sample << "(" << m_etaBins[sample].back() << ", " << itr->first << ")");
166 return StatusCode::FAILURE;
167 }
168 m_etaBins[sample].push_back(itr->second);
169 }
170
171 itr = etBins[sample].begin();
172 end = etBins[sample].end();
173 m_etBins[sample].reserve(std::distance(itr, end) + 1);
174 m_etBins[sample].push_back(itr->first);
175 m_etBins[sample].push_back(itr->second);
176 ++itr;
177 for (; itr != end; ++itr)
178 {
179 // Make sure that the bin edges match up
180 if (itr->first != m_etBins[sample].back())
181 {
182 ATH_MSG_ERROR("Et bins do not match up for sample " << sample);
183 return StatusCode::FAILURE;
184 }
185 m_etBins[sample].push_back(itr->second);
186 }
187
188 // Now copy the histograms over
189 for (const auto &p : tmpHistMap[sample])
190 {
191 // Use the lower bounds of each bins to get the index
192 std::size_t etaIndex = getEtaIndex(sample, p.first.first.first);
193 std::size_t etIndex = getEtIndex(sample, p.first.second.first);
194 auto mapKey = std::make_tuple(sample, etaIndex, etIndex);
195 std::map<float, float> &integrals = m_timingSamples[mapKey];
196 float cumulativeSum = 0;
197 TAxis *axis = p.second->GetXaxis();
198 integrals[cumulativeSum] = axis->GetBinLowEdge(1);
199 for (int idx = 1; idx < axis->GetNbins(); ++idx)
200 {
201 cumulativeSum += p.second->GetBinContent(idx);
202 integrals[cumulativeSum] = axis->GetBinUpEdge(idx);
203 }
204 }
205 }
206 return StatusCode::SUCCESS;
207 }
208
209 StatusCode SCEmulation::execute(const EventContext &ctx) const
210 {
211 // Prepare output container
212 auto superCells = std::make_unique<CaloCellContainer>();
213 // Get input
214 auto cells = SG::makeHandle(m_inputCellsKey, ctx);
215 if (!cells.isValid())
216 {
217 ATH_MSG_ERROR("Failed to retrieve input cells " << m_inputCellsKey.key());
218 return StatusCode::FAILURE;
219 }
220
221 const CaloBCIDAverage *caloBCIDAvg = nullptr;
222 const CaloNoiseSigmaDiff *caloNoiseSigmaDiff = nullptr;
223 if (m_useBCID)
224 {
225 auto handle = SG::makeHandle(m_caloBCIDAverageKey, ctx);
226 if (!handle.isValid())
227 {
228 ATH_MSG_ERROR("Failed to retrieve " << m_caloBCIDAverageKey);
229 return StatusCode::FAILURE;
230 }
231 caloBCIDAvg = handle.cptr();
232 }
233 if (m_useNoise)
234 {
236 if (!handle.isValid())
237 {
238 ATH_MSG_ERROR("Failed to retrieve " << m_caloNoiseSigmaDiffKey);
239 return StatusCode::FAILURE;
240 }
241 caloNoiseSigmaDiff = handle.cptr();
242 }
243
245 const CaloSuperCellDetDescrManager* scellMgr = *caloSuperCellMgrHandle;
246
247 auto evtInfo = SG::makeHandle(m_evtInfoKey, ctx);
248 if (!evtInfo.isValid())
249 {
250 ATH_MSG_ERROR("Failed to retrieve " << m_evtInfoKey.key());
251 return StatusCode::FAILURE;
252 }
253 std::mt19937_64 generator;
254 // seed the generator for the whole event
255 generator.seed(evtInfo->eventNumber() * evtInfo->runNumber());
256
257 const CaloCell_SuperCell_ID *superCellIDHelper = m_caloIdMgr->getCaloCell_SuperCell_ID();
258 const TileID *tileCellID = m_caloIdMgr->getTileID();
259 const Tile_SuperCell_ID *tileSuperCellID = m_caloIdMgr->getTile_SuperCell_ID();
260 const CaloCell_ID *caloCellID = m_caloIdMgr->getCaloCell_ID();
261
262 // Prepare the output values
263 std::size_t nSuperCells = superCellIDHelper->calo_cell_hash_max();
264 std::vector<float> energies(nSuperCells, 0.0);
265 std::vector<float> enTime(nSuperCells, 0.0);
266 std::vector<float> enForTime(nSuperCells, 0.0);
267 std::vector<char> timeDef(nSuperCells, false);
268 std::vector<uint16_t> qualities(nSuperCells, 0);
269 std::vector<float> sigmaNoisePerSuperCell(nSuperCells, 0.0);
270
271 for (const CaloCell *cell : *cells)
272 {
273 Identifier cellID = cell->ID();
274 IdentifierHash cellIDHash = caloCellID->calo_cell_hash(cellID);
275 // map to super cell ID
276 Identifier superCellID = m_scidTool->offlineToSuperCellID(cellID);
277 const CaloDetDescrElement *cdde = cell->caloDDE();
278 if (!superCellID.is_valid())
279 {
280 continue;
281 }
282 IdentifierHash scIDHash = superCellIDHelper->calo_cell_hash(superCellID);
283 float energy = cell->energy();
284 if (m_useBCID)
285 energy += caloBCIDAvg->average(cellID);
286 energies[scIDHash] += energy;
287 if (m_useNoise && !cdde->is_tile() && cell->gain() == CaloGain::LARHIGHGAIN)
288 sigmaNoisePerSuperCell[scIDHash] += (*caloNoiseSigmaDiff)[cellIDHash];
289
290 // This is a bad definition, but it's needed to be consistent with the other code (for now...)
291 CaloSampling::CaloSample s = cell->caloDDE()->getSampling();
292 bool isTile_BAD = s >= 9 && s < 21;
293 if (cell->provenance() & 0x2000)
294 {
295 if (cell->energy() > 256)
296 {
297 // We have the timing values correctly for above 256
298 timeDef[scIDHash] |= true;
299 enForTime[scIDHash] += cell->energy();
300 enTime[scIDHash] += cell->energy() * cell->time();
301 }
302 else if (!isTile_BAD)
303 {
304 // Use the random sampling from timing histograms (only midtrain)
305
306 CaloSampling::CaloSample sample = cell->caloDDE()->getSampling();
307 // Locate the correct eta/et bins
308 std::size_t iEta = getEtaIndex(sample, std::abs(cell->eta()));
309 if (iEta == SIZE_MAX)
310 {
311 ATH_MSG_ERROR("Eta value " << cell->eta() << " for sampling " << sample << " does not fall in a bin");
312 return StatusCode::FAILURE;
313 }
314 std::size_t iEt = getEtIndex(sample, cell->et());
315 if (iEt == SIZE_MAX)
316 {
317 ATH_MSG_ERROR("Et value " << cell->et() << " for sampling " << sample << " does not fall in a bin");
318 return StatusCode::FAILURE;
319 }
320 float cellTime = getRandom(m_timingSamples.at(std::make_tuple(sample, iEta, iEt)), generator);
321 timeDef.at(scIDHash) |= true;
322 enForTime.at(scIDHash) += cell->energy();
323 enTime.at(scIDHash) += cell->energy() * cellTime;
324 }
325 } //> if (provenance & 0x2000)
326 uint16_t &quality = qualities.at(scIDHash);
327 // Add the qualities such that you don't overflow the storage
328 if ((std::numeric_limits<uint16_t>::max() + 1 - quality) < cell->quality())
329 quality = std::numeric_limits<uint16_t>::max();
330 else
331 quality += cell->quality();
332 //ATH_MSG_INFO("Quality is " << quality);
333 // Special case for SAMP_D in tile. The signal is split into two SCs
334 if (cdde->is_tile() && tileCellID->sampling(cellID) == TileID::SAMP_D)
335 {
336 int section = tileCellID->section(cellID);
337 int side = tileCellID->side(cellID);
338 int module = tileCellID->module(cellID);
339 int tower = tileCellID->tower(cellID);
340
341 // Get the parameters for the new SCs
342 int section1 = section;
343 int section2 = section;
344 int side1 = side;
345 int side2 = side;
346 int tower1 = tower;
347 int tower2 = tower - 1;
348 if (tower == 0)
349 {
350 side1 = -1;
351 side2 = 1;
352 tower1 = 0;
353 tower2 = 0;
354 }
355 else if (tower == 10)
356 {
357 section1 = TileID::EXTBAR;
358 section2 = TileID::BARREL;
359 }
360
361 Identifier scID1 = tileSuperCellID->cell_id(section1, side1, module, tower1, 0);
362 Identifier scID2 = tileSuperCellID->cell_id(section2, side2, module, tower2, 0);
363
364 // Split the energy between the SCs
365 energies.at(superCellIDHelper->calo_cell_hash(scID1)) += cell->energy() * 0.5;
366 energies.at(superCellIDHelper->calo_cell_hash(scID2)) += cell->energy() * 0.5;
367 }
368 } //> end loop over cells
369
370 for (std::size_t idx = 0; idx < energies.size(); ++idx)
371 {
372 const CaloDetDescrElement *dde = scellMgr->get_element(idx);
373 if (!dde)
374 {
375 ATH_MSG_WARNING("Invalid DDE for hash index " << idx);
376 continue;
377 }
378 // Only push LAr supercells
380 bool isTile_BAD = s >= 9 && s < 21;
381 if (isTile_BAD)
382 continue;
383 float energy = energies.at(idx);
384 float sigmaNoise = sigmaNoisePerSuperCell.at(dde->calo_hash());
385 if (!dde->is_tile() && sigmaNoise > 0.0)
386 {
387 std::normal_distribution<double> distribution(0.0, sigmaNoise);
388 energy += distribution(generator);
389 }
390 auto superCell = std::make_unique<CaloCell>();
391 superCell->setCaloDDE(dde);
392 superCell->setEnergy(energy);
393 uint16_t prov = 0;
394 if (timeDef.at(idx) && enForTime.at(idx) != 0)
395 {
396 float time = enTime.at(idx) / enForTime.at(idx);
397 superCell->setTime(time);
398 float et = superCell->et();
399 prov = 0x2000;
400 if ((et > 10e3 && time > -8 && time < 18) || (et <= 10e3 && std::abs(time) < 8))
401 prov |= 0x200;
402 }
403 else
404 superCell->setTime(999.0);
405 superCell->setProvenance(prov);
406 superCell->setGain(CaloGain::LARHIGHGAIN);
407 superCells->push_back(superCell.release());
408 }
409 auto superCellHandle = SG::makeHandle(m_outputSuperCellsKey, ctx);
410 ATH_CHECK(superCellHandle.record(std::move(superCells)));
411 return StatusCode::SUCCESS;
412 }
413
415 {
416 return getIndex(m_etaBins.at(sample), eta);
417 }
418
419 std::size_t SCEmulation::getEtIndex(CaloSampling::CaloSample sample, float et) const
420 {
421 return getIndex(m_etBins.at(sample), et);
422 }
423} // namespace LVL1
Scalar eta() const
pseudorapidity method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
Helper class for offline supercell identifiers.
std::vector< float > CaloNoiseSigmaDiff
NAME : CaloNoiseSigmaDiff.h PACKAGE : Calorimeter/CaloConditions.
static const std::vector< std::string > bins
static const std::vector< std::string > qualities
Handle class for reading from StoreGate.
Handle class for recording to StoreGate.
void section(const std::string &sec)
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
const ServiceHandle< StoreGateSvc > & detStore() const
An algorithm that can be simultaneously executed in multiple threads.
float average(const Identifier &id) const
size_type calo_cell_hash_max() const
cell 'global' hash table max size
IdentifierHash calo_cell_hash(const Identifier cellId) const
create hash id from 'global' cell id
Helper class for offline cell identifiers.
Definition CaloCell_ID.h:34
Helper class for offline supercell identifiers.
Data object for each calorimeter readout cell.
Definition CaloCell.h:57
This class groups all DetDescr information related to a CaloCell.
CaloCell_ID::CaloSample getSampling() const
cell sampling
const CaloDetDescrElement * get_element(const Identifier &cellId) const
get element by its identifier
This is a "hash" representation of an Identifier.
bool is_valid() const
Check if id is in a valid state.
SG::ReadCondHandleKey< CaloNoiseSigmaDiff > m_caloNoiseSigmaDiffKey
Definition SCEmulation.h:42
SG::ReadHandleKey< xAOD::EventInfo > m_evtInfoKey
Definition SCEmulation.h:39
std::size_t getEtaIndex(CaloSampling::CaloSample sample, float eta) const
virtual StatusCode execute(const EventContext &ctx) const override
std::map< CaloSampling::CaloSample, std::vector< float > > m_etaBins
eta binning read from timing file
Definition SCEmulation.h:60
virtual ~SCEmulation() override
SG::ReadHandleKey< CaloBCIDAverage > m_caloBCIDAverageKey
Definition SCEmulation.h:40
SG::ReadCondHandleKey< CaloSuperCellDetDescrManager > m_caloSuperCellMgrKey
Super cell manager key.
Definition SCEmulation.h:45
std::map< std::tuple< CaloSampling::CaloSample, std::size_t, std::size_t >, std::map< float, float > > m_timingSamples
Timing distributions.
Definition SCEmulation.h:65
SG::WriteHandleKey< CaloCellContainer > m_outputSuperCellsKey
Definition SCEmulation.h:47
const CaloIdManager * m_caloIdMgr
Calo ID helpers.
Definition SCEmulation.h:68
virtual StatusCode initialize() override
std::size_t getEtIndex(CaloSampling::CaloSample sample, float et) const
SG::ReadHandleKey< CaloCellContainer > m_inputCellsKey
Definition SCEmulation.h:38
bool m_useBCID
Compensate for BCIDs.
Definition SCEmulation.h:54
SCEmulation(const std::string &name, ISvcLocator *pSvcLocator)
std::string m_cellTimingFile
The cell timing file.
Definition SCEmulation.h:56
ToolHandle< ICaloSuperCellIDTool > m_scidTool
Offline<->supercell mapping tool.
Definition SCEmulation.h:50
bool m_useNoise
Use noise values.
Definition SCEmulation.h:52
std::map< CaloSampling::CaloSample, std::vector< float > > m_etBins
Et binning read from timing file.
Definition SCEmulation.h:62
static std::string find_calib_file(const std::string &logical_file_name)
const_pointer_type cptr()
Helper class for TileCal offline identifiers.
Definition TileID.h:67
int tower(const Identifier &id) const
Identifier cell_id(const Identifier &any_id) const
int side(const Identifier &id) const
int section(const Identifier &id) const
int sampling(const Identifier &id) const
Helper class for Tile offline identifiers for supercells.
int r
Definition globals.cxx:22
bool match(std::string s1, std::string s2)
match the individual directories of two strings
Definition hcg.cxx:357
@ LARHIGHGAIN
Definition CaloGain.h:18
eFexTowerBuilder creates xAOD::eFexTowerContainer from supercells (LATOME) and triggerTowers (TREX) i...
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
Extra patterns decribing particle interation process.