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