ATLAS Offline Software
Loading...
Searching...
No Matches
LArCellPreparationAlg.cxx
Go to the documentation of this file.
1/*
2 * Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 */
4
5/*
6 This Algorithm simulates the energy encoding of all LAr cells for Global and simulated the truncation of cells
7 from overflowing FEB2s. The hardware-accurate cells are then stored in a GlobalLArCellContainer object within
8 StoreGate
9*/
10
12
14#include "CaloEvent/CaloCell.h"
17
18#include "TMath.h"
19#include <fstream>
20#include <vector>
21#include <cmath>
22
23namespace GlobalSim {
24
25 // Initialize function which defines the parameters of the multilinear energy encoding, calculates the ranges,
26 // determines the maximum number of cells per FEB2 that can be sent to Global and reads the LAr cell map to get
27 // the full list of associated boards and how they are wired to the Global MUXs
29 ATH_MSG_INFO ("Initializing " << name());
30 ATH_MSG_INFO ("Target name of GlobalLArCellContainer is " << m_LArCellContainerKey);
31
32 CHECK(m_eventInfo.initialize());
33 CHECK(m_caloCellsKey.initialize());
34 CHECK(m_LArCellContainerKey.initialize());
35
36 // retrieve ID helper
37 ATH_CHECK(detStore()->retrieve(m_calocell_id, "CaloCell_ID"));
38
39 ATH_CHECK(m_totalNoiseKey.initialize());
40
41 ATH_MSG_INFO("Active energy encoding scheme for LAr cells is " << m_numberOfEnergyBits.value() << " energy bits with " << m_valueLSB.value() << " MeV for the least significant bit and a gain factor of " << m_valueGainFactor.value());
42
43 m_stepsPerRange = std::pow(2,m_numberOfEnergyBits.value()-2);
44
45 m_readoutRanges[0] = 0;
51
52 ATH_MSG_DEBUG("Readout scheme with " << m_numberOfEnergyBits.value() << "-bits provides the following four energy thresholds (with " << m_stepsPerRange << " discrete steps on each threshold)");
53 ATH_MSG_DEBUG("GEP cell energy range 0: min = " << m_readoutRanges[0] << " MeV -> max = " << m_readoutRanges[1] << " MeV");
54 ATH_MSG_DEBUG("GEP cell energy range 1: min = " << m_readoutRanges[1] + m_valueLSB.value() << " MeV -> max = " << m_readoutRanges[2] << " MeV");
55 ATH_MSG_DEBUG("GEP cell energy range 2: min = " << m_readoutRanges[2]+(m_valueGainFactor.value()*m_valueLSB.value()) << " MeV -> max = " << m_readoutRanges[3] << " MeV");
56 ATH_MSG_DEBUG("GEP cell energy range 3: min = " << m_readoutRanges[3]+(m_valueGainFactor.value()*m_valueGainFactor.value()*m_valueLSB.value()) << " MeV -> max = " << m_readoutRanges[4] << " MeV");
57
58 // At the moment only have a detailed scheme for 6-10 bit readouts, thus rejecting any other value
59 switch(m_numberOfEnergyBits.value()) {
60 case 6: m_maxCellsPerFEB = 62; break;
61 case 7: m_maxCellsPerFEB = 54; break;
62 case 8: m_maxCellsPerFEB = 48; break;
63 case 9: m_maxCellsPerFEB = 43; break;
64 case 10: m_maxCellsPerFEB = 39; break;
65 default: ATH_MSG_FATAL("A LAr cell energy encoding scheme with " << m_numberOfEnergyBits.value() << " energy bits is currently not defined");
66 return StatusCode::FAILURE;
67 }
68
69 ATH_MSG_INFO("Loading cell map associating LAr cells to FEB2s");
70
71 std::string cellMapPath = PathResolverFindCalibFile(m_LArCellMap);
72 if(cellMapPath.empty()) ATH_MSG_ERROR("Could not find file with cell map data: " << m_LArCellMap.value());
73
74 std::ifstream file(cellMapPath.c_str());
75
76 unsigned n_cells = 0;
77 m_gblLArCellMap.clear();
78
79 std::map<std::string,Feb2MuxInfo> feb2MuxAssoc;
80
81 // Read input file
82 if (file.is_open()) {
83
84 int online_id, offline_id, channel, con_num, fbr;
85 std::string assocFEB2, con_type, muxname, muxrack, cnnctr, laspname, lasprack;
86
87 // Skipping header of file
88 std::getline(file, assocFEB2);
89
90 // start reading data
91 while (true) {
92
93 file >> offline_id >> online_id >> assocFEB2 >> channel >> con_type >> con_num >> fbr >> muxname >> muxrack >> cnnctr >> laspname >> lasprack;
94
95 if (file.eof()) break;
96
97 GlobalSim::GlobalLArCell gblLArCell(offline_id, assocFEB2, channel);
98 gblLArCell.setBoardConnector(cnnctr, con_type, con_num, fbr);
99 gblLArCell.setMUX(muxname);
100 gblLArCell.setLASP(laspname);
101
102 m_gblLArCellMap.insert(std::pair<int, GlobalSim::GlobalLArCell>(offline_id, gblLArCell));
103
104 int indexOnMux = fbr;
105 if (cnnctr == "B") indexOnMux += 24;
106 if (cnnctr == "C") indexOnMux += 32;
107
108 // Add FEB2 to MUX association map
109 auto itr = feb2MuxAssoc.find(assocFEB2);
110 if (itr == feb2MuxAssoc.end()) {
111 feb2MuxAssoc.insert(std::pair<std::string,Feb2MuxInfo>(assocFEB2, {muxname, indexOnMux}));
112 }
113
114 ++n_cells;
115 }
116 }
117 else {
118 ATH_MSG_ERROR("Could not open file containing the cell to FEB2 association");
119 return StatusCode::FAILURE;
120 }
121
122 ATH_MSG_DEBUG("Loaded FEB2 information for " << n_cells << " LAr cells");
123
124 // Constructing the GlobalLArCellContainer
125 m_gblLArCellContainerTemplate = std::make_unique<GlobalSim::GlobalLArCellContainer>(feb2MuxAssoc);
127
128 return StatusCode::SUCCESS;
129 }
130
131
132 // Read in a CaloCell container, encode the cell energy according to the active encoding scheme, perform
133 // the FEB2 truncation and then store all cells which would be sent to Global in a GlobalLArCellContainer
134 StatusCode LArCellPreparationAlg::execute(const EventContext& ctx) const {
135
136 ATH_MSG_DEBUG ("Executing LArCellPreparationAlg algorithm");
137
139 CHECK(eventInfo.isValid());
140
141 // Read in container containing calorimeter cells
142 auto h_caloCells = SG::makeHandle(m_caloCellsKey, ctx);
143 CHECK(h_caloCells.isValid());
144 const auto & cells = *h_caloCells;
145
146 ATH_MSG_DEBUG("Reading " << std::to_string(h_caloCells->size()) << " cells in input cell container");
147
149 if (!totalNoiseHdl.isValid()) {return StatusCode::FAILURE;}
150 const CaloNoise* totalNoiseCDO = *totalNoiseHdl;
151
152 std::map<std::string,std::vector<GlobalSim::GlobalLArCell>> gblLArCellsPerFEB2;
153
154 // Set up a GlobalLArCellContainer from template
156 auto gblLArCellContainer = std::make_unique<GlobalSim::GlobalLArCellContainer>(templateRef);
157
158 for(const auto *cell: cells){
159
160 int cell_id = (cell->ID().get_identifier32()).get_compact();
161
162 auto gblLArCell_itr = m_gblLArCellMap.find(cell_id);
163 if (gblLArCell_itr == m_gblLArCellMap.end()) continue;
164
165 //Fill a map with the cell location -> Cell ID
166 if(cell->caloDDE()->getSampling() == 1 || cell->caloDDE()->getSampling() == 5){
167 gblLArCellContainer->fillLocToIDMap(cell->ID(), cell);
168 }
169 GlobalSim::GlobalLArCell gblLArCell = gblLArCell_itr->second;
170
171 float totalNoise = totalNoiseCDO->getNoise(cell->ID(), cell->gain());
172 float sigma = cell->energy() / totalNoise;
173
174 // Only send positive-energy 2sigma cells to the GEP
175 if (sigma < 2.0) continue;
176
177 if (cell->badcell()) continue;
178
179 std::pair<float, boost::dynamic_bitset<>> gep_energy = encodeEnergy(cell->energy() / TMath::CosH(cell->eta()));
180
181 gblLArCell.setEnergy(gep_energy.first, std::move(gep_energy.second));
182 gblLArCell.setSigma(sigma);
183 gblLArCell.setPosition(cell->eta(), cell->phi());
184 gblLArCell.setSize(cell->caloDDE()->deta(), cell->caloDDE()->dphi());
185 gblLArCell.setSampling(cell->caloDDE()->getSampling());
186 gblLArCell.setLayer(cell->caloDDE()->getLayer());
187
188 // Fill cells into map according to FEB
189 auto feb2_itr = gblLArCellsPerFEB2.find(gblLArCell.getFEB2());
190 if (feb2_itr != gblLArCellsPerFEB2.end()) feb2_itr->second.push_back(std::move(gblLArCell));
191 else {
192 std::vector<GlobalSim::GlobalLArCell> cellsThisFEB(1, gblLArCell);
193 gblLArCellsPerFEB2.insert(std::pair<std::string,std::vector<GlobalSim::GlobalLArCell>>(gblLArCell.getFEB2(),cellsThisFEB));
194 }
195 }
196
197 // do truncation
198 for (auto& [feb2Name, cells] : gblLArCellsPerFEB2) {
199
200 // Overflow and error flags
201 bool inOverflow = false;
202 bool inError = false;
203
204 // LAr FEBs might overflow, so they will get truncated
205 if (cells.size() > m_maxCellsPerFEB) {
206 ATH_MSG_INFO("FEB " << feb2Name << " is sending " << cells.size() << " cells, which is more cells than GEP can receive. Removing all but the possible " << m_maxCellsPerFEB << " cells.");
208 inOverflow = true;
209 }
210
211 for (auto& gblLArCell : cells){
212 IdentifierHash hashId=m_calocell_id->calo_cell_hash(static_cast<Identifier>(gblLArCell.getID()));
213 gblLArCellContainer->push_back(std::move(gblLArCell),hashId);
214 }
215
216 gblLArCellContainer->setFeb2Flags(feb2Name, inOverflow, inError);
217 }
218 ATH_MSG_DEBUG("Global is receiving a total of " << gblLArCellContainer->size() << " LAr cells in this event");
219
221 ATH_CHECK( h_gblLArCellContainer.record( std::move(gblLArCellContainer) ) );
222
223 return StatusCode::SUCCESS;
224 }
225
226
227 // Function to emulate the hardware realistic energy of the cell by applying the
228 // multilinear energy encoding scheme defined in the initialize function and at
229 // the same time building the bitstring encoding the energy
230 std::pair<float,boost::dynamic_bitset<>> LArCellPreparationAlg::encodeEnergy(float energy) const {
231
232 // Negative energy cell
233 if (energy < 0) return std::pair<float,boost::dynamic_bitset<>>(0.0,boost::dynamic_bitset<>(m_numberOfEnergyBits.value(),0));
234
235 // Saturated cell
236 if (energy > m_readoutRanges[4]) {
237 int max_value = ( m_stepsPerRange + m_stepsPerRange*m_valueGainFactor.value() +
240 return std::pair<float,boost::dynamic_bitset<>>(max_value,boost::dynamic_bitset<>(m_numberOfEnergyBits.value(),std::pow(2,m_numberOfEnergyBits.value())-1));
241 }
242
243 int range = 0;
244 for (int i = 1; i <= 3; ++i) {
245 if (energy > m_readoutRanges[i]) range = i;
246 }
247
248 float step = ((float) m_readoutRanges[range+1] - (float) m_readoutRanges[range]) / m_stepsPerRange;
249
250 float encoded_energy = -1;
251 int used_steps = 0;
252 for (int i = 0; i < m_stepsPerRange; ++i) {
253 encoded_energy = m_readoutRanges[range]+(step*i);
254 used_steps = i;
255 if (energy < (m_readoutRanges[range]+(step*(i+1)))) break;
256 }
257
258 std::size_t n_bitsE = m_numberOfEnergyBits.value() - 2;
259 boost::dynamic_bitset<> energy_bits(m_numberOfEnergyBits.value(), used_steps);
260 energy_bits |= boost::dynamic_bitset<>(m_numberOfEnergyBits.value(), static_cast<unsigned long>(range) << n_bitsE);
261
262 return std::pair<float,boost::dynamic_bitset<>>(encoded_energy,energy_bits);
263 }
264
265
266 // Function to find FEB2s which have more 2sigma cells in this event than the available
267 // latency allows to send and truncates overflowing cells
268 StatusCode LArCellPreparationAlg::removeCellsFromOverloadedFEB(std::vector<GlobalSim::GlobalLArCell> &cells) const {
269
270 // Sort cells by channel
271 std::sort(cells.begin(), cells.end(), [](const auto& a, const auto& b) {
272 return a.getChannel() < b.getChannel(); });
273
274 // Remove overflowing cells from vector
275 if (cells.size() > m_maxCellsPerFEB)
276 cells.erase(std::next(cells.begin(), m_maxCellsPerFEB), cells.end());
277
278 return StatusCode::SUCCESS;
279 }
280
281} // namespace GlobalSim
282
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_DEBUG(x)
#define CHECK(...)
Evaluate an expression and check for errors.
static Double_t a
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
const ServiceHandle< StoreGateSvc > & detStore() const
float getNoise(const IdentifierHash h, const int gain) const
Accessor by IdentifierHash and gain.
Definition CaloNoise.h:35
void setEnergy(float energy)
copy & move c'tor, assignment, and destructor are automatically generated
void setSampling(int sampling)
set sampling of cell
void setBoardConnector(std::string connector, std::string type, int number, int fiber)
set properties of associated board connector
void setMUX(std::string muxname)
set name of associated MUX
void setSigma(float sigma)
set significancy of energy deposit
void setSize(float deta, float dphi)
set size of cell in eta-phi space
void setLASP(std::string laspname)
set name of associated LASP
void setLayer(int layer)
set layer of cell
const std::string & getFEB2() const
get the name of the FEB2 this cell is associated with
void setPosition(float eta, float phi)
set position of cell in eta-phi space
virtual StatusCode execute(const EventContext &) const override
execute function running for every event
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo
Key for the EventInfo object.
Gaudi::Property< int > m_numberOfEnergyBits
Parameters defining the multilinear energy encoding scheme.
Gaudi::Property< std::string > m_LArCellMap
Path to the LAr cell map in the CVMFS GroupData space.
std::pair< float, boost::dynamic_bitset<> > encodeEnergy(float energy) const
Function to simulate the cell energy as seen by Global.
std::map< int, GlobalSim::GlobalLArCell > m_gblLArCellMap
LAr cell map where the key is the offline cell ID.
virtual StatusCode initialize() override
initialize function running before first event
int m_readoutRanges[5]
array holding the energy edges of the multilinear encoding
int m_stepsPerRange
number of discrete values per multilinear energy encoding range
StatusCode removeCellsFromOverloadedFEB(std::vector< GlobalSim::GlobalLArCell > &cells) const
Function to simulate the truncation of overflowing FEB2s.
std::unique_ptr< GlobalSim::GlobalLArCellContainer > m_gblLArCellContainerTemplate
GlobalLArCellContainer template which is constructed in initialize and used in execute.
SG::ReadCondHandleKey< CaloNoise > m_totalNoiseKey
Key to the total noise used for each CaloCell.
unsigned m_maxCellsPerFEB
maximum number of cells that can be send to Global for each FEB2
SG::ReadHandleKey< CaloCellContainer > m_caloCellsKey
Key to the CaloCell container.
SG::WriteHandleKey< GlobalSim::GlobalLArCellContainer > m_LArCellContainerKey
Key to writing the GlobalLArCellContainer to StoreGate.
This is a "hash" representation of an Identifier.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
AlgTool to read in LArStripNeighborhoods, and run the eRatio Algorithm.
SG::ReadCondHandle< T > makeHandle(const SG::ReadCondHandleKey< T > &key, const EventContext &ctx=Gaudi::Hive::currentContext())
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
TFile * file