ATLAS Offline Software
Loading...
Searching...
No Matches
LArR4ElecCalibCalculator.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6
7#include <chai/Container.h>
8#include <chai/Database.h>
9#include <chai/Iov.h>
10#include <chai/Log.h>
11#include <chai/PayloadSpec.h>
12#include <chai/Types.h>
13
15#include "CaloDetDescr/CaloDetDescrElement.h"
24
25namespace {
26
27// Method to convert coral::Blob to BlobData
28chai::BlobData vecToBlobData(const std::vector<float>& input) {
29 const std::size_t size = input.size() * sizeof(float);
30 const void* inPtr = input.data();
31 // Create vector and copy data
32 std::vector<uint8_t> bytes(size);
33 if (size > 0) {
34 memcpy(bytes.data(), inPtr, size);
35 }
36
37 return chai::BlobData(std::move(bytes));
38}
39} // namespace
40
42
43 ATH_CHECK(detStore()->retrieve(m_onlineHelper, "LArOnlineID"));
44 ATH_CHECK(detStore()->retrieve(m_caloCellID, "CaloCell_ID"));
45
46 ATH_CHECK(m_cablingKey.initialize());
47
48 ATH_CHECK(m_lAruA2MeVKey.initialize());
49 ATH_CHECK(m_lArDAC2uAKey.initialize());
50 ATH_CHECK(m_mcSym.initialize());
51
52 ATH_CHECK(m_caloMgrKey.initialize());
53
54 return StatusCode::SUCCESS;
55}
56
57// ********************** EXECUTE ****************************
58StatusCode LArR4ElecCalibCalculator::execute(const EventContext& /*ctx*/) {
59 return StatusCode::SUCCESS;
60}
61
62// ********************** FINALIZE ****************************
64
65 // Values below are mA, in the lower gain
66 const std::map<CaloSampling::CaloSample, float> dynRange{
67 {CaloSampling::PreSamplerB, 2},
68 {CaloSampling::EMB1, 2},
69 {CaloSampling::EMB2, 10},
70 {CaloSampling::EMB3, 10},
71 {CaloSampling::PreSamplerE, 2},
72 {CaloSampling::EME1, 2},
73 {CaloSampling::EME2, 10},
74 {CaloSampling::EME3, 10},
75 {CaloSampling::HEC0, 2},
76 {CaloSampling::HEC1, 2},
77 {CaloSampling::HEC2, 2},
78 {CaloSampling::HEC3, 2,},
79 {CaloSampling::FCAL0, 10},
80 {CaloSampling::FCAL1, 10},
81 {CaloSampling::FCAL2, 10},
82 };
83
84 // Values are in ADC counts in HIGH gain
85 // Structure: maps of samplings < vector <eta-boundary,value> >
86 const std::map<CaloSampling::CaloSample, std::vector<std::pair<float, float> > > noiseMap{
87 {CaloSampling::PreSamplerB, {{5, 3.2}}},
88 {CaloSampling::EMB1, {{0.8, 1.8}, {5, 2.1}}},
89 {CaloSampling::EMB2, {{0.8, 1.4}, {5, 1.7}}},
90 {CaloSampling::EMB3, {{0.8, 1.4}, {5, 1.7}}},
91 {CaloSampling::PreSamplerE, {{5, 3.5}}},
92 {CaloSampling::EME1, {{2, 2.7}, {5, 2.9}}},
93 {CaloSampling::EME2, {{2, 1.3}, {5, 1.5}}},
94 {CaloSampling::EME3, {{2, 1.3}, {5, 1.5}}},
95 {CaloSampling::HEC0, {{5, 3.1}}},
96 {CaloSampling::HEC1, {{5, 3.1}}},
97 {CaloSampling::HEC2, {{5, 2.1}}},
98 {CaloSampling::HEC3, {{5, 2.1}}},
99
100 {CaloSampling::FCAL0, {{5, 4.3}}},
101 {CaloSampling::FCAL1, {{5, 4.6}}},
102 {CaloSampling::FCAL2, {{5, 4.5}}},
103 };
104
109
111
112 std::unique_ptr<LArRampMC> rampMC = std::make_unique<LArRampMC>();
113 ATH_CHECK(rampMC->setGroupingType("Single", msg()));
114 ATH_CHECK(rampMC->initialize());
115
116 const auto& symIDs = larMCsymHdl->symIds();
117
118 const int nUsableBits = int(pow(2, m_nADCBits) * 3 / 4.);
119
120
121 //Calculate the R4 ramps (ADC2DAC) values, store them in run 1/2/3 style objects (LArRampMC)
122 //Can be stored in COOL-reference POOL files if the RegistrationSvc and OutptuConditionsAlg are scheduled in job-config
123 for (const HWIdentifier hwid : symIDs) {
124 const Identifier id = (*cablingHdl)->cnvToIdentifier(hwid);
125 const auto sampling = (CaloSampling::CaloSample)m_caloCellID->calo_sample(id);
126 const auto rangeIt = dynRange.find(sampling);
127 if (rangeIt == dynRange.end())[[unlikely]]{
128 ATH_MSG_WARNING("LArR4ElecCalibCalculator::stop: sampling not found in dynRange.");
129 continue;
130 }
131 const double mARange = rangeIt->second;
132 const double uAperADC = 1000 * mARange / nUsableBits;
133 const double dac2uA = (*DAC2uAHdl)->DAC2UA(hwid); // uA/DAC
134 const double ADC2DAC = uAperADC / dac2uA;
135
136 // For cross-check:
137 const double ADC2MeV = ADC2DAC * dac2uA * uA2MeVHdl->UA2MEV(hwid);
138 const double adc2uA = ADC2DAC * dac2uA;
139 ATH_MSG_DEBUG("sub_calo=" << m_caloCellID->sub_calo(id) << ", layer " << m_caloCellID->sampling(id) << ", region=" << m_caloCellID->region(id) << ": uA/ADC "
140 << uAperADC << ", ADC/mA " << nUsableBits / mARange << ", DAC2uA " << dac2uA << ", Ramp " << ADC2DAC << ", ADC2MeV=" << ADC2MeV
141 << ", ADC2DAC*dac2uA=" << adc2uA);
142
143 std::vector<float> vRamp;
144 vRamp.push_back(0); // ignore intercept for MC
145 vRamp.push_back(ADC2DAC);
146
147 rampMC->set(hwid, CaloGain::LARMEDIUMGAIN, vRamp);
148 // re-use the same short vector for higher gain
149 vRamp[1] /= 23.0; // HIGH gain =23* lower gain
150 rampMC->set(hwid, CaloGain::LARHIGHGAIN, vRamp);
151 }
152
153 // With the backward compatible MT-migration, the LArRampMC object became
154 // "write only". It is stored in the database but on read-back turned into a
155 // LArRampSym object. Only the latter can be used
156 std::unique_ptr<LArRampSym> rampSym = std::make_unique<LArRampSym>(*larMCsymHdl, rampMC.get());
157
158 StatusCode sc = detStore()->record(std::move(rampMC), m_keyoutput);
159 if (sc.isFailure()) {
160 ATH_MSG_ERROR("Failed to record LArRampSym object with key " << m_keyoutput);
161 }
163 if (sc.isFailure()) {
164 ATH_MSG_ERROR("Failed to symlink LArRampMC to ILArRamp base-class");
165 }
166
167 m_keyoutput += "Sym";
168 sc = detStore()->record(std::move(rampSym), m_keyoutput);
169 if (sc.isFailure()) {
170 ATH_MSG_ERROR("Failed to record LArRampSym object with key " << m_keyoutput);
171 }
173 if (sc.isFailure()) {
174 ATH_MSG_ERROR("Failed to symlink LArRampSym to ILArRamp base-class");
175 }
176
177
178 //Pedestal: Use only one value for all channels in the MC case
179 //Again, create a run 1/2/3 style LArPedestalMC object that can be store in a COOL-referenced POOL file
180 std::vector<float> pedVec, pedRMSVec;
181 pedVec.push_back(m_pedestalValue.value());
182 pedRMSVec.push_back(m_pedestalRMS.value());
183 std::unique_ptr<LArPedestalMC> pedPtr = std::make_unique<LArPedestalMC>();
184 pedPtr->set(pedVec, pedRMSVec);
185 ATH_CHECK(detStore()->record(std::move(pedPtr), m_pedkeyoutput));
186
187
188
189 //Noise: Fill a run 1/2/3-style LArNoiseMC object that can be store in a COOL-referenced POOL file
190 std::unique_ptr<LArNoiseMC> noisePtr = std::make_unique<LArNoiseMC>();
191 ATH_CHECK(noisePtr->setGroupingType("Single", msg()));
192 ATH_CHECK(noisePtr->initialize());
193
195 for (const HWIdentifier hwid : symIDs) {
196 const Identifier id = (*cablingHdl)->cnvToIdentifier(hwid);
197 const auto sampling = (CaloSampling::CaloSample)m_caloCellID->calo_sample(id);
198 const CaloDetDescrElement* dde = caloDDM->get_element(id);
199 const float eta = dde->eta_raw();
200
201 const auto& pairs = noiseMap.find(sampling)->second;
202 float noise = -1;
203 for (auto [e, n] : pairs) {
204 if (eta < e) {
205 noise = n;
206 ATH_MSG_DEBUG("Sampling: " << sampling << ", eta=" << eta << ", noise=" << noise);
207 break;
208 }
209 }
210 noisePtr->set(hwid, CaloGain::LARHIGHGAIN, noise);
211 noisePtr->set(hwid, CaloGain::LARMEDIUMGAIN, noise / 23.0);
212 } // end loop over sym-ids
213
214 std::unique_ptr<LArNoiseSym> noiseSym = std::make_unique<LArNoiseSym>(*larMCsymHdl, noisePtr.get());
215
216 ATH_CHECK(detStore()->record(std::move(noisePtr), "LArNoise"));
218 if (sc.isFailure()) {
219 ATH_MSG_ERROR("Failed to symlink LArNoiseMC to ILArNoise base-class");
220 }
221
222 sc = detStore()->record(std::move(noiseSym), "LArNoiseSym");
223 if (sc.isFailure()) {
224 ATH_MSG_ERROR("Failed to record LArNoiseSym object with key " << m_keyoutput);
225 }
227 if (sc.isFailure()) {
228 ATH_MSG_ERROR("Failed to symlink LArNoiseSym to ILArNoise base-class");
229 }
230
231
232
233
234 //If a CREST database is also given, we store the calibration constants in CREST
235 //In this case, the values are stored 'inline' in a Blob, so it can be read back into LArXYZFlat classes that are
236 //used for data-processing also in run 2 and 3.
237 if (!m_crestDBStr.value().empty()) {
238
239 chai::Tag::Metadata chaiMD{.iovType=chai::Tag::IovType::RunNumberLumiBlock,
240 .objectType="crest-json-single-iov",
241 .synchronization=chai::Tag::Synchronization::All,
242 .status=chai::Tag::Status::Unlocked,
243 .nodeDescription = chai::Tag::buildNodeDescription(chai::Tag::IovType::RunNumberLumiBlock, "CondAttrListCollection", 1238547719u)
244 };
245
246 std::vector<float> rampsHG, rampsMG, noiseHG, noiseMG, ped, pedRMS;
247 const LArRampSym* rampsIn = nullptr;
248 ATH_CHECK(detStore()->retrieve(rampsIn, "LArRampSym"));
249 const LArNoiseSym* noiseIn = nullptr;
250 ATH_CHECK(detStore()->retrieve(noiseIn, "LArNoiseSym"));
251
252 const unsigned int hashmax = m_onlineHelper->channelHashMax();
253
254 //Store only one pedestal value for all channels:
255 ped.push_back((m_pedestalValue.value()));
256 pedRMS.push_back(m_pedestalRMS.value());
257 for (unsigned idx = 0; idx < hashmax; ++idx) {
258 IdentifierHash hIdx(idx);
259 HWIdentifier hwid = m_onlineHelper->channel_Id(hIdx);
260 if (!(*cablingHdl)->isOnlineConnectedFromHash(hIdx)) {
261 rampsHG.push_back(0);
262 rampsHG.push_back(-999);
263 rampsMG.push_back(0);
264 rampsMG.push_back(-999);
265 noiseHG.push_back(-999);
266 noiseMG.push_back(-999);
267 } else {
268 const auto rampvecHG = rampsIn->ADC2DAC(hwid, CaloGain::LARHIGHGAIN);
269 rampsHG.push_back(rampvecHG[0]);
270 rampsHG.push_back(rampvecHG[1]);
271 const auto rampvecMG = rampsIn->ADC2DAC(hwid, CaloGain::LARMEDIUMGAIN);
272 rampsMG.push_back(rampvecMG[0]);
273 rampsMG.push_back(rampvecMG[1]);
274
275 noiseHG.push_back(noiseIn->noise(hwid, CaloGain::LARHIGHGAIN));
276 noiseMG.push_back(noiseIn->noise(hwid, CaloGain::LARMEDIUMGAIN));
277 }
278 }
279 chai::Database db = chai::Database(m_crestDBStr);
280 auto gt=db.createGlobalTag("GlobalTestTag", "test", "MC");
281
282 // Pedestals
283 {
284 chai::PayloadSpec spec(chai::FieldSpec({{"Pedestal", chai::Type::Blob}, {"PedestalRMS", chai::Type::Blob}, {"version", chai::Type::UInt32}}),
285
286 chai::ChannelSpec({
287 {0, "HIGHGain"},
288 {1, "MEDGain"},
289 }));
290
291 auto tag = db.createTag("LARElecCalibPedestal-R4-00", "Pedestal of FEB 2", spec, chaiMD);
292 gt->addTag("/LAR/ElecCalibMC/Pedestal","LARElecCalibPedestal-R4-00");
293
294 chai::Container container = tag->buildContainer();
295 for (size_t g = 0; g < 2; ++g) {
296 container[g].push(std::move(vecToBlobData(ped)));
297 container[g].push(std::move(vecToBlobData(pedRMS)));
298 container[g].push(0); // version number
299 }
300 tag->addPayload(container, 0);
301 }
302 // Ramps
303 {
304 chai::PayloadSpec spec(chai::FieldSpec({{"RampVec", chai::Type::Blob}, {"nPoints", chai::Type::UInt32}, {"version", chai::Type::UInt32}}),
305
306 chai::ChannelSpec({
307 {0, "HIGHGain"},
308 {1, "MEDGain"},
309 }));
310
311 auto tag = db.createTag("LARElecCalibMCRamp-R4-00", "Electronic gain of FEB 2", spec, chaiMD);
312 gt->addTag("/LAR/ElecCalibMC/Ramp", "LARElecCalibMCRamp-R4-00");
313
314 chai::Container container = tag->buildContainer();
315 container[0].push(std::move(vecToBlobData(rampsHG)));
316 container[0].push(2); // number of points (intercept,gradient)
317 container[0].push(0); // version number
318
319 container[1].push(std::move(vecToBlobData(rampsMG)));
320 container[1].push(2); // number of points (intercept,gradient)
321 container[1].push(0); // version number
322
323 tag->addPayload(container, 0);
324 }
325 // Noise
326 {
327 chai::PayloadSpec spec(chai::FieldSpec({{"Noise", chai::Type::Blob}, {"version", chai::Type::UInt32}}),
328
329 chai::ChannelSpec({
330 {0, "HIGHGain"},
331 {1, "MEDGain"},
332 }));
333
334 auto tag = db.createTag("LARElecCalibMCNoise-R4-00", "Noise of FEB 2 (in ADC counts)", spec, chaiMD);
335 gt->addTag("/LAR/ElecCalibMC/Noise","LARElecCalibMCNoise-R4-00");
336
337 chai::Container container = tag->buildContainer();
338
339 container[0].push(std::move(vecToBlobData(noiseHG)));
340 container[0].push(0); // version number
341
342 container[1].push(std::move(vecToBlobData(noiseMG)));
343 container[1].push(0); // version number
344 tag->addPayload(container, 0);
345 }
346 }
347 ATH_MSG_INFO("LArR4RampCalculator has finished.");
348 return StatusCode::SUCCESS;
349} // end finalize-method.
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)
#define ATH_MSG_DEBUG(x)
static Double_t sc
size_t size() const
Number of registered mappings.
const ServiceHandle< StoreGateSvc > & detStore() const
This class groups all DetDescr information related to a CaloCell.
This is a "hash" representation of an Identifier.
virtual const float & noise(const HWIdentifier &hwid, int gain) const override
SG::ReadCondHandleKey< LArMCSym > m_mcSym
Gaudi::Property< float > m_pedestalRMS
SG::ReadCondHandleKey< ILArDAC2uA > m_lArDAC2uAKey
SG::ReadCondHandleKey< ILAruA2MeV > m_lAruA2MeVKey
Gaudi::Property< std::string > m_keyoutput
Gaudi::Property< std::string > m_pedkeyoutput
SG::ReadCondHandleKey< CaloDetDescrManager > m_caloMgrKey
Gaudi::Property< float > m_pedestalValue
virtual StatusCode initialize() override
SG::ReadCondHandleKey< LArOnOffIdMapping > m_cablingKey
virtual StatusCode stop() override
Gaudi::Property< std::string > m_crestDBStr
virtual StatusCode execute(const EventContext &ctx) override
Execute method.
virtual RampRef_t ADC2DAC(const HWIdentifier &CellID, int gain) const override
@ LARMEDIUMGAIN
Definition CaloGain.h:18
@ LARHIGHGAIN
Definition CaloGain.h:18
#define unlikely(x)