ATLAS Offline Software
Loading...
Searching...
No Matches
NSWCalibSmearingTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
7
8#include "CLHEP/Random/RandFlat.h"
9#include "CLHEP/Random/RandGaussZiggurat.h"
10
11#include <iostream>
12#include <fstream>
13#include <string>
14#include "TString.h"
15
16using namespace Muon;
17
19 const std::string& n,
20 const IInterface* p ) :
21 AthAlgTool(t,n,p)
22{
23 declareInterface<INSWCalibSmearingTool>(this);
24}
25
27{
28 ATH_MSG_DEBUG("In initialize()");
29 ATH_CHECK(m_idHelperSvc.retrieve());
30
31 if ( !(m_idHelperSvc->hasMM() || m_idHelperSvc->hasSTGC() ) ) {
32 ATH_MSG_ERROR("MM or STGC not part of initialized detector layout");
33 return StatusCode::FAILURE;
34 }
35
36
39 }
40
41 return StatusCode::SUCCESS;
42}
43
44//
45// check if a hit is acceppted
46//
47StatusCode Muon::NSWCalibSmearingTool::isAccepted(const Identifier id, bool& accepted, CLHEP::HepRandomEngine* rndmEngine) const
48{
49 accepted = true;
50
51 int etaSector = 0;
52 int phiSector = 0;
53 int gasGap = 0;
54
55 if (!getIdFields(id,etaSector,phiSector,gasGap)) {
56 ATH_MSG_WARNING("Invalid identifier");
57 return StatusCode::SUCCESS;
58 }
59
61 float efficiencyCut = 0.0;
63 efficiencyCut = m_clusterEfficiency.value()[gasGap-1];
64 }
65 else {
66 // get the efficiency from the HV map and the parametrization
67 Identifier pcb_id;
68 if ( !getPCBIdentifier(id, pcb_id) ) {
69 ATH_MSG_ERROR("Could not convert the id " << m_idHelperSvc->toString(id) << " to a PCB identifier" );
70 return StatusCode::FAILURE;
71 }
72
73 // get the HV
74 std::map<Identifier,float>::const_iterator it = m_hvMap.find(pcb_id);
75 if ( it != m_hvMap.end() ) {
76 double hv = it->second;
77 efficiencyCut = getMMEfficiencyFromHV(hv);
78 }
79 else {
80 ATH_MSG_WARNING("PCB Id not found in the HV map " << m_idHelperSvc->toString(pcb_id));
81 accepted = true;
82 return StatusCode::SUCCESS;
83 }
84 }
85
87 if ( CLHEP::RandFlat::shoot(rndmEngine, 0. , 1.) > efficiencyCut ) {
88 accepted = false;
89 }
90
91 return StatusCode::SUCCESS;
92
93}
94
95
96//
97// smear only the charge
98//
99StatusCode Muon::NSWCalibSmearingTool::smearCharge(Identifier id, float& charge, bool& accepted, CLHEP::HepRandomEngine* rndmEngine) const
100{
101
102 ATH_MSG_DEBUG("Smearing the strips charge");
103
104 int etaSector = 0;
105 int phiSector = 0;
106 int gasGap = 0;
107
108 if (!getIdFields(id,etaSector,phiSector,gasGap)) {
109 ATH_MSG_WARNING("Invalid identifier");
110 return StatusCode::SUCCESS;
111 }
113
114
115 float efficiencyCut = 0.0;
117 efficiencyCut = m_clusterEfficiency.value()[gasGap-1];
118 }
119 else {
120 // get the efficiency from the HV map and the parametrization
121 Identifier pcb_id;
122 if ( !getPCBIdentifier(id, pcb_id) ) {
123 ATH_MSG_ERROR("Could not convert the id " << m_idHelperSvc->toString(id) << " to a PCB identifier" );
124 return StatusCode::FAILURE;
125 }
126 // get the HV
127 std::map<Identifier,float>::const_iterator it = m_hvMap.find(pcb_id);
128 if ( it != m_hvMap.end() ) {
129 double hv = it->second;
130 efficiencyCut = getMMEfficiencyFromHV(hv);
131 }
132 else {
133 ATH_MSG_WARNING("PCB Id not found in the HV map " << m_idHelperSvc->toString(pcb_id));
134 accepted = true;
135 return StatusCode::SUCCESS;
136 }
137 }
138
139 if ( m_phiSectors.value()[phiSector-1] && m_etaSectors.value()[etaSector-1] ) {
140 // smear charge
141 double chargeSmear = m_chargeSmear.value()[gasGap-1];
142 charge = charge + CLHEP::RandGaussZiggurat::shoot(rndmEngine,0.0, chargeSmear);
143
144 // check if the single strip can be accepted
145 accepted = true;
146 if ( CLHEP::RandFlat::shoot(rndmEngine, 0. , 1.) > efficiencyCut ) {
147 accepted = false;
148 }
149 }
150
151 return StatusCode::SUCCESS;
152}
153
154//
155// smear time and charge
156//
157StatusCode Muon::NSWCalibSmearingTool::smearTimeAndCharge(Identifier id, float& time, float& charge, bool& accepted, CLHEP::HepRandomEngine* rndmEngine) const
158{
159
160 if ( m_idHelperSvc->issTgc(id) ) {
161 ATH_MSG_ERROR("Can't smear time for the STGC's");
162 return StatusCode::FAILURE;
163 }
164
165 int etaSector = 0;
166 int phiSector = 0;
167 int gasGap = 0;
168
169 if (!getIdFields(id,etaSector,phiSector,gasGap)) {
170 ATH_MSG_WARNING("Invalid identifier");
171 return StatusCode::SUCCESS;
172 }
173
174 if ( m_phiSectors.value()[phiSector-1] && m_etaSectors.value()[etaSector-1] ) {
175
176 // smear time and charge
177 double timeSmear = m_timeSmear.value()[gasGap-1];
178 double chargeSmear = m_chargeSmear.value()[gasGap-1];
179
180 time = time + CLHEP::RandGaussZiggurat::shoot(rndmEngine,0.0, timeSmear);
181 charge = charge + CLHEP::RandGaussZiggurat::shoot(rndmEngine,0.0, chargeSmear);
182
183 // check if the RDO can be accepted
184 accepted = true;
185 if ( CLHEP::RandFlat::shoot(rndmEngine, 0. , 1.) > m_channelEfficiency.value()[gasGap-1] ) {
186 accepted = false;
187 }
188 }
189
190 return StatusCode::SUCCESS;
191}
192
193//
194// get the fraction of the actual gain for a given gap
195//
197{
198 int etaSector = 0;
199 int phiSector = 0;
200 int gasGap = 0;
201
202 if (!getIdFields(id,etaSector,phiSector,gasGap)) {
203 ATH_MSG_WARNING("Invalid identifier");
204 return StatusCode::SUCCESS;
205 }
206
207 gainFraction = 1.0;
208
210 if ( m_phiSectors.value()[phiSector-1] && m_etaSectors.value()[etaSector-1] ) {
211 gainFraction = m_gainFraction.value()[gasGap-1];
212 }
213 }
214 else {
215 float hv = getHighVoltage(id);
216 if(hv == -2.0) { // could not convert id to PCB id
217 return StatusCode::FAILURE;
218 }
219 else if(hv == -1.0) { // could not find PCB in HV map
220 gainFraction = 1;
221 }
222 else {
223 gainFraction=getMMGainFractionFromHV(hv);
224 ATH_MSG_DEBUG("Got gain fraction: "<< gainFraction << " for id " << m_idHelperSvc->toString(id));
225 }
226 }
227 return StatusCode::SUCCESS;
228}
229
230
231//
232// get id fields for both STGC and MM
233//
234bool NSWCalibSmearingTool::getIdFields(const Identifier id, int& etaSector, int& phiSector, int& gasGap) const
235{
236 if ( m_idHelperSvc->isMM(id) ) {
237 int multilayer = m_idHelperSvc->mmIdHelper().multilayer(id);
238 gasGap = (multilayer-1)*4+m_idHelperSvc->mmIdHelper().gasGap(id);
239 etaSector = m_idHelperSvc->mmIdHelper().stationEta(id);
240 phiSector = m_idHelperSvc->mmIdHelper().stationPhi(id);
241 // transform the eta sector
242 etaSector < 0 ? etaSector = etaSector + 3 : etaSector = etaSector + 2;
243 }
244 else if ( m_idHelperSvc->issTgc(id) ) {
245 int multilayer = m_idHelperSvc->stgcIdHelper().multilayer(id);
246 gasGap = (multilayer-1)*4+m_idHelperSvc->stgcIdHelper().gasGap(id);
247 etaSector = m_idHelperSvc->stgcIdHelper().stationEta(id);
248 phiSector = m_idHelperSvc->stgcIdHelper().stationPhi(id);
249 // transform the eta sector
250 etaSector < 0 ? etaSector = etaSector + 4 : etaSector = etaSector + 3;
251 }
252 else {
253 ATH_MSG_WARNING("Wrong identifier: should be MM or STGC");
254 return false;
255 }
256
257
258 if ( phiSector < 1 || phiSector> (int) m_phiSectors.value().size()
259 || etaSector < (int) (-m_etaSectors.value().size()) || etaSector> (int) m_etaSectors.value().size() || etaSector==0
260 || gasGap < 1 || gasGap> (int) m_timeSmear.value().size() || gasGap>(int) m_chargeSmear.value().size() ) {
261 ATH_MSG_WARNING("Wrong phi, eta sector, or gasGap number: " << phiSector << " "
262 << etaSector << " " << gasGap << "Size of m_chargeSmear " << m_chargeSmear.value().size() << " size of m_etaSectors "<< m_etaSectors.value().size());
263 return false;
264 }
265
266 return true;
267}
268
269//
270// get the high voltage from a strip identifier
272{
273 Identifier pcbId;
274 bool foundPCB = getPCBIdentifier(stripId,pcbId);
275 if ( !foundPCB ) {
276 ATH_MSG_ERROR("Identifier " << m_idHelperSvc->toString(stripId) << " not converted" );
277 return -2.0;
278 }
279
280 double hv = -1.0;
281 std::map<Identifier,float>::const_iterator it = m_hvMap.find(pcbId);
282 if (it == m_hvMap.end() ) {
283 ATH_MSG_DEBUG("Identifier " << m_idHelperSvc->toString(pcbId) << " not found in the map" );
284 return -1.0;
285 }
286
287 hv = (*it).second;
288 return hv;
289}
290
291
292//
293// get the efficiency from the parametrization vs HV for the MM
295{
296
297 // sigmoid to paramtrize efficiency (initial values from BB5 measurements)
298 double eff = 1.0/(1+exp(-0.0551*(hv-510.54)));
299
300 return eff;
301}
302
303//
304// get the gain fraction from the parametrization vs HV for the MM
306{
307
308 // initial values from BB5 measurements. Scale cluster charge with respect to 570 V
309 return std::exp(-8.87971 + 0.0224561 * hv) / std::exp(-8.87971 + 0.0224561 * 570);
310
311}
312
313
314
316// get the PCB identifier as the identifier of the central strip ( 512 ) of each PCB (MM only)
319{
320
321 if ( m_idHelperSvc->isMM(id) ) {
322 // get the channel number
323 int channel = m_idHelperSvc->mmIdHelper().channel(id);
324 int pcb_strip = channel/1024;
325 pcb_strip = pcb_strip * 1024 + 512;
326
327 int stationName = m_idHelperSvc->mmIdHelper().stationName(id);
328 int stationEta = m_idHelperSvc->mmIdHelper().stationEta(id);
329 int stationPhi = m_idHelperSvc->mmIdHelper().stationPhi(id);
330
331 int multilayer = m_idHelperSvc->mmIdHelper().multilayer(id);
332 int gasGap = m_idHelperSvc->mmIdHelper().gasGap(id);
333
334 pcb_id = m_idHelperSvc->mmIdHelper().channelID(stationName,stationEta,stationPhi,multilayer,gasGap,pcb_strip);
335 }
336 else {
337 ATH_MSG_WARNING("Requesting PCB id for STGC");
338 return false;
339 }
340
341 return true;
342}
343
344//
345// read the MM HV map from a set of ascii files
346//
348{
349
350 std::string fileNamesA[16] = {"A01.txt","A02.txt","A03.txt","A04.txt",
351 "A05.txt","A06.txt","A07.txt","A08.txt",
352 "A09.txt","A10.txt","A11.txt","A12.txt",
353 "A13.txt","A14.txt","A15.txt","A16.txt" };
354
355 for (int ifile = 0 ; ifile<16 ; ++ifile) {
356
357 std::string fileName = PathResolverFindCalibFile(Form("NSWCalibTools/210128_initial/%s", fileNamesA[ifile].c_str()));
358
359 std::ifstream file(fileName,std::ios::in);
360 if ( !file.is_open() ) {
361 ATH_MSG_DEBUG("HV File " << fileNamesA[ifile] << " not available " );
362 continue;
363 }
364 ATH_MSG_INFO("Reading HV from configuration file: " << fileName);
365
366 //LM sector
367 //Layer PCB HV_left HV_right HV_min
368 //LM1 - IP
369
370 std::string line;
371 bool isLM,isSM,isIP,isHO;
372 int stationName,stationPhi,gasGap,HVval;
373 int side = 0;
374 std::string layerId[4] = {"L1","L2","L3","L4"};
375
376 int endPCB=0;
377
378 getline(file,line);
379 ATH_MSG_VERBOSE(line);
380 getline(file,line);
381 ATH_MSG_VERBOSE(line);
382
383 while ( getline(file,line) ) {
384 ATH_MSG_VERBOSE(line);
385
386 isIP=false;
387 isHO=false;
388
389 std::string secName = fileNamesA[ifile].substr(0,2);
390
391 if ( secName.substr(0,1)=="A" ) side = +1;
392 else if ( secName.substr(0,1)=="C" ) side = -1;
393 else {
394 ATH_MSG_ERROR("ERROR side not defined");
395 return StatusCode::FAILURE;
396 }
397 int phiSec = std::stoi(fileNamesA[ifile].substr(1,2));
398 stationPhi = (phiSec-1)/2+1;
399
400 size_t fLM = line.find("LM");
401 size_t fSM = line.find("SM");
402 isLM = (fLM!=std::string::npos);
403 isSM = (fSM!=std::string::npos);
404
405 // get layer 1 from the line with the module name
406 if ( isLM || isSM ) {
407 int stationEta = 0;
408 if ( isSM ) {
409 stationEta = side*std::stoi(line.substr(fSM+2,1));
410 }
411 else {
412 stationEta = side*std::stoi(line.substr(fLM+2,1));
413 }
414
416 if (stationEta==1) endPCB=5;
417 else if (stationEta==2) endPCB=3;
418 else {
419 ATH_MSG_ERROR("wrong stationEta value = " << stationEta);
420 }
421
422 isSM ? stationName=55 : stationName=56;
423
424 int multilayer = 0;
425 std::size_t fIP = line.find("IP");
426 isIP = (fIP!=std::string::npos);
427 std::size_t fHO = line.find("HO");
428 isHO = (fHO!=std::string::npos);
429 if ( !isIP && !isHO ) {
430 ATH_MSG_ERROR("ERROR multilayer id not found (IP/HO) ");
431 return StatusCode::FAILURE;
432 }
433 else if ( isIP && isHO ) {
434 ATH_MSG_ERROR("ERROR multilayer id duplicated (IP and HO) ");
435 return StatusCode::FAILURE;
436 }
437 else if ( isIP ) {
438 multilayer = 1;
439 }
440 else if ( isHO ) {
441 multilayer = 2;
442 }
443
444 // now read the various layers
445 //int ilayer = 1;
446 //int ipcb = 1;
447 for (int ilayer = 1; ilayer <= 4; ilayer++) {
448 for (int ipcb = 1; ipcb <= endPCB; ipcb++) {
449 getline(file,line);
450 ATH_MSG_VERBOSE(line);
451
452 std::istringstream elem(line);
453 std::vector<std::string> elements;
454
455 while(elem) {
456 std::string subs_elem;
457 elem >> subs_elem;
458 if (!subs_elem.empty()) elements.push_back(subs_elem);
459 }
460
461 gasGap = std::stoi(elements[0]);
462 int readed_pcb = std::stoi(elements[1]);
463 if (gasGap != ilayer || readed_pcb != ipcb) {
464 ATH_MSG_ERROR("Layer or pcb wrong!");
465 return StatusCode::FAILURE;
466 }
467
468 HVval=std::stoi(elements[4]);
469
470 ATH_MSG_DEBUG("PCB done, stationName, stationEta, stationPhi, ml, layer, pcb, hv: "
471 << stationName<< " " << stationEta << " " << stationPhi << " " << multilayer << " "
472 << ilayer << " " << ipcb << " " << HVval );
473
474 int chanNum = (ipcb-1)*1024+512;
476 Identifier pcbId = m_idHelperSvc->mmIdHelper().channelID(stationName,stationEta,stationPhi,
477 multilayer,ilayer,chanNum);
478 float hv = (float)HVval;
479 m_hvMap.insert(std::pair<Identifier,float>(pcbId,hv));
480
481 }
482 if ( ilayer == 4 ) {
483 getline(file,line);
484 ATH_MSG_VERBOSE(line);
485 }
486 } // loop on the layers
487 }
488 }
489 } // loop on the files
490 return StatusCode::SUCCESS;
491}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(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
std::string PathResolverFindCalibFile(const std::string &logical_file_name)
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
Gaudi::Property< std::vector< double > > m_chargeSmear
Gaudi::Property< std::vector< double > > m_channelEfficiency
virtual StatusCode initialize() override
bool getIdFields(const Identifier id, int &etaSector, int &phiSector, int &gasGap) const
Gaudi::Property< bool > m_readEfficiencyFromFile
double getMMGainFractionFromHV(double hv) const
Gaudi::Property< std::vector< double > > m_gainFraction
double getMMEfficiencyFromHV(double hv) const
Gaudi::Property< std::vector< double > > m_timeSmear
double getHighVoltage(Identifier id) const
bool getPCBIdentifier(const Identifier id, Identifier &pcb_id) const
NSWCalibSmearingTool(const std::string &, const std::string &, const IInterface *)
StatusCode smearCharge(const Identifier id, float &charge, bool &accepted, CLHEP::HepRandomEngine *rndmEngine) const override
Gaudi::Property< std::vector< bool > > m_phiSectors
Gaudi::Property< std::vector< bool > > m_etaSectors
ServiceHandle< Muon::IMuonIdHelperSvc > m_idHelperSvc
StatusCode smearTimeAndCharge(const Identifier id, float &time, float &charge, bool &accepted, CLHEP::HepRandomEngine *rndmEngine) const override
std::map< Identifier, float > m_hvMap
Gaudi::Property< bool > m_readGainFractionFromFile
virtual StatusCode isAccepted(const Identifier id, bool &accepted, CLHEP::HepRandomEngine *rndmEngine) const override
virtual StatusCode getGainFraction(const Identifier id, float &charge) override
Gaudi::Property< std::vector< double > > m_clusterEfficiency
NRpcCablingAlg reads raw condition data and writes derived condition data to the condition store.
TFile * file