ATLAS Offline Software
Loading...
Searching...
No Matches
NSWCalibTool.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 "NSWCalibTool.h"
6#include "GaudiKernel/SystemOfUnits.h"
7#include "GaudiKernel/PhysicalConstants.h"
10
13#include <cfloat>
14namespace {
15 constexpr double toRad = M_PI/180;
16 constexpr double pitchErr = 0.425 * 0.425 / 12;
17 constexpr double reciprocalSpeedOfLight = 1. / Gaudi::Units::c_light; // mm/ns
18
19 // since the final operation gas is not yet fixed different, different mixtures are added for studies
20 static const std::map<std::string, float> map_transDiff {{"ArCo2_937", 0.036},
21 {"ArCo2_8020", 0.019}, {"ArCo2iC4H10_9352", 0.035}};
22 static const std::map<std::string, float> map_longDiff {{"ArCo2_937", 0.019},
23 {"ArCo2_8020", 0.022 }, {"ArCo2iC4H10_9352", 0.0195}};
24 static const std::map<std::string, float> map_vDrift {{"ArCo2_937", 0.047},
25 {"ArCo2_8020", 0.040}, {"ArCo2iC4H10_9352", 0.045}};
26
27
28 // unit correction factors
29 constexpr double const MM_electronsPerfC = 6241.;
30 constexpr double const sTGC_pCPerfC = 1000.;
31
32
33 //Functional form fit to agree with Garfield simulations. Fit and parameters from G. Iakovidis
34 // For now only the parametrisation for 93:7 is available
35 using angleFunction = NSWCalib::MicroMegaGas::angleFunction;
36 static const std::map<std::string, angleFunction> map_lorentzAngleFunctionPars {
37 {"ArCo2_937", [](double x) {return 0.f + 58.87f*x -2.983f*x*x -10.62f*x*x*x + 2.818f*x*x*x*x;}},
38 {"ArCo2_8020", [](double x) {return 0.f + 58.87f*x -2.983f*x*x -10.62f*x*x*x + 2.818f*x*x*x*x;}},
39 {"ArCo2iC4H10_9352", [](double x) {return 0.f + 58.87f*x -2.983f*x*x -10.62f*x*x*x + 2.818f*x*x*x*x;}}};
40
41 // For now only the parametrisation for 93:7 is available
42 static const std::map<std::string, float> map_interactionDensitySigma {{"ArCo2_937", 4.04 / 5.},
43 {"ArCo2_8020", 4.04 / 5.}, {"ArCo2iC4H10_9352", 4.04 / 5.}};
44 static const std::map<std::string, float> map_interactionDensityMean {{"ArCo2_937", 16.15 / 5.},
45 {"ArCo2_8020", 16.15 / 5.}, {"ArCo2iC4H10_9352", 16.15 / 5.}};
46
47}
48
50{
51 ATH_MSG_DEBUG("In initialize()");
52 ATH_CHECK(m_idHelperSvc.retrieve());
53 ATH_CHECK(m_condTdoPdoKey.initialize());
56 ATH_CHECK(m_muDetMgrKey.initialize());
60 return StatusCode::SUCCESS;
61}
62
64 if (!map_vDrift.count(m_gasMixture)) {
65 ATH_MSG_FATAL("Configured Micromegas with unkown gas mixture: " << m_gasMixture);
66 return StatusCode::FAILURE;
67 }
68
69 m_vDrift = map_vDrift.find(m_gasMixture)->second;
70 m_transDiff = map_transDiff.find(m_gasMixture)->second;
71 m_longDiff = map_longDiff.find(m_gasMixture)->second;
72 m_interactionDensitySigma = map_interactionDensitySigma.find(m_gasMixture)->second;
73 m_interactionDensityMean = map_interactionDensityMean.find(m_gasMixture)->second;
74 m_lorentzAngleFunction = map_lorentzAngleFunctionPars.find(m_gasMixture)->second;
75 return StatusCode::SUCCESS;
76}
77StatusCode Muon::NSWCalibTool::calibrateClus(const EventContext& ctx, const Muon::MMPrepData* prepData, const Amg::Vector3D& globalPos, std::vector<NSWCalib::CalibratedStrip>& calibClus) const {
78
79 double lorentzAngle {0.};
83 ATH_CHECK(loadMagneticField(ctx, fieldCache));
84 Amg::Vector3D magneticField{Amg::Vector3D::Zero()};
85 fieldCache.getField(globalPos.data(), magneticField.data());
86
88 double phi = globalPos.phi();
89 double bfield = (magneticField.x()*std::sin(phi)-magneticField.y()*std::cos(phi))*1000.;
90
92 int gasGap = m_idHelperSvc->mmIdHelper().gasGap(prepData->identify());
93 bool changeSign = ( globalPos.z() < 0. ? (gasGap==1 || gasGap==3) : (gasGap==2 || gasGap==4) );
94 if (changeSign) bfield = -bfield;
95
97 lorentzAngle = (bfield>0. ? 1. : -1.)*m_lorentzAngleFunction(std::abs(bfield)) * toRad;
98 }
99
101 for (unsigned int i = 0; i < prepData->stripNumbers().size(); ++i){
102 Identifier id = prepData->rdoList().at(i);
103 double time = prepData->stripTimes().at(i);
104 double charge = prepData->stripCharges().at(i);
105 //Retrieve pointing constraint
106 const Amg::Vector3D& globPos{prepData->globalPosition()};
107 NSWCalib::CalibratedStrip calibStrip;
108 ATH_CHECK(calibrateStrip(ctx, id, time, charge, (globPos.theta() / toRad) , lorentzAngle, calibStrip));
109
110 calibClus.push_back(std::move(calibStrip));
111 }
112 return StatusCode::SUCCESS;
113}
114
115
116StatusCode Muon::NSWCalibTool::calibrateClus(const EventContext& ctx,
117 const ActsTrk::GeometryContext& gctx,
118 const xAOD::MMCluster& prepData,
119 const Amg::Vector3D& globalPos,
120 std::vector<NSWCalib::CalibratedStrip>& calibClus) const {
121
122 double lorentzAngle {0.};
125 MagField::AtlasFieldCache fieldCache;
126 ATH_CHECK(loadMagneticField(ctx, fieldCache));
127 Amg::Vector3D magneticField{Amg::Vector3D::Zero()};
128 fieldCache.getField(globalPos.data(), magneticField.data());
129
131 double phi = globalPos.phi();
132 double bfield = (magneticField.x()*std::sin(phi)-magneticField.y()*std::cos(phi))*1000.;
133
135 int gasGap = m_idHelperSvc->mmIdHelper().gasGap(prepData.identify());
136 bool changeSign = ( globalPos.z() < 0. ? (gasGap==1 || gasGap==3) : (gasGap==2 || gasGap==4) );
137 if (changeSign) bfield = -bfield;
138
140 lorentzAngle = (bfield>0. ? 1. : -1.)*m_lorentzAngleFunction(std::abs(bfield)) * toRad;
141 }
142
144 for (unsigned int i = 0; i < prepData.stripNumbers().size(); ++i){
145 Identifier id = m_idHelperSvc->mmIdHelper().channelID(prepData.identify(), m_idHelperSvc->mmIdHelper().multilayer(prepData.identify()), m_idHelperSvc->mmIdHelper().gasGap(prepData.identify()),prepData.stripNumbers().at(i));
146 double time = prepData.stripTimes().at(i);
147 double charge = prepData.stripCharges().at(i);
148 //Retrieve pointing constraint
149 const Amg::Vector3D& globPos{prepData.readoutElement()->localToGlobalTransform(gctx, prepData.layerHash()) * (prepData.localPosition<1>()[0]*Amg::Vector3D::UnitX())};
150 NSWCalib::CalibratedStrip calibStrip;
151 ATH_CHECK(calibrateStrip(ctx, id, time, charge, (globPos.theta() / toRad) , lorentzAngle, calibStrip));
152
153 calibClus.push_back(std::move(calibStrip));
154 }
155 return StatusCode::SUCCESS;
156}
157
158
159
160StatusCode Muon::NSWCalibTool::calibrateStrip(const EventContext& ctx,
161 const Identifier& id,
162 const double time,
163 const double charge,
164 const double theta,
165 const double lorentzAngle,
166 NSWCalib::CalibratedStrip& calibStrip) const {
167 //get local positon
168 auto locPos = localStripPosition(ctx, id);
169 if(!locPos) {
170 ATH_MSG_WARNING(__FILE__<<":"<<__LINE__<<" Failed to retrieve local strip position "<<m_idHelperSvc->toString(id));
171 return StatusCode::FAILURE;
172 }
173
174 calibStrip.identifier = id;
175 calibStrip.charge = charge;
176 calibStrip.time = time;
177
178 const MmIdHelper& idHelper{m_idHelperSvc->mmIdHelper()};
179
180 //retrieve identifier for the gas gap, not necessarily for the channel
181 //There is no pcb segmentation for these corrections, stored with pcb = 1 as default
182 Identifier gasGapId = idHelper.channelID(id,
183 idHelper.multilayer(id),
184 idHelper.gasGap(id), 1);
185
186 double vDrift = m_vDrift; //nominal value from Garfield simulation
187
189 const MmCTPClusterCalibData* ctpCalibData{nullptr};
190 ATH_CHECK(SG::get(ctpCalibData, m_ctpClusterCalibKey, ctx));
191 vDrift = ctpCalibData->getCTPCorrectedDriftVelocity(gasGapId, theta);
192
193 //Calculate the new half max possible time based on the new drift velocity
194 float max_half_drifttime = (vDrift != 0 ) ? 2.5/vDrift : 50.;
195
196 //Shift the mean of the time to account for different values of drift velocities
197 calibStrip.time = time + (max_half_drifttime - m_mmT0TargetValue);
198 ATH_MSG_VERBOSE( "Original drift time: " << time << " new max half drift time: " << max_half_drifttime
199 << " new time: " << calibStrip.time << " targett0 " << m_mmT0TargetValue );
200 }
201
202
203 double vDriftCorrected = vDrift * std::cos(lorentzAngle);
204
205 calibStrip.distDrift = vDriftCorrected * calibStrip.time;
206
208 calibStrip.resTransDistDrift = pitchErr + std::pow(m_transDiff * calibStrip.distDrift, 2);
209 calibStrip.resLongDistDrift = std::pow(m_ionUncertainty * vDriftCorrected, 2)
210 + std::pow(m_longDiff * calibStrip.distDrift, 2);
211 calibStrip.dx = std::sin(lorentzAngle) * calibStrip.time * vDrift;
212 calibStrip.locPos = Amg::Vector2D{locPos->x() + calibStrip.dx, locPos->y()};
213 return StatusCode::SUCCESS;
214}
215
216
217StatusCode Muon::NSWCalibTool::calibrateStrip(const EventContext& ctx,
218 const Muon::MM_RawData* mmRawData,
219 NSWCalib::CalibratedStrip& calibStrip) const {
220
221 const Identifier& rdoId = mmRawData->identify();
222
223 const MuonGM::MuonDetectorManager* muDetMgr{nullptr};
224 ATH_CHECK(SG::get(muDetMgr, m_muDetMgrKey, ctx));
225
226 //get globalPos
227 Amg::Vector3D globalPos{Amg::Vector3D::Zero()};
228 const MuonGM::MMReadoutElement* detEl = muDetMgr->getMMReadoutElement(rdoId);
229 if (!detEl->stripGlobalPosition(rdoId, globalPos)) {
230 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - Failed to fetch global position for "
231 <<m_idHelperSvc->toString(rdoId));
232 return StatusCode::FAILURE;
233 }
234
235 // RDO has values in counts for both simulation and data
236 float time{-std::numeric_limits<float>::max()},
237 charge{-std::numeric_limits<float>::max()};
238 tdoToTime (ctx, mmRawData->timeAndChargeInCounts(), mmRawData->time(), rdoId, time, mmRawData->relBcid());
239 pdoToCharge(ctx, mmRawData->timeAndChargeInCounts(), mmRawData->charge(), rdoId, charge);
240
241 calibStrip.charge = charge;
242 // historically the peak time is included in the time determined by the MM digitization and therefore added back in the tdoToTime function
243 // in order to not break the RDO to digit conversion needed for the trigger and the overlay
244 calibStrip.time = time - globalPos.norm() * reciprocalSpeedOfLight - mmPeakTime();
245 // applying T0 calibration, cannot be done inside the the tdo to time function since the tof correction was included when deriving the calibration constants
247 calibStrip.time = applyT0Calibration(ctx, rdoId, calibStrip.time);
248 }
249
250 calibStrip.identifier = rdoId;
251
252 ATH_MSG_DEBUG(__func__<<"() "<<__LINE__<<" - Calibrating RDO " << m_idHelperSvc->toString(rdoId)
253 << " with pdo: " << mmRawData->charge() << ", tdo: "<< mmRawData->time()
254 << ", relBCID "<< mmRawData->relBcid() << ", charge and time in counts: "
255 << mmRawData->timeAndChargeInCounts() <<", "<< m_isData << " to charge: "
256 << calibStrip.charge << " electrons time after corrections " << calibStrip.time
257 << " ns time before corrections "<< time << "ns");
258 //get stripWidth
259 detEl->getDesign(rdoId)->channelWidth(); // positon is not used for strip width
260
261 calibStrip.distDrift = m_vDrift * calibStrip.time;
262 calibStrip.resTransDistDrift = pitchErr + std::pow(m_transDiff * calibStrip.distDrift, 2);
263 calibStrip.resLongDistDrift = std::pow(m_ionUncertainty * m_vDrift, 2)
264 + std::pow(m_longDiff * calibStrip.distDrift, 2);
265
267 detEl->surface(rdoId).globalToLocal(globalPos, Amg::Vector3D::Zero(), calibStrip.locPos);
268
269 return StatusCode::SUCCESS;
270}
271
272StatusCode Muon::NSWCalibTool::calibrateStrip(const EventContext& ctx,
273 const Muon::STGC_RawData* sTGCRawData,
274 NSWCalib::CalibratedStrip& calibStrip) const {
275
276 const Identifier& rdoId = sTGCRawData->identify();
277 const MuonGM::MuonDetectorManager* muDetMgr{nullptr};
278 ATH_CHECK(SG::get(muDetMgr, m_muDetMgrKey, ctx));
279
280 //get globalPos
281 Amg::Vector3D globalPos{Amg::Vector3D::Zero()};
282 const MuonGM::sTgcReadoutElement* detEl = muDetMgr->getsTgcReadoutElement(rdoId);
283 if (!detEl->stripGlobalPosition(rdoId,globalPos)) {
284 ATH_MSG_WARNING(__func__<<"() "<<__LINE__<<" - Failed to retrieve a valid global position for "
285 <<m_idHelperSvc->toString(rdoId));
286 return StatusCode::FAILURE;
287 }
288 // RDO has values in counts for both simulation and data
289 float time{-std::numeric_limits<float>::max()}, charge{-std::numeric_limits<float>::max()};
290 tdoToTime(ctx, sTGCRawData->timeAndChargeInCounts(), sTGCRawData->time(), rdoId, time, sTGCRawData->bcTag());
291 pdoToCharge(ctx, sTGCRawData->timeAndChargeInCounts(), sTGCRawData->charge(), rdoId, charge);
292 if(sTGCRawData->timeAndChargeInCounts()){
293 calibStrip.charge = charge * sTGC_pCPerfC;
294 } else {
295 calibStrip.charge = charge;
296 }
297 calibStrip.time = time - stgcPeakTime();
298
300 calibStrip.time = applyT0Calibration(ctx, rdoId, calibStrip.time);
301 }
302
303 calibStrip.identifier = rdoId;
305 detEl->surface(rdoId).globalToLocal(globalPos, Amg::Vector3D::Zero(), calibStrip.locPos);
306
307 return StatusCode::SUCCESS;
308
309}
310StatusCode Muon::NSWCalibTool::loadMagneticField(const EventContext& ctx, MagField::AtlasFieldCache& fieldCache) const {
311 const AtlasFieldCacheCondObj* condObj{};
313 condObj->getInitializedCache(fieldCache);
314 return StatusCode::SUCCESS;
315}
316StatusCode Muon::NSWCalibTool::distToTime(const EventContext& ctx,
317 const Muon::MMPrepData* prepData,
318 const Amg::Vector3D& globalPos,
319 const std::vector<double>& driftDistances,
320 std::vector<double>& driftTimes) const {
322 MagField::AtlasFieldCache fieldCache;
323 ATH_CHECK(loadMagneticField(ctx, fieldCache));
324 Amg::Vector3D magneticField{Amg::Vector3D::Zero()};
325 fieldCache.getField(globalPos.data(), magneticField.data());
326
328 const double phi = globalPos.phi();
329 double bfield = (magneticField.x()*std::sin(phi)-magneticField.y()*std::cos(phi))*1000.;
330
332 int gasGap = m_idHelperSvc->mmIdHelper().gasGap(prepData->identify());
333 bool changeSign = ( globalPos.z() < 0. ? (gasGap==1 || gasGap==3) : (gasGap==2 || gasGap==4) );
334 if (changeSign) bfield = -bfield;
335 double cos2_lorentzAngle = std::pow(std::cos ( (bfield>0. ? 1. : -1.)*m_lorentzAngleFunction(std::abs(bfield)) * toRad), 2);
337 for (const double dist : driftDistances){
338 double time = dist / (m_vDrift*cos2_lorentzAngle);
339 driftTimes.push_back(time);
340 }
341 return StatusCode::SUCCESS;
342
343}
344
345bool
346Muon::NSWCalibTool::chargeToPdo(const EventContext& ctx, const float charge, const Identifier& chnlId, int& pdo) const {
347 const NswCalibDbTimeChargeData* tdoPdoData{nullptr};
348 if (!SG::get(tdoPdoData, m_condTdoPdoKey, ctx)) {
349 pdo = 0;
350 return false;
351 }
352 const TimeCalibConst* calib_ptr = tdoPdoData->getCalibForChannel(TimeCalibType::PDO, chnlId);
353 if (!calib_ptr) {
354 pdo = 0;
355 return false;
356 }
357 const TimeCalibConst& calib{*calib_ptr};
358 float c = charge;
359 if (m_idHelperSvc->isMM (chnlId)) c /= MM_electronsPerfC;
360 else if(m_idHelperSvc->issTgc(chnlId)) c *= sTGC_pCPerfC;
361 else {
362 pdo = 0;
363 return false;
364 }
365 pdo = c * calib.slope + calib.intercept;
366 return true;
367}
368
369bool
370Muon::NSWCalibTool::pdoToCharge(const EventContext& ctx,
371 const bool inCounts,
372 const int pdo,
373 const Identifier& chnlId,
374 float& charge) const {
375 if(!inCounts){
376 charge = pdo;
377 return true;
378 }
379 const NswCalibDbTimeChargeData* tdoPdoData{nullptr};
380 if (!SG::get(tdoPdoData, m_condTdoPdoKey, ctx)) {
381 charge = 0.;
382 return false;
383 }
384 const TimeCalibConst* calib_ptr = tdoPdoData->getCalibForChannel(TimeCalibType::PDO, chnlId);
385 if (!calib_ptr) {
386 charge = 0.;
387 return false;
388 }
389 const TimeCalibConst& calib{*calib_ptr};
390 charge = (pdo-calib.intercept)/calib.slope;
391 if (m_idHelperSvc->isMM (chnlId)) charge *= MM_electronsPerfC;
392 else if(m_idHelperSvc->issTgc(chnlId)) charge /= sTGC_pCPerfC;
393 else return false;
394 return true;
395}
396
397bool
398Muon::NSWCalibTool::timeToTdo(const EventContext& ctx, const float time, const Identifier& chnlId, int& tdo, int& relBCID) const {
399 const NswCalibDbTimeChargeData* tdoPdoData{nullptr};
400 if (!SG::get(tdoPdoData, m_condTdoPdoKey, ctx)) return false;
401 if (m_idHelperSvc->isMM (chnlId)) return timeToTdoMM (tdoPdoData, time, chnlId, tdo, relBCID);
402 else if(m_idHelperSvc->issTgc(chnlId)) return timeToTdoSTGC(tdoPdoData, time, chnlId, tdo, relBCID);
403 return false;
404}
405
406bool
407Muon::NSWCalibTool::timeToTdoMM(const NswCalibDbTimeChargeData* tdoPdoData, const float time, const Identifier& chnlId, int& tdo, int& relBCID) const {
408 const float t = time - m_mmPeakTime - m_mmLatencyMC; // subtract peaking time first! This is not supossed to run on data ever only needed for the RDO->Digit step
409 const TimeCalibConst* calib_ptr = tdoPdoData->getCalibForChannel(TimeCalibType::TDO, chnlId);
410 if (!calib_ptr) {
411 tdo = relBCID = 0;
412 return false;
413 }
414 const TimeCalibConst& calib{*calib_ptr};
415 float tdoTime = -999.9;
416 constexpr float lowerBound = Muon::MM_RawData::s_lowerTimeBound;
417 for(int i_relBCID=0; i_relBCID<Muon::MM_RawData::s_BCWindow; i_relBCID++){
418 if(t >= lowerBound+i_relBCID*25 && t < (lowerBound+25)+i_relBCID*25){
419 tdoTime = i_relBCID*25 - t;
420 relBCID = i_relBCID;
421 break;
422 }
423 }
424 if(tdoTime < lowerBound) {
425 tdo = relBCID = 0;
426 return false;
427 }
428 tdo = tdoTime*calib.slope + calib.intercept;
429 return true;
430}
431
432bool
433Muon::NSWCalibTool::timeToTdoSTGC(const NswCalibDbTimeChargeData* tdoPdoData, const float time, const Identifier& chnlId, int& tdo, int& relBCID) const {
434 const float t = time - m_stgcPeakTime - m_stgcLatencyMC; // subtract peaking time and latency first! This is not supossed to run on data ever only needed for the RDO->Digit step
435 const TimeCalibConst* calib_ptr = tdoPdoData->getCalibForChannel(TimeCalibType::TDO, chnlId);
436 if (!calib_ptr){
437 tdo = relBCID = 0;
438 return false;
439 }
440 const TimeCalibConst& calib = {*calib_ptr};
441 float tdoTime = -999.9;
442 const float lowerBound = Muon::STGC_RawData::s_lowerTimeBound - m_stgcLatencyMC; // this is not supossed to run on data ever, only needed for the RDO->Digit step
443 for(int i_relBCID=0; i_relBCID<Muon::STGC_RawData::s_BCWindow; ++i_relBCID){
444 if(t >= lowerBound+i_relBCID*25 && t < (lowerBound+25)+i_relBCID*25){
445 tdoTime = i_relBCID*25 - t;
446 relBCID = i_relBCID;
447 break;
448 }
449 }
450 if(tdoTime < lowerBound) {
451 tdo = relBCID = 0;
452 return false;
453 }
454 tdo = tdoTime*calib.slope + calib.intercept;
455 return true;
456}
457
458float Muon::NSWCalibTool::applyT0Calibration(const EventContext& ctx, const Identifier& id, float time) const {
459 const NswT0Data* readT0{nullptr};
460 if(!SG::get(readT0, m_condT0Key, ctx).isSuccess()){
461 ATH_MSG_ERROR("Cannot find conditions data container for T0s!");
462 }
463 std::optional<float> t0 = readT0->getT0(id);
464 if(!t0){
465 ATH_MSG_DEBUG("failed to retrieve good t0 from database, skipping t0 calibration");
466 return time;
467 }
468 const auto& targetT0 = (m_idHelperSvc->isMM(id) ? m_mmT0TargetValue : m_stgcT0TargetValue);
469 float newTime = time + (targetT0 - (*t0));
470 ATH_MSG_DEBUG("doing T0 calibration for RDO " << m_idHelperSvc->toString(id) << " time " << time
471 <<" t0 from database " << (*t0) << " t0 target " << targetT0 << " new time " << newTime);
472 return newTime;
473
474}
475
476
477bool
478Muon::NSWCalibTool::tdoToTime(const EventContext& ctx, const bool inCounts, const int tdo, const Identifier& chnlId, float& time, const int relBCID) const {
479 if(!inCounts){
480 time = tdo;
481 return true;
482 }
483 const NswCalibDbTimeChargeData* tdoPdoData{nullptr};
484 if (!SG::get(tdoPdoData, m_condTdoPdoKey, ctx)){
485 time = 0.;
486 return false;
487 }
488 const TimeCalibConst* calib_ptr = tdoPdoData->getCalibForChannel(TimeCalibType::TDO, chnlId);
489 if (!calib_ptr){
490 time = 0.;
491 return false;
492 }
493 const TimeCalibConst& calib {*calib_ptr};
494 //this shift of 25ns is necessary to align the time of the signal with the way the VMM determines the time
495 //(relBCID 0 corresponds to -37.5 ns to - 12.5 ns)
496 //Eventually it should go into the conditions db since it is probably not the same for MC and Data
497 //but for now it is kept like it is. pscholer 8th of June 2022
498 float mmLatency = (m_isData? m_mmLatencyData : m_mmLatencyMC );
499 float stgcLatency = (m_isData? m_stgcLatencyData : m_stgcLatencyMC);
500
501 const float peakTime = m_idHelperSvc->isMM(chnlId) ? mmPeakTime() + mmLatency : stgcPeakTime() + stgcLatency;
502 time = relBCID*25. - (tdo-calib.intercept)/calib.slope + peakTime;
503 return true;
504}
505
507 NSWCalib::MicroMegaGas properties{};
508 properties.driftVelocity = m_vDrift;
509 properties.longitudinalDiffusionSigma = m_longDiff;
510 properties.transverseDiffusionSigma = m_transDiff;
511 properties.interactionDensityMean = m_interactionDensityMean;
512 properties.interactionDensitySigma = m_interactionDensitySigma;
513 properties.lorentzAngleFunction = m_lorentzAngleFunction;
514 return properties;
515}
516
517
518std::optional<Amg::Vector2D> Muon::NSWCalibTool::localStripPosition(const EventContext& ctx,
519 const Identifier& id) const {
520
521 const MuonGM::MuonDetectorManager* muDetMgr{nullptr};
522 if (!SG::get(muDetMgr, m_muDetMgrKey, ctx)) {
523 THROW_EXCEPTION("Failed to retrieve the detector manager");
524 }
525 Amg::Vector2D locPos{Amg::Vector2D::Zero()};
526 if(m_idHelperSvc->isMM(id)){
527 if (!muDetMgr->getMMReadoutElement(id)->stripPosition(id,locPos)) {
528 return std::nullopt;
529 }
530 } else if(m_idHelperSvc->issTgc(id)){
531 if (!muDetMgr->getsTgcReadoutElement(id)->stripPosition(id,locPos)) {
532 return std::nullopt;
533 }
534 } else {
535 ATH_MSG_WARNING("Non NSW identifier "<<m_idHelperSvc->toString(id));
536 return std::nullopt;
537 }
538 return locPos;
539}
#define M_PI
Scalar phi() const
phi method
Scalar theta() const
theta method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
double charge(const T &p)
Definition AtlasPID.h:997
static Double_t t0
#define x
void getInitializedCache(MagField::AtlasFieldCache &cache) const
get B field cache for evaluation as a function of 2-d or 3-d position.
Local cache for magnetic field (based on MagFieldServices/AtlasFieldSvcTLS.h)
void getField(const double *ATH_RESTRICT xyz, double *ATH_RESTRICT bxyz, double *ATH_RESTRICT deriv=nullptr)
get B field value at given position xyz[3] is in mm, bxyz[3] is in kT if deriv[9] is given,...
Identifier channelID(int stationName, int stationEta, int stationPhi, int multilayer, int gasGap, int channel) const
int gasGap(const Identifier &id) const override
get the hashes
int multilayer(const Identifier &id) const
const Amg::Transform3D & localToGlobalTransform(const ActsTrk::GeometryContext &ctx) const
Returns the transformation from the local coordinate system of the readout element into the global AT...
An MMReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station con...
virtual bool stripPosition(const Identifier &id, Amg::Vector2D &pos) const override final
strip position – local or global If the strip number is outside the range of valid strips,...
const MuonChannelDesign * getDesign(const Identifier &id) const
returns the MuonChannelDesign class for the given identifier
bool stripGlobalPosition(const Identifier &id, Amg::Vector3D &gpos) const
virtual const Trk::PlaneSurface & surface() const override
access to chamber surface (phi orientation), uses the first gas gap
The MuonDetectorManager stores the transient representation of the Muon Spectrometer geometry and pro...
const MMReadoutElement * getMMReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
const sTgcReadoutElement * getsTgcReadoutElement(const Identifier &id) const
access via extended identifier (requires unpacking)
An sTgcReadoutElement corresponds to a single STGC module; therefore typicaly a barrel muon station c...
virtual bool stripPosition(const Identifier &id, Amg::Vector2D &pos) const override final
strip position - should be renamed to channel position If the strip number is outside the range of va...
bool stripGlobalPosition(const Identifier &id, Amg::Vector3D &gpos) const
Class to represent MM measurements.
Definition MMPrepData.h:22
const std::vector< uint16_t > & stripNumbers() const
returns the list of strip numbers
Definition MMPrepData.h:247
const std::vector< short int > & stripTimes() const
returns the list of times
Definition MMPrepData.h:252
virtual const Amg::Vector3D & globalPosition() const override final
Returns the global position.
Definition MMPrepData.h:211
const std::vector< int > & stripCharges() const
returns the list of charges
Definition MMPrepData.h:257
Temporary class to hold the MM RDO.
Definition MM_RawData.h:20
static constexpr int s_BCWindow
Definition MM_RawData.h:75
int time() const
Definition MM_RawData.h:62
static constexpr double s_lowerTimeBound
Definition MM_RawData.h:72
const Identifier & identify() const
Definition MM_RawData.h:58
uint16_t relBcid() const
Definition MM_RawData.h:63
bool timeAndChargeInCounts() const
Definition MM_RawData.h:65
int charge() const
Definition MM_RawData.h:64
double getCTPCorrectedDriftVelocity(const Identifier &identifier, const double theta) const
Gaudi::Property< bool > m_CalibDriftVelocityFromData
Gaudi::Property< float > m_mmT0TargetValue
bool timeToTdoMM(const NswCalibDbTimeChargeData *tdoPdoData, const float time, const Identifier &chnlId, int &tdo, int &relBCID) const
double m_interactionDensityMean
bool tdoToTime(const EventContext &ctx, const bool inCounts, const int tdo, const Identifier &chnlId, float &time, const int relBCID) const override
angleFunction m_lorentzAngleFunction
StatusCode distToTime(const EventContext &ctx, const MMPrepData *prepData, const Amg::Vector3D &globalPos, const std::vector< double > &driftDistances, std::vector< double > &driftTimes) const override
Gaudi::Property< double > m_ionUncertainty
double m_interactionDensitySigma
virtual StatusCode initialize() override
SG::ReadCondHandleKey< NswT0Data > m_condT0Key
Gaudi::Property< bool > m_applyMmT0Calib
Gaudi::Property< float > m_stgcT0TargetValue
SG::ReadCondHandleKey< MmCTPClusterCalibData > m_ctpClusterCalibKey
Gaudi::Property< bool > m_applyMmBFieldCalib
bool chargeToPdo(const EventContext &ctx, const float charge, const Identifier &chnlId, int &pdo) const override
SG::ReadCondHandleKey< MuonGM::MuonDetectorManager > m_muDetMgrKey
ServiceHandle< IMuonIdHelperSvc > m_idHelperSvc
bool timeToTdoSTGC(const NswCalibDbTimeChargeData *tdoPdoData, const float time, const Identifier &chnlId, int &tdo, int &relBCID) const
Gaudi::Property< float > m_mmLatencyData
Gaudi::Property< std::string > m_gasMixture
float applyT0Calibration(const EventContext &ctx, const Identifier &id, float time) const
Gaudi::Property< float > m_stgcPeakTime
SG::ReadCondHandleKey< AtlasFieldCacheCondObj > m_fieldCondObjInputKey
bool timeToTdo(const EventContext &ctx, const float time, const Identifier &chnlId, int &tdo, int &relBCID) const override
Gaudi::Property< double > m_transDiff
StatusCode initializeGasProperties()
Gaudi::Property< double > m_longDiff
float stgcPeakTime() const override
StatusCode loadMagneticField(const EventContext &ctx, MagField::AtlasFieldCache &fieldCache) const
Gaudi::Property< float > m_mmLatencyMC
Gaudi::Property< double > m_vDrift
Gaudi::Property< bool > m_applysTgcT0Calib
Gaudi::Property< float > m_stgcLatencyMC
SG::ReadCondHandleKey< NswCalibDbTimeChargeData > m_condTdoPdoKey
float mmPeakTime() const override
bool pdoToCharge(const EventContext &ctx, const bool inCounts, const int pdo, const Identifier &chnlId, float &charge) const override
Gaudi::Property< float > m_stgcLatencyData
StatusCode calibrateClus(const EventContext &ctx, const MMPrepData *prepData, const Amg::Vector3D &globalPos, std::vector< NSWCalib::CalibratedStrip > &calibClus) const override
NswCalibDbTimeChargeData::CalibConstants TimeCalibConst
StatusCode calibrateStrip(const EventContext &ctx, const Identifier &id, const double time, const double charge, const double theta, const double lorentzAngle, NSWCalib::CalibratedStrip &calibStrip) const override
Gaudi::Property< bool > m_isData
NSWCalib::MicroMegaGas mmGasProperties() const override
Gaudi::Property< float > m_mmPeakTime
std::optional< Amg::Vector2D > localStripPosition(const EventContext &ctx, const Identifier &id) const
bool timeAndChargeInCounts() const
static constexpr int s_BCWindow
static constexpr double s_lowerTimeBound
unsigned int charge() const
uint16_t bcTag() const
const Identifier identify() const
float time() const
const CalibConstants * getCalibForChannel(const CalibDataType type, const Identifier &channelId) const
Retrieves the calibration constant for a particular readout channel.
Conditions data object to calibrate the timeoff set of each individual channel in the NSW.
Definition NswT0Data.h:26
std::optional< float > getT0(const Identifier &channelId) const
Retrieve the t0 calibration constant for a given NSW channel.
Definition NswT0Data.cxx:62
virtual bool globalToLocal(const Amg::Vector3D &glob, const Amg::Vector3D &mom, Amg::Vector2D &loc) const override final
Specified for PlaneSurface: GlobalToLocal method without dynamic memory allocation - boolean checks i...
Identifier identify() const
return the identifier
const std::vector< Identifier > & rdoList() const
return the List of rdo identifiers (pointers)
const std::vector< uint16_t > & stripNumbers() const
returns the list of strip numbers
const Identifier & identify() const
: Returns the Athena identifier of the micro mega cluster It's constructed from the measurementHash &...
IdentifierHash layerHash() const
Returns the hash of the associated layer (Needed for surface retrieval)
const std::vector< int > & stripCharges() const
returns the list of charges
const std::vector< int16_t > & stripTimes() const
returns the list of times
const MuonGMR4::MmReadoutElement * readoutElement() const
Retrieve the associated MmReadoutElement.
ConstVectorMap< N > localPosition() const
Returns the local position of the measurement.
Eigen::Matrix< double, 2, 1 > Vector2D
Eigen::Matrix< double, 3, 1 > Vector3D
const T * get(const ReadCondHandleKey< T > &key, const EventContext &ctx)
Convenience function to retrieve an object given a ReadCondHandleKey.
MMCluster_v1 MMCluster
double channelWidth() const
calculate local channel width
std::function< double(double)> angleFunction
#define THROW_EXCEPTION(MESSAGE)
Definition throwExcept.h:10