ATLAS Offline Software
Loading...
Searching...
No Matches
MuonConditions/MuonCondGeneral/MuonCondAlg/src/MdtCalibDbAlg.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#include "MdtCalibDbAlg.h"
6
12#include "CLHEP/Random/RandGaussZiggurat.h"
13#include "CoralBase/Attribute.h"
14#include "CoralBase/AttributeListSpecification.h"
15#include "GaudiKernel/PhysicalConstants.h"
33
35
36
37#include <fstream>
38
39#include "TFile.h"
40#include "TSpline.h"
41#include "GeoModelKernel/throwExcept.h"
42
43using namespace MuonCalib;
44using namespace CxxUtils;
48
49namespace Muon {
50
52 ATH_MSG_DEBUG("initialize " << name());
53
54 // if timeslew correction vector m_MeanCorrectionVsR has non-zero size then set
55 // m_TsCorrectionT0=m_MeanCorrectionVsR[0] and subtract this each value in the vector.
56 if (m_MeanCorrectionVsR.size()) {
58 for (float & it : m_MeanCorrectionVsR) {
59 it -= m_TsCorrectionT0;
60 }
61 }
62
63 ATH_CHECK(m_idHelperSvc.retrieve());
64 ATH_CHECK(m_idToFixedIdTool.retrieve());
65 // initiallize random number generator if doing t0 smearing (for robustness studies)
66 if (m_t0Spread != 0.) {
67 ATH_CHECK(m_AthRNGSvc.retrieve());
68 ATH_MSG_DEBUG(" initialize Random Number Service: running with t0 shift "
69 << m_t0Shift << " spread " << m_t0Spread << " rt shift " << m_rtShift);
70 // getting our random numbers stream
71 m_RNGWrapper = m_AthRNGSvc->getEngine(this, m_randomStream);
72 if (!m_RNGWrapper) {
73 ATH_MSG_ERROR("Could not get random number engine from AthRNGSvc. Abort.");
74 return StatusCode::FAILURE;
75 }
76 }
77
78 if (m_rtShift != 0. || m_rtScale != 1. || m_t0Shift != 0. || m_t0Spread != 0.) {
79 ATH_MSG_INFO("************************************" << std::endl
80 << " Running with Calibration Deformations! " << std::endl
81 << " For performance studies only!" << std::endl
82 << " **************************************");
83 ATH_MSG_DEBUG(" rt scale " << m_rtScale << " t0 shift " << m_t0Shift << " spread " << m_t0Spread << " rt shift " << m_rtShift);
84 }
85
86 ATH_CHECK(m_readKeyRt.initialize());
87 ATH_CHECK(m_readKeyTube.initialize());
88 ATH_CHECK(m_writeKey.initialize());
90
91 if (m_useNewGeo) {
92 ATH_CHECK(detStore()->retrieve(m_r4detMgr));
93 } else {
94 ATH_CHECK(detStore()->retrieve(m_detMgr));
95 }
96 return StatusCode::SUCCESS;
97}
98 StatusCode MdtCalibDbAlg::declareDependency(const EventContext& ctx,
100
101 writeHandle.addDependency(EventIDRange(IOVInfiniteRange::infiniteTime()));
103 if (key.empty()) continue;
104 SG::ReadCondHandle readHandle{key, ctx};
105 if (!readHandle.isValid()) {
106 ATH_MSG_FATAL("Failed to retrieve conditions object "<<readHandle.fullKey());
107 return StatusCode::FAILURE;
108 }
109 writeHandle.addDependency(readHandle);
110 ATH_MSG_INFO("Size of CondAttrListCollection " << readHandle.fullKey() << " readCdoRt->size()= " << readHandle->size());
111 ATH_MSG_INFO("Range of input is " << readHandle.getRange());
112 }
113 if (m_readKeyDCS.empty()) {
114 return StatusCode::SUCCESS;
115 }
116 SG::ReadCondHandle readHandle{m_readKeyDCS, ctx};
117 if (!readHandle.isValid()) {
118 ATH_MSG_FATAL("Failed to retrieve conditions object "<<m_readKeyDCS.fullKey());
119 return StatusCode::FAILURE;
120 }
121 if (readHandle->hasDCS()) {
122 writeHandle.addDependency(readHandle);
123 }
124 return StatusCode::SUCCESS;
125}
126StatusCode MdtCalibDbAlg::execute(const EventContext& ctx) const {
127 ATH_MSG_DEBUG("execute " << name());
128 SG::WriteCondHandle writeHandle{m_writeKey, ctx};
129 if (writeHandle.isValid()) {
130 ATH_MSG_DEBUG("CondHandle " << writeHandle.fullKey() << " is already valid."
131 << ". In theory this should not be called, but may happen"
132 << " if multiple concurrent events are being processed out of order.");
133 return StatusCode::SUCCESS;
134 }
135 ATH_CHECK(declareDependency(ctx, writeHandle));
136
137 RegionGranularity gran{RegionGranularity::OnePerChamber};
138 if (m_readKeyRt.key() == "/MDT/RTUNIQUE") {
139 ATH_MSG_DEBUG("Save one set of Rt constants per chamber");
140 gran = RegionGranularity::OneRt;
141 } else if (m_UseMLRt) {
142 ATH_MSG_DEBUG("Save one set of calibration constants per multi layer");
143 gran = RegionGranularity::OnePerMultiLayer;
144 } else ATH_MSG_DEBUG("Save one set of calibration constants per chamber");
145 std::unique_ptr<MuonCalib::MdtCalibDataContainer> writeCdo = std::make_unique<MuonCalib::MdtCalibDataContainer>(m_idHelperSvc.get(), gran);
146
147 ATH_CHECK(loadRt(ctx, *writeCdo));
148 ATH_CHECK(loadTube(ctx, *writeCdo));
149 ATH_CHECK(writeHandle.record(std::move(writeCdo)));
150 return StatusCode::SUCCESS;
151}
152
154 ATH_MSG_DEBUG("defaultRt " << name());
155 std::string fileName = PathResolver::find_calib_file(m_RTfileName);
156 std::ifstream inputFile(fileName);
157 if (!inputFile) {
158 ATH_MSG_ERROR("Unable to open RT Ascii file: " << fileName);
159 return StatusCode::FAILURE;
160 }
161 ATH_MSG_DEBUG("Opened RT Ascii file: " << fileName);
162
163
164 // Read the RTs from the text file
166 rts.read(inputFile);
167 ATH_MSG_VERBOSE("File contains " << rts.nRts() << " RT relations ");
168
169 // Loop over all RTs in the file (but the default file only has 1 RT)
170 // Use the first valid RT found in the file as the default for all chambers.
171 const MdtIdHelper& idHelper{m_idHelperSvc->mdtIdHelper()};
172 for (unsigned int n = 0; n < rts.nRts(); ++n) {
173 std::unique_ptr<MuonCalib::RtDataFromFile::RtRelation> rt(rts.getRt(n));
174
175 const MuonCalib::RtDataFromFile::RtRelation::DataVec &times = rt->times();
176 const MuonCalib::RtDataFromFile::RtRelation::DataVec &radii = rt->radii();
177 const MuonCalib::RtDataFromFile::RtRelation::DataVec &reso = rt->resolution();
178
179 // check if rt contains data, at least two points on the rt are required
180 if (times.size() < 2) {
181 ATH_MSG_ERROR(" defaultRt rt table has too few entries");
182 return StatusCode::FAILURE;
183 }
184 // check if all tables have same size
185 if (times.size() != radii.size() || times.size() != reso.size()) {
186 ATH_MSG_ERROR("defaultRt rt table size mismatch ");
187 return StatusCode::FAILURE;
188 }
189 // check for negative time bins, i.e. decreasing time value with radius
190 double t_min = times[0];
191 double bin_size = times[1] - t_min;
192 if (bin_size <= 0) {
193 ATH_MSG_ERROR("defaultRt rt table negative binsize ");
194 return StatusCode::FAILURE;
195 }
196
197 // create a vector to hold the r values,
198 // we need two extra fields to store t_min and bin_size
200 rtPars.push_back(t_min);
201 rtPars.push_back(bin_size);
202
203 // copy r values into vector
204 rtPars.insert(rtPars.end(), radii.begin(), radii.end());
205
206 ATH_MSG_DEBUG("defaultRt new MuonCalib::IRtRelation");
207
208 MuonCalib::CalibFunc::ParVec resoPars{t_min, bin_size};
209 // copy r values into vector
210 resoPars.insert(resoPars.end(), reso.begin(), reso.end());
211
212 ATH_MSG_DEBUG("defaultRt new MuonCalib::IRtResolution");
213
214 // create RT and resolution "I" objects
215 std::shared_ptr<MuonCalib::IRtRelation> rtRel{std::make_shared<RtRelationLookUp>(rtPars)};
216 std::shared_ptr<MuonCalib::IRtResolution> resoRel{std::make_shared<RtResolutionLookUp>(resoPars)};
217
218
219 // Since the same RT is loaded for all chambers you might be tempted to create it once
220 // and simply store the same pointer in writeCdoRt for all regions.
221 // However it seems that when StoreGate clears writeCdoRt (which will happen in LoadRt
222 // by detStore()->removeDataAndProxy) it will crash unless there are unique pointers/objects
223 // for rtRel, resoRel, and MdtRtRelation
224
225 // Loop over RT regions and store the default RT in each
226 RtRelationPtr MdtRt = std::make_shared<MuonCalib::MdtRtRelation>(rtRel, resoRel);
227
228 for(auto itr = idHelper.detectorElement_begin();
229 itr!= idHelper.detectorElement_end();++itr){
230 const Identifier detElId{*itr};
231 if (writeCdo.hasDataForChannel(detElId, msgStream())) {
232 const MdtFullCalibData* dataObj = writeCdo.getCalibData(detElId, msgStream());
233 if (dataObj->rtRelation) {
234 ATH_MSG_DEBUG("Rt relation constants for "<<m_idHelperSvc->toString(detElId)<<" already exists");
235 continue;
236 }
237 }
239 RtRelationPtr storeMe = MdtRt;
240 if (idHelper.multilayer(detElId) == 2) {
241 if (writeCdo.granularity() != RegionGranularity::OnePerMultiLayer) continue;
242 const Identifier firstML = idHelper.multilayerID(detElId, 1);
243 if (writeCdo.hasDataForChannel(firstML, msgStream())) {
244 const MdtFullCalibData* dataObj = writeCdo.getCalibData(firstML, msgStream());
245 if (dataObj->rtRelation) {
246 ATH_MSG_DEBUG("Copy Rt constanst from the first multi layer for "<<m_idHelperSvc->toString(detElId));
247 storeMe = dataObj->rtRelation;
248 }
249 }
250 }
251 ATH_MSG_DEBUG("Add default rt constants for "<<m_idHelperSvc->toString(detElId));
252 if (!writeCdo.storeData(detElId, storeMe, msgStream())) {
253 ATH_MSG_FATAL(__FILE__<<":"<<__LINE__<<" Failed to save default rts for "<<m_idHelperSvc->toString(detElId));
254 return StatusCode::FAILURE;
255 }
256
258 loadedRts[detElId] = MdtRt;
259
260 }
261
262 // if VERBOSE enabled print out RT function
263 if (msgLvl(MSG::VERBOSE)) {
264 int npoints = rtRel->nPar() - 2;
265 ATH_MSG_VERBOSE("defaultRt npoints from rtRel=" << npoints);
266 for (int ipt = 0; ipt < npoints; ++ipt) {
267 double t = t_min + ipt * bin_size;
268 ATH_MSG_VERBOSE(" " << ipt << " " << t << " " << rtRel->radius(t) << " " << resoRel->resolution(t));
269 }
270 }
271 break; // only need the first good RT from the text file
272
273 } // end loop over RTs in file
274
275 return StatusCode::SUCCESS;
276}
277std::optional<double> MdtCalibDbAlg::getInnerTubeRadius(const Identifier& id) const {
278 static std::atomic<bool> rtWarningPrinted = false;
279
280 if (m_detMgr) {
281 const MuonGM::MdtReadoutElement *detEl = m_detMgr->getMdtReadoutElement(id);
282 if (detEl) { return std::make_optional<double>(detEl->innerTubeRadius()); }
283
284 } else if (m_r4detMgr) {
285 const MuonGMR4::MdtReadoutElement* detEl = m_r4detMgr->getMdtReadoutElement(id);
286 if (detEl) { return std::make_optional<double>(detEl->innerTubeRadius()); }
287 }
288 if (!rtWarningPrinted) {
289 ATH_MSG_WARNING("getInnerTubeRadius() - no Muon station known under the name "
290 << m_idHelperSvc->toString(id));
291 rtWarningPrinted = true;
292 }
293 return std::nullopt;
294}
295
296StatusCode MdtCalibDbAlg::legacyRtPayloadToJSON(const coral::AttributeList& attr, nlohmann::json & json) const {
297 std::string data{}, delim{};
298 if (attr["data"].specification().type() == typeid(coral::Blob)) {
299 ATH_MSG_VERBOSE("Loading data as a BLOB, uncompressing...");
301 ATH_MSG_FATAL("Cannot uncompress BLOB! Aborting...");
302 return StatusCode::FAILURE;
303 }
304 delim = "\n";
305 } else {
306 data = *(static_cast<const std::string *>((attr["data"]).addressOfData()));
307 delim = " ";
308 }
309 const std::vector<std::string> tokens = tokenize(data, delim);
310 if (tokens.size() < 2) {
311 ATH_MSG_FATAL("The line "<<data<<" cannot be resolved into header & payload");
312 return StatusCode::FAILURE;
313 }
314 const std::string& header = tokens[0];
315 const std::string& payload = tokens[1];
316 ATH_MSG_DEBUG("Header: '"<<header<<"' payload: '"<<payload<<"'");
318 unsigned int numPoints{0};
319 nlohmann::json channel{};
320 const bool rt_ts_applied = (attr["tech"].data<int>() & MuonCalib::TIME_SLEWING_CORRECTION_APPLIED);
321 channel["appliedRT"] = rt_ts_applied;
322 const MdtIdHelper& idHelper{m_idHelperSvc->mdtIdHelper()};
323 {
324
325 std::vector<int> tokensHeader = tokenizeInt(header, ",");
326 if(tokensHeader.size()< 2){
327 ATH_MSG_FATAL("Failed to deduce extract number of points & calib Identifier from "<<header);
328 return StatusCode::FAILURE;
329 }
330 unsigned int calibId = tokensHeader[0];
331 numPoints = tokensHeader[1];
332 MuonCalib::MuonFixedId id(calibId);
333 if (!id.is_mdt()) {
334 ATH_MSG_FATAL("Found non-MDT MuonFixedId, continuing...");
335 return StatusCode::FAILURE;
336 }
337 const Identifier athenaId = m_idToFixedIdTool->fixedIdToId(id);
338 if (!m_idHelperSvc->isMuon(athenaId)) {
339 ATH_MSG_WARNING("The translation from the calibration ID with station: "
340 <<id.stationNameString()<<"("<<id.stationName()<<") "
341 <<" eta:"<<id.eta()<<" phi: "<<id.phi());
342 }
343 channel["station"] = m_idHelperSvc->stationNameString(athenaId);
344 channel["eta"] = m_idHelperSvc->stationEta(athenaId);
345 channel["phi"] = m_idHelperSvc->stationPhi(athenaId);
346 channel["ml"] = idHelper.multilayer(athenaId);
347 channel["layer"] = idHelper.tubeLayer(athenaId);
348 channel["tube"] = idHelper.tube(athenaId);
349 }
351 const std::vector<double> dataPoints = tokenizeDouble(payload, ",");
352 std::vector<double> radii{}, times{}, resos{};
353 radii.reserve(numPoints);
354 times.reserve(numPoints);
355 resos.reserve(numPoints);
359 for (unsigned int k = 0 ; k < dataPoints.size(); ++k) {
360 const double value = dataPoints[k];
361 switch (k%3) {
362 case 0:
363 radii.push_back(value);
364 break;
365 case 1:
366 times.push_back(value);
367 break;
368 case 2:
369 resos.push_back(value);
370 break;
371 default:
372 break;
373 }
374 }
376 if (radii.size() != numPoints ||
377 times.size() != numPoints ||
378 resos.size() != numPoints) {
379 ATH_MSG_FATAL("Payload "<<payload<<" does not lead to the expected number of points "<<numPoints<<" vs. "<<dataPoints.size());
380 return StatusCode::FAILURE;
381 }
382 channel["radii"] = std::move(radii);
383 channel["times"] = std::move(times);
384 channel["resolutions"] = std::move(resos);
385 json.push_back(channel);
386 return StatusCode::SUCCESS;
387}
388
389StatusCode MdtCalibDbAlg::loadRt(const EventContext& ctx, MuonCalib::MdtCalibDataContainer& writeCdo) const {
390 ATH_MSG_DEBUG("loadRt " << name());
391
392 // Read Cond Handle
393 SG::ReadCondHandle readHandleRt{m_readKeyRt, ctx};
394 if (!readHandleRt.isValid()) {
395 ATH_MSG_ERROR("readCdoRt==nullptr");
396 return StatusCode::FAILURE;
397 }
398 // read new-style format 2020
399
400 nlohmann::json rtCalibJson = nlohmann::json::array();
401 const MdtIdHelper& idHelper{m_idHelperSvc->mdtIdHelper()};
402 if (m_newFormat2020) {
403 for (CondAttrListCollection::const_iterator itr = readHandleRt->begin();
404 itr != readHandleRt->end(); ++itr) {
405 const coral::AttributeList &atr = itr->second;
406 std::string data{};
407 if (atr["data"].specification().type() == typeid(coral::Blob)) {
408 ATH_MSG_VERBOSE("Loading data as a BLOB, uncompressing...");
410 ATH_MSG_FATAL("Cannot uncompress BLOB! Aborting...");
411 return StatusCode::FAILURE;
412 }
413 } else {
414 ATH_MSG_VERBOSE("Loading data as a STRING");
415 data = *(static_cast<const std::string *>((atr["data"]).addressOfData()));
416 }
417 // unwrap the json and build the data vector
418 nlohmann::json yy = nlohmann::json::parse(data);
419 for (auto &it : yy.items()) {
420 nlohmann::json yx = it.value();
421 rtCalibJson.push_back(yx);
422 }
423 }
424 }
425 // read old-style format
426 else {
427 for (CondAttrListCollection::const_iterator itr = readHandleRt->begin();
428 itr != readHandleRt->end(); ++itr) {
429 ATH_CHECK(legacyRtPayloadToJSON(itr->second, rtCalibJson));
430 }
431 }
433 LoadedRtMap loadedRtRel{};
434 // unpack the strings in the collection and update the writeCdoRt
435 for (const auto& payload : rtCalibJson) {
436 const bool rt_ts_applied = payload["appliedRT"];
438 const std::string stName = payload["station"];
439 const Identifier athenaId = idHelper.channelID(stName, payload["eta"], payload["phi"],
440 payload["ml"], payload["layer"], payload["tube"]);
441
442 std::optional<double> innerTubeRadius = getInnerTubeRadius(idHelper.multilayerID(athenaId, 1));
443 if (!innerTubeRadius) continue;
444
445
446 const std::vector<double> radii = payload["radii"];
447 const std::vector<double> times = payload["times"];
448 const std::vector<double> resolutions = payload["resolutions"];
449
450 if (writeCdo.hasDataForChannel(athenaId, msgStream())) {
451 const MdtFullCalibData* dataObj = writeCdo.getCalibData(athenaId, msgStream());
452 if (dataObj->rtRelation) {
453 ATH_MSG_DEBUG("Rt relation constants for "<<m_idHelperSvc->toString(athenaId)<<" already exists");
454 continue;
455 }
456 }
457
458 MuonCalib::CalibFunc::ParVec rtPars{}, resoPars{};
459
460 MuonCalib::SamplePoint tr_point, ts_point; // pairs of numbers; tr = (time,radius); ts = (time,sigma) [sigma=resolution]
461 std::vector<MuonCalib::SamplePoint> tr_points{}, ts_points{};
463 float multilayer_tmax_diff{-std::numeric_limits<float>::max()};
464
465 // loop over RT function payload (triplets of radius,time,sigma(=resolution) )
466 for (unsigned int k = 0; k < radii.size(); ++k) {
467 float radius = radii[k];
468 if (m_rtShift != 0.) {
469 float oldradius = radius;
470 // TODO: What is this magic number
471 float rshift = m_rtShift * 1.87652e-2 * radius * (radius - *innerTubeRadius);
472 radius = oldradius + rshift;
473 ATH_MSG_DEBUG("DEFORM RT: old radius " << oldradius << " new radius " << radius << " shift " << rshift
474 << " max shift " << m_rtShift);
475 }
476
477 if (m_rtScale != 1.) {
478 float oldradius = radius;
479 radius = radius * m_rtScale;
480 ATH_MSG_DEBUG("DEFORM RT: old radius " << oldradius << " new radius " << radius << " scale factor " << m_rtScale);
481 }
482 tr_point.set_x2(radius);
483
484 float time = times[k];
485 tr_point.set_x1(time);
486 ts_point.set_x1(time);
487
488 float sigma = resolutions[k];
489 ts_point.set_x2(sigma);
490 ts_point.set_error(1.0);
491 tr_point.set_error(1.0);
492 if (tr_point.x2() < -99) { // if radius is < -99 then treat time as ML Tmax difference
493 multilayer_tmax_diff = tr_point.x1();
494 } else if (tr_points.empty() || (tr_points.back().x1() < tr_point.x1() && tr_points.back().x2() < tr_point.x2())) {
495 tr_points.push_back(tr_point);
496 ts_points.push_back(ts_point);
497 }
498 } // end loop over RT function payload (triplets of radius,time,resolution)
499
501 if (ts_points.size() < 3) {
502 ATH_MSG_FATAL("Rt relation broken!");
503 return StatusCode::FAILURE;
504 }
505
506 if (rt_ts_applied != m_TimeSlewingCorrection) {
507 float sign(rt_ts_applied ? -1.0 : 1.0);
508 float slice_width = (*innerTubeRadius) / static_cast<float>(m_MeanCorrectionVsR.size());
509 for (auto & tr_point : tr_points) {
510 int slice_number = static_cast<int>(std::floor(tr_point.x2() / slice_width));
511 if (slice_number < 0) slice_number = 0;
512 if (slice_number >= static_cast<int>(m_MeanCorrectionVsR.size()))
513 slice_number = static_cast<int>(m_MeanCorrectionVsR.size()) - 1;
514 tr_point.set_x1(tr_point.x1() + sign * m_MeanCorrectionVsR[slice_number]);
515 }
516 }
517
518 // Create resolution function from ts_points
519 std::unique_ptr<MuonCalib::IRtResolution> reso = getRtResolutionInterpolation(ts_points);
520 if (msgLvl(MSG::VERBOSE)) {
521 ATH_MSG_VERBOSE("Resolution points :");
522 for (const MuonCalib::SamplePoint& point : tr_points) {
523 ATH_MSG_VERBOSE(point.x1() << "|" << point.x2() << "|" << point.error());
524 }
525 ATH_MSG_DEBUG("Resolution parameters :");
526 for (unsigned int i = 0; i < reso->nPar(); i++) { ATH_MSG_VERBOSE(i << " " << reso->par(i)); }
527 }
528
529 // Create RT function from tr_points and load RT and resolution functions
530 std::unique_ptr<MuonCalib::IRtRelation> rt = MuonCalib::RtFromPoints::getRtRelationLookUp(tr_points);
531 if (!reso || !rt) { continue; }
532
533 if (rt->par(1) == 0.) {
534 ATH_MSG_FATAL("Bin size is 0");
535 for (const MuonCalib::SamplePoint& it: tr_points)
536 ATH_MSG_WARNING(it.x1() << " " << it.x2() << " " << it.error());
537 return StatusCode::FAILURE;
538 }
539 // Save ML difference if it is available
540 if (multilayer_tmax_diff > -8e8) { rt->SetTmaxDiff(multilayer_tmax_diff); }
541 // Store RT and resolution functions for this region
542 RtRelationPtr rt_rel = std::make_shared<MuonCalib::MdtRtRelation>(std::move(rt), std::move(reso));
543
544 if (!writeCdo.storeData(athenaId ,rt_rel, msgStream())) return StatusCode::FAILURE;
546 loadedRtRel[athenaId] = rt_rel;
547
548 } // end loop over itr (strings read from COOL)
549 ATH_CHECK(defaultRt(writeCdo, loadedRtRel));
550
551 if (loadedRtRel.empty()) {
552 return StatusCode::SUCCESS;
553 }
554
555 ATH_MSG_DEBUG("Initializing " << loadedRtRel.size()<< " b-field functions");
556 const MdtCondDbData* condDbData{nullptr};
557 if (!m_readKeyDCS.empty()) {
558 SG::ReadCondHandle readCondHandleDb{m_readKeyDCS, ctx};
560 if (readCondHandleDb->hasDCS()) {
561 condDbData = readCondHandleDb.cptr();
562 } else {
563 ATH_MSG_INFO("Do not retrieve the HV from DCS. Fall back to 2730 & 3080");
564 }
565 }
566
567
568 for (const auto& [athenaId, rtRelation] : loadedRtRel) {
569 CorrectionPtr corrFuncSet = std::make_unique<MuonCalib::MdtCorFuncSet>();
570
572 std::vector<double> corr_params(2);
573 bool loadDefault{false};
574 if (condDbData){
575 const MuonCond::DcsConstants& dcs{condDbData->getHvState(athenaId)};
576 corr_params[0] = dcs.readyVolt;
578 if (corr_params[0] < std::numeric_limits<float>::epsilon()) {
579 ATH_MSG_DEBUG("Chamber "<<m_idHelperSvc->toString(athenaId)<<" is switched off "<<dcs);
580 loadDefault = true;
581 }
582 } else loadDefault = true;
583 if (loadDefault) {
584 if (m_idHelperSvc->issMdt(athenaId)) {
585 corr_params[0] = 2730.0;
586 } else {
587 corr_params[0] = 3080.0;
588 }
589 }
590 corr_params[1] = 0.11; // epsilon parameter
591 corrFuncSet->setBField(std::make_unique<MuonCalib::BFieldCorFunc>("medium", corr_params, rtRelation->rt()));
592 }
594 corrFuncSet->setSlewing(std::make_unique<MuonCalib::MdtSlewCorFuncHardcoded>(MuonCalib::CalibFunc::ParVec()));
595 }
596 if (!writeCdo.storeData(athenaId, corrFuncSet, msgStream())) return StatusCode::FAILURE;
597 }
598
599 return StatusCode::SUCCESS;
600}
601
602// build the transient structure and load some defaults for T0s
604 const MdtIdHelper& id_helper{m_idHelperSvc->mdtIdHelper()};
605
606 // loop over modules (MDT chambers) and create an MdtTubeContainer for each
608 MdtIdHelper::const_id_iterator it_end = id_helper.module_end();
609 for (; it != it_end; ++it) {
610
611 if (writeCdo.hasDataForChannel(*it, msgStream())) {
612 const MdtFullCalibData* dataObj = writeCdo.getCalibData(*it, msgStream());
613 if (dataObj->tubeCalib) {
614 ATH_MSG_DEBUG("Rt relation constants for "<<m_idHelperSvc->toString(*it)<<" already exists");
615 continue;
616 }
617 }
618 // create an MdtTubeContainer
619 TubeContainerPtr tubes = std::make_unique<MuonCalib::MdtTubeCalibContainer>(m_idHelperSvc.get(), *it);
620 if (!writeCdo.storeData(*it, tubes, msgStream())) return StatusCode::FAILURE;
621
622 // is tubes ever 0? how could that happen?
623 double t0 = m_defaultT0;
624
625 unsigned int nml = tubes->numMultilayers();
626 unsigned int nlayers = tubes->numLayers();
627 unsigned int ntubes = tubes->numTubes();
628 int size = nml * nlayers * ntubes;
629
630 ATH_MSG_VERBOSE("Adding chamber " << m_idHelperSvc->toString(*it)
631 <<" size " << size << " ml " << nml << " l " << nlayers << " t " << ntubes);
632 for (unsigned int ml = 1; ml <= nml; ++ml) {
633 for (unsigned int l = 1; l <= nlayers; ++l) {
634 for (unsigned int t = 1; t <= ntubes; ++t) {
636 const Identifier tubeId = id_helper.channelID(*it, ml, l, t);
637 data.t0 = t0;
638 data.adcCal = 1.;
639 tubes->setCalib(std::move(data), tubeId, msgStream());
640 }
641 }
642 }
643 }
644 return StatusCode::SUCCESS;
645}
646
647
648StatusCode MdtCalibDbAlg::legacyTubePayloadToJSON(const coral::AttributeList& attr,nlohmann::json & json) const {
649 std::string data{};
650 if (attr["data"].specification().type() == typeid(coral::Blob)) {
651 ATH_MSG_VERBOSE("Loading data as a BLOB, uncompressing...");
653 ATH_MSG_FATAL("Cannot uncompress BLOB! Aborting...");
654 return StatusCode::FAILURE;
655 }
656
657 } else {
658 data = *(static_cast<const std::string *>((attr["data"]).addressOfData()));
659 }
660 std::vector<std::string> tokens = tokenize(data, "\n");
661 if (tokens.size() < 2) {
662 ATH_MSG_FATAL("The line "<<data<<" cannot be resolved into header & payload");
663 return StatusCode::FAILURE;
664 }
665 std::string& header = tokens[0];
666 const std::string& payload = tokens[1];
667
672 const std::string stName = header.substr(2,3);
673 int eta{0}, phi{0}, nTubes{0};
674 {
675 std::replace(header.begin(), header.end(),'_', ',');
676 const std::vector<std::string> headerTokens = tokenize(header, ",");
677 phi = atoi(headerTokens[1]);
678 eta = atoi(headerTokens[2]);
679 nTubes = atoi(headerTokens[5]);
680 }
681 const MdtIdHelper& idHelper{m_idHelperSvc->mdtIdHelper()};
682 bool isValid{false};
683 const Identifier chamID = idHelper.elementID(stName, eta, phi, isValid);
684 if (!isValid) {
685 static std::atomic<bool> idWarningPrinted = false;
686 if (!idWarningPrinted) {
687 ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" Identifier: "<<stName<<","<<eta<<","<<phi
688 <<" is invalid. Skipping");
689 idWarningPrinted.store(true, std::memory_order_relaxed);
690 }
691 return StatusCode::SUCCESS;
692 }
693 nlohmann::json channel{};
694 const bool t0_ts_applied = (attr["tech"].data<int>() & MuonCalib::TIME_SLEWING_CORRECTION_APPLIED);
695 channel["appliedT0"] = t0_ts_applied;
696 channel["station"] = stName;
697 channel["eta"] = eta;
698 channel["phi"] = phi;
699
700 const std::vector<double> payLoadData = tokenizeDouble(payload, ",");
701 std::vector<double> tzeros{}, meanAdcs{};
702 std::vector<int> statusCodes{};
705 for (unsigned int k = 0; k < payLoadData.size(); ++k){
706 const double value = payLoadData[k];
707 switch (k%3) {
708 case 0:
709 tzeros.push_back(value);
710 break;
711 case 1:
712 statusCodes.push_back(value);
713 break;
714 case 2:
715 meanAdcs.push_back(value);
716 break;
717 default:
718 break;
719 }
720 }
721 if (statusCodes.size() != tzeros.size() ||
722 statusCodes.size() != meanAdcs.size() ||
723 statusCodes.empty()) {
724 ATH_MSG_FATAL("Failed to properly readt t0 calibrations for chamber "<<m_idHelperSvc->toStringChamber(chamID));
725 return StatusCode::FAILURE;
726 }
728 int ml{1}, layer{1}, tube{1};
729
730 const int numMl = idHelper.numberOfMultilayers(chamID);
731 const Identifier secondMlID = idHelper.multilayerID(chamID, numMl);
732 const int tubesPerLay = std::max(idHelper.tubeMax(chamID), idHelper.tubeMax(secondMlID));
733 const int numLayers = std::max(idHelper.tubeLayerMax(chamID), idHelper.tubeLayerMax(secondMlID));
734 if (m_checkTubes && (numMl * numLayers * tubesPerLay) != nTubes) {
735 ATH_MSG_FATAL("Calibration database differs in terms of number of tubes for chamber "
736 <<m_idHelperSvc->toStringChamber(chamID)<<". Expected "<<(numMl * numLayers * tubesPerLay)
737 <<" vs. observed "<<nTubes);
738 return StatusCode::FAILURE;
739 }
740 nlohmann::json calibData = nlohmann::json::array();
741 for (unsigned int k = 0; k < tzeros.size(); ++k) {
742 nlohmann::json channelData{};
743 channelData["ml"] = ml;
744 channelData["layer"] =layer;
745 channelData["tube"] = tube;
746 channelData["t0"] = tzeros[k];
747 channelData["meanAdc"] = meanAdcs[k];
748 channelData["status"] = statusCodes[k];
749 ++tube;
750 if (tube > tubesPerLay){
751 tube = 1;
752 ++layer;
753 }
754 if (layer > numLayers){
755 layer = 1;
756 ++ml;
757 }
758 calibData.push_back(std::move(channelData));
759 }
760 channel["calibConstants"] = std::move(calibData);
761 json.push_back(std::move(channel));
762 return StatusCode::SUCCESS;
763}
764StatusCode MdtCalibDbAlg::loadTube(const EventContext& ctx, MuonCalib::MdtCalibDataContainer& writeCdo) const {
765 ATH_MSG_DEBUG("loadTube " << name());
766 const MdtIdHelper& idHelper{m_idHelperSvc->mdtIdHelper()};
767
768 // Read Cond Handle
769 SG::ReadCondHandle readHandleTube{m_readKeyTube, ctx};
770 // read new-style format 2020
771 nlohmann::json t0CalibJson = nlohmann::json::array();
772 if (m_newFormat2020) {
773 for (CondAttrListCollection::const_iterator itr = readHandleTube->begin();
774 itr != readHandleTube->end(); ++itr) {
775 const coral::AttributeList &atr = itr->second;
776 std::string data{};
777 if (atr["data"].specification().type() == typeid(coral::Blob)) {
778 ATH_MSG_VERBOSE("Loading data as a BLOB, uncompressing...");
780 ATH_MSG_FATAL("Cannot uncompress BLOB! Aborting...");
781 return StatusCode::FAILURE;
782 }
783 } else {
784 ATH_MSG_VERBOSE("Loading data as a STRING");
785 data = *(static_cast<const std::string *>((atr["data"]).addressOfData()));
786 }
787 // unwrap the json and build the data vector
788 nlohmann::json yy = nlohmann::json::parse(data);
789 for (auto &it : yy.items()) {
790 nlohmann::json yx = it.value();
791 t0CalibJson.push_back(yx);
792 }
793 }
794 }
795 // read old-style format
796 else {
797 for (CondAttrListCollection::const_iterator itr = readHandleTube->begin();
798 itr != readHandleTube->end(); ++itr) {
799 ATH_CHECK(legacyTubePayloadToJSON(itr->second, t0CalibJson));
800 }
801 }
802
803 // Inverse of wire propagation speed
804 const float inversePropSpeed = 1. / (Gaudi::Units::c_light * m_prop_beta);
805 writeCdo.setInversePropSpeed(inversePropSpeed);
806
807
808 // unpack the strings in the collection and update the
809 // MdtTubeCalibContainers in TDS
810 for (const auto& chambChannel : t0CalibJson) {
811 const std::string stName = chambChannel["station"];
812 const int ieta = chambChannel["eta"];
813 const int iphi = chambChannel["phi"];
814 const bool t0_ts_applied = chambChannel["appliedT0"];
815 // need to check validity of Identifier since database contains all Run 2 MDT chambers, e.g. also EI chambers which are
816 // potentially replaced by NSW
817 bool isValid{false}; // the elementID takes a bool pointer to check the validity of the Identifier
818 const Identifier chId = idHelper.elementID(stName, ieta, iphi, isValid);
819 if (!isValid) {
820 static std::atomic<bool> idWarningPrinted = false;
821 if (!idWarningPrinted) {
822 ATH_MSG_WARNING("Element Identifier " << chId.get_compact() << " retrieved for station name " << stName
823 << " is not valid, skipping");
824 idWarningPrinted.store(true, std::memory_order_relaxed);
825 }
826 continue;
827 }
828
829 if (writeCdo.hasDataForChannel(chId, msgStream())) {
830 const MdtFullCalibData* dataObj = writeCdo.getCalibData(chId, msgStream());
831 if (dataObj->tubeCalib) {
832 ATH_MSG_DEBUG("Rt relation constants for "<<m_idHelperSvc->toString(chId)<<" already exists");
833 continue;
834 }
835 }
836
837 TubeContainerPtr tubes = std::make_unique<MdtTubeCalibContainer>(m_idHelperSvc.get(), chId);
838 if (!writeCdo.storeData(chId, tubes, msgStream())) {
839 ATH_MSG_FATAL(__FILE__<<":"<<__LINE__<<" Failed to add chamber "<<m_idHelperSvc->toString(chId)
840 <<" ID fields: "<<stName<<","<<ieta<<","<<iphi);
841 return StatusCode::FAILURE;
842 }
843 //const ref. No copy
844 const nlohmann::json& tubeConstants = chambChannel["calibConstants"];
845 for (const auto& tubeChannel : tubeConstants) {
846 const int ml = tubeChannel["ml"];
847 const int l = tubeChannel["layer"];
848 const int t = tubeChannel["tube"];
849 double tzero = tubeChannel["t0"];
850 if (m_t0Shift != 0.) {
851 tzero += m_t0Shift;
852 ATH_MSG_VERBOSE("T0 shift " << m_t0Shift << " t0 " << tzero << " id " << ml << " " << l << " " << t);
853 }
854 if (m_t0Spread != 0.) {
855 CLHEP::HepRandomEngine *engine = m_RNGWrapper->getEngine(ctx);
856 double sh = CLHEP::RandGaussZiggurat::shoot(engine, 0., m_t0Spread);
857 tzero += sh;
858 ATH_MSG_VERBOSE("T0 spread " << sh << " t0 " << tzero << " id " << ml << " " << l << " " << t);
859 }
860 if (!t0_ts_applied && m_TimeSlewingCorrection) { tzero += m_TsCorrectionT0; }
861 if (t0_ts_applied && !m_TimeSlewingCorrection) { tzero -= m_TsCorrectionT0; }
862
863 const int statusCode = tubeChannel["status"];
864 const double meanAdc = tubeChannel["meanAdc"];
866 datatube.statusCode = statusCode;
867 datatube.t0 = tzero;
868 datatube.adcCal = meanAdc;
869 const Identifier tubeId = idHelper.channelID(chId, ml, l, t);
870 tubes->setCalib(std::move(datatube), tubeId, msgStream());
871 }
872 } // end loop over readCdoTube
873
874 ATH_CHECK(defaultT0s(writeCdo));
875 // finally record writeCdo
876 return StatusCode::SUCCESS;
877}
878
879std::unique_ptr<MuonCalib::RtResolutionLookUp> MdtCalibDbAlg::getRtResolutionInterpolation(const std::vector<MuonCalib::SamplePoint> &sample_points) {
881 // VARIABLES //
883 std::vector<Double_t> x(sample_points.size(),0);
884 std::vector<Double_t> y(sample_points.size(),0);
885
886 for (unsigned int i = 0; i < sample_points.size(); i++) {
887 x[i] = sample_points[i].x1();
888 y[i] = sample_points[i].x2();
889 }
890 TSpline3 sp("Rt Res Tmp", x.data(), y.data(), sample_points.size());
892 // CREATE AN RtRelationLookUp OBJECT WITH THE CORRECT PARAMETERS //
894 unsigned int nb_points(100);
895 std::vector<double> res_param(nb_points + 2); // r-t parameters
896 Double_t bin_width = (x[sample_points.size() - 1] - x[0]) / static_cast<Double_t>(nb_points);
897
898 res_param[0] = x[0];
899 res_param[1] = bin_width;
900 for (unsigned int k = 0; k < nb_points; k++) {
901 Double_t xx = x[0] + k * bin_width;
902 res_param[k + 2] = sp.Eval(xx);
903 if (std::isnan(res_param[k + 2])) {
904 TFile outf("kacke.root", "RECREATE");
905 sp.Write("kacke");
906 THROW_EXCEPTION("MdtCalibDbAlg::getRtResolutionInterpolation "
907 "encountered nan element");
908 }
909 }
910 return std::make_unique<MuonCalib::RtResolutionLookUp>(std::move(res_param));
911}
912}
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#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_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
bool isValid(const T &p)
Av: we implement here an ATLAS-sepcific convention: all particles which are 99xxxxx are fine.
Definition AtlasPID.h:878
This file defines the class for a collection of AttributeLists where each one is associated with a ch...
static boost::dynamic_bitset rshift(boost::dynamic_bitset<> const &b, int n)
char data[hepevt_bytes_allocation_ATLAS]
Definition HepEvt.cxx:11
nlohmann::json json
Abstract interface to IOVDbSvc to access IOVRange and tag information.
static Double_t sp
static Double_t t0
MdtFullCalibData::CorrectionPtr CorrectionPtr
MdtFullCalibData::TubeContainerPtr TubeContainerPtr
MdtCalibDataContainer::RegionGranularity RegionGranularity
int sign(int a)
#define y
#define x
const ServiceHandle< StoreGateSvc > & detStore() const
bool msgLvl(const MSG::Level lvl) const
ChanAttrListMap::const_iterator const_iterator
static EventIDRange infiniteTime()
Produces an EventIDRange that is inifinite in Time and invalid in RunLumi.
value_type get_compact() const
Get the compact id.
const DcsConstants & getHvState(const Identifier &multiLayerID) const
Identifier multilayerID(const Identifier &channeldID) const
int multilayer(const Identifier &id) const
Access to components of the ID.
Identifier elementID(int stationName, int stationEta, int stationPhi) const
int tube(const Identifier &id) const
static int tubeLayerMax()
int tubeLayer(const Identifier &id) const
int numberOfMultilayers(const Identifier &id) const
int tubeMax() const
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int tubeLayer, int tube) const
std::vector< double > ParVec
Definition CalibFunc.h:35
bool storeData(const Identifier &mlID, CorrectionPtr corrFuncSet, MsgStream &msg)
bool hasDataForChannel(const Identifier &measId, MsgStream &msg) const
Checks whether a calibration data object is already present.
void setInversePropSpeed(const float speed)
const MdtFullCalibData * getCalibData(const Identifier &measId, MsgStream &msg) const
Returns the calibration data associated with this station.
void setBField(std::unique_ptr< IMdtBFieldCorFunc > &&bField)
void setSlewing(std::unique_ptr< IMdtSlewCorFunc > &&slew)
bool setCalib(SingleTubeCalib val, const Identifier &tubeId, MsgStream &msg)
set the calibration constants of a single tube
Implements fixed identifiers not dependent upon Athena Identifier for internal use in the calibration...
Definition MuonFixedId.h:50
Manages the I/O of the Rt realtions from/to file.
std::vector< double > DataVec
static std::unique_ptr< IRtRelation > getRtRelationLookUp(const std::vector< SamplePoint > &sample_points)
This class provides a sample point for the BaseFunctionFitter.
Definition SamplePoint.h:15
double x2() const
get the error on the x2 coordinate of the sample point
Definition SamplePoint.h:44
void set_error(const double merror)
Definition SamplePoint.h:62
void set_x2(const double mx2)
set the error of the x2 coordinate sample point to merror
Definition SamplePoint.h:60
void set_x1(const double mx1)
set the x2 coordinate of the sample point to mx2
Definition SamplePoint.h:58
double x1() const
< get the x1 coordinate of the sample point
Definition SamplePoint.h:42
Readout element to describe the Monitored Drift Tube (Mdt) chambers Mdt chambers usually comrpise out...
double innerTubeRadius() const
Returns the inner tube radius.
double innerTubeRadius() const
Returns the inner tube radius excluding the aluminium walls.
std::vector< Identifier >::const_iterator const_id_iterator
const_id_iterator module_end() const
const_id_iterator module_begin() const
Iterators over full set of ids.
const_id_iterator detectorElement_begin() const
Iterators over full set of ids.
const_id_iterator detectorElement_end() const
MuonCalib::MdtFullCalibData::RtRelationPtr RtRelationPtr
StatusCode legacyTubePayloadToJSON(const coral::AttributeList &attr, nlohmann::json &json) const
virtual StatusCode execute(const EventContext &ctx) const override
std::optional< double > getInnerTubeRadius(const Identifier &id) const
StatusCode declareDependency(const EventContext &ctx, SG::WriteCondHandle< MuonCalib::MdtCalibDataContainer > &writeHandle) const
SG::ReadCondHandleKey< CondAttrListCollection > m_readKeyTube
SG::WriteCondHandleKey< MuonCalib::MdtCalibDataContainer > m_writeKey
StatusCode defaultRt(MuonCalib::MdtCalibDataContainer &writeCdoRt, LoadedRtMap &loadedRts) const
Gaudi::Property< bool > m_checkTubes
only needed to retrieve information on number of tubes etc. (no alignment needed)
StatusCode loadTube(const EventContext &ctx, MuonCalib::MdtCalibDataContainer &writeCdo) const
ToolHandle< MuonCalib::IIdToFixedIdTool > m_idToFixedIdTool
StatusCode legacyRtPayloadToJSON(const coral::AttributeList &attr, nlohmann::json &json) const
Parses the legacy payload for the RT functions to a json format.
StatusCode defaultT0s(MuonCalib::MdtCalibDataContainer &writeCdoTube) const
static std::unique_ptr< MuonCalib::RtResolutionLookUp > getRtResolutionInterpolation(const std::vector< MuonCalib::SamplePoint > &sample_points)
StatusCode loadRt(const EventContext &ctx, MuonCalib::MdtCalibDataContainer &writeCdo) const
SG::ReadCondHandleKey< CondAttrListCollection > m_readKeyRt
static std::string find_calib_file(const std::string &logical_file_name)
const DataObjID & fullKey() const
const EventIDRange & getRange()
const_pointer_type cptr()
void addDependency(const EventIDRange &range)
StatusCode record(const EventIDRange &range, T *t)
record handle, with explicit range DEPRECATED
const DataObjID & fullKey() const
bool readBlobAsString(const coral::Blob &, std::string &)
std::vector< int > tokenizeInt(const std::string &the_str, std::string_view delimiter)
std::vector< std::string > tokenize(const std::string &the_str, std::string_view delimiters)
Splits the string into smaller substrings.
std::vector< double > tokenizeDouble(const std::string &the_str, std::string_view delimiter)
int atoi(std::string_view str)
Helper functions to unpack numbers decoded in string into integers and doubles The strings are requir...
CscCalcPed - algorithm that finds the Cathode Strip Chamber pedestals from an RDO.
const std::string & stName(StIndex index)
convert StIndex into a string
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
class which holds the full set of calibration constants for a given tube
GeoModel::TransientConstSharedPtr< MdtTubeCalibContainer > TubeContainerPtr
GeoModel::TransientConstSharedPtr< MdtCorFuncSet > CorrectionPtr
float adcCal
quality flag for the SingleTubeCalib constants: 0 all ok, 1 no hits found, 2 too few hits,...
Helper struct to cache all dcs constants in a common place of the memory.
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10