ATLAS Offline Software
Loading...
Searching...
No Matches
RpcPatFinder.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3*/
4
5#include "RpcPatFinder.h"
7#include <GaudiKernel/IMessageSvc.h>
8#include <cstddef>
9#include <cmath>
10#include <bitset>
11#include <iostream>
12
13// Original author: Massimo Corradi
14
15// --------------------------------------------------------------------------------
16// --------------------------------------------------------------------------------
17
18void TrigL2MuonSA::RpcPatFinder::addHit(const std::string& stationName,
19 int stationEta,
20 bool measuresPhi,
21 unsigned int gasGap,
22 unsigned int doubletR,
23 double gPosX,
24 double gPosY,
25 double gPosZ,
26 TrigL2MuonSA::RpcLayerHits& rpcLayerHits ) const{
27
28 int ilay=0;
29 // BO
30 if (stationName.substr(0,2)=="BO") ilay=4;
31 // doubletR
32 ilay+=2*(doubletR-1);
33 // BML7 special chamber with 1 RPC doublet (doubletR=1 but RPC2) :
34 if (stationName.substr(0,3)=="BML" && stationEta==7) ilay+=2;
35 // gasGap
36 ilay+=gasGap-1;
37
38 double R=std::sqrt(gPosX*gPosX+gPosY*gPosY);
39 const double Phi=std::atan2(gPosY,gPosX);
40
41 if (!measuresPhi){
42 // if eta measurement then save Z/R
43 R = calibR(stationName,R, Phi);
44 double x=gPosZ/R;
45 rpcLayerHits.hits_in_layer_eta.at(ilay).push_back(x);
46 rpcLayerHits.hits_in_layer_R.at(ilay).push_back(R);//mod!
47 rpcLayerHits.hits_in_layer_Z.at(ilay).push_back(gPosZ);//mod!
48 }else{
49 // if phi measurement then save phi
50 rpcLayerHits.hits_in_layer_phi.at(ilay).push_back(Phi);
51 }
52}
53
54// --------------------------------------------------------------------------------
55// --------------------------------------------------------------------------------
56
58 std::array<std::reference_wrapper<double>, 3>& result_aw,
59 std::array<std::reference_wrapper<double>, 3>& result_bw,
60 const TrigL2MuonSA::RpcLayerHits& rpcLayerHits) const{
61
62 const std::vector<std::vector<double>>& rpc_x {rpcLayerHits.hits_in_layer_eta};
63
64 int layer_end {5};
65 if(rpc_x.at(6).size()+rpc_x.at(7).size() >0) layer_end = 7;//special "feet" towers
66
67 // reset parameters
68 std::bitset<8> result_pat{};
69 double result_dMM{9999}, result_dMO{9999};
70 int nHits_pat{0};
71 std::array<size_t, 8> result_index{};
72
73 // Loop on start layer
74 for (int l_start=0; l_start<layer_end; l_start++){
75 // Loop on hits of start layer, for each hit try a new pattern
76 for (size_t i_start = 0; i_start < rpc_x.at(l_start).size(); ++i_start){
77
78 // Initialize a new pattern
79 int nHits=1;
80 std::bitset<8> pat (1<<l_start); // bit pattern of hit layers
81 std::array<size_t, 8> index {};
82 index[l_start] = i_start;
83 double dMO{9999}; // lowest deltaX between two consecutive hits, when having at least one of the two hit in BO
84 double dMM{9999}; // lowest deltaX between two consecutive hits, when having both hits in BM, or both in BO (but different doublets)
85
86 int current_l = l_start;
87 double current_x = rpc_x.at(l_start).at(i_start); // set current_x to the starting hit
88
89 // ----- add compatible hits in other layers ----//
90 // loop on test layers:
91 for (int l_test=l_start+1; l_test<=layer_end; l_test++){
92 double min_delta {999}; // min deltaX in this test laeyr
93 const std::vector<double>& test_layer_hits {rpc_x.at(l_test)};
94
95 for (size_t i_test = 0; i_test < test_layer_hits.size(); ++i_test){
96 double delta=-1;
97 // check if within the road
98 if (deltaOK(current_l,l_test,current_x, test_layer_hits.at(i_test),false,delta)){
99 // if closest hit we keep it as best hit for this test layer
100 if (delta < min_delta) {
101 min_delta = delta;
102 index[l_test] = i_test;
103 }
104 }
105 }
106 if (min_delta < 998){ //we found at least one hit in the window
107 current_l = l_test;
108 current_x = test_layer_hits.at(index[l_test]);
109 nHits+=1;
110 pat.set(l_test);
111 dMO = (l_start<4 and l_test>=4) ? std::min(dMO, min_delta) : dMO;
112 dMM = (l_start<2 and l_test>=2 and l_test<4) or (l_start>=4 and l_start<5 and l_test>=6) ? std::min(dMM, min_delta) : dMM;
113 }
114 }//for l_test
115
116 // if longest pattern found, update result
117 if (nHits>nHits_pat) {
118 nHits_pat=nHits;
119 result_pat=pat;
120 result_dMO=dMO;
121 result_dMM=dMM;
122 result_index=index;
123 }else if (nHits==nHits_pat) {
124 // if same lenght but smallest dMM/dMO, update result
125 if (dMM<result_dMM or (dMM==result_dMM and dMO<result_dMO)){
126 result_pat=pat;
127 result_dMO=dMO;
128 result_dMM=dMM;
129 result_index=index;
130 }
131 }
132 }//for i_start
133 }//for l_start
134
135 if (nHits_pat>=2) {
136 abcal(result_pat, result_index, result_aw, result_bw, rpcLayerHits);
137 if(msgLevel(MSG::DEBUG)){
138 std::ostringstream ossR, ossZ;
139 bool isFirst{true};
140 for (int i=0; i<8; ++i){
141 if(result_pat.test(i)){
142 if (isFirst){
143 ossR << rpcLayerHits.hits_in_layer_R.at(i).at(result_index[i]);
144 ossZ << rpcLayerHits.hits_in_layer_Z.at(i).at(result_index[i]);
145 isFirst=false;
146 }else{
147 ossR << "," << rpcLayerHits.hits_in_layer_R.at(i).at(result_index[i]);
148 ossZ << "," << rpcLayerHits.hits_in_layer_Z.at(i).at(result_index[i]);
149 }
150 }
151 }
152 std::ostringstream oss;
153 std::copy(result_index.begin(), result_index.end(), std::ostream_iterator<int>(oss, " "));
154 ATH_MSG_DEBUG("patfinder: BEST pat= " << result_pat << " nHit: " << nHits_pat << " Idx: " << oss.str()
155 <<" dMM= "<<result_dMM <<" dMO= "<<result_dMO << " R_hits: " << ossR.str() << " Z_hits: " << ossZ.str()
156 <<" Slopes: " << result_aw[0] << "," << result_aw[1] << "," << result_aw[2] << " Offsets: " << result_bw[0] << "," << result_bw[1] << "," << result_bw[2]);
157 }
158 return true;
159 }
160 return false;
161}
162
163// --------------------------------------------------------------------------------
164// --------------------------------------------------------------------------------
166 double &phi_outer,
167 const TrigL2MuonSA::RpcLayerHits& rpcLayerHits) const{
168 const int N_layers=8;
169
170 const std::vector<std::vector<double>>& rpc_phi {rpcLayerHits.hits_in_layer_phi};
171
172 int l_start_max=2; //max layer of first hit
173 if (rpc_phi.at(6).size()+rpc_phi.at(7).size()>0) l_start_max=5; // special "feet" towers
174
175 // reset parameters
176 phi_middle=0;
177 phi_outer=0;
178 double result_dMM{9999}, result_dMO{9999};
179 int nHits_pat=0;
180
181 // Loop on start layer
182 for (int l_start=0; l_start<=l_start_max; l_start++){
183 // Loop on hits of start layer, for each hit try a new pattern
184 for (const double& phi_start : rpc_phi.at(l_start)){
185 // Initialize a new pattern
186 int nHits=1;
187 double dMO{9999}; // lowest deltaX between two consecutive hits, when having at least one of the two hit in BO
188 double dMM{9999}; // lowest deltaX between two consecutive hits, when having both hits in BM, or both in BO (but different doublets)
189
190 int current_l = l_start;
191 double current_phi = phi_start; // set current_x to the starting hit
192
193 // ----- add compatible hits in other layers ----//
194 // loop on test layers:
195 for (int l_test=l_start+1; l_test<N_layers; l_test++){
196 double min_delta {999}; // min deltaX in this test laeyr
197 double layer_phi {0.};
198
199 for (const double& phi_test : rpc_phi.at(l_test)){
200 double delta=-1;
201 // check if within the road
202 if (deltaOK(current_l,l_test,current_phi, phi_test,true,delta)){
203 // if closest hit we keep it as best hit for this test layer
204 if (delta < min_delta) {
205 min_delta = delta;
206 layer_phi = phi_test;
207 }
208 }
209 }
210 if (min_delta < 998){ //we found at least one hit in the window
211 current_l = l_test;
212 current_phi = layer_phi;
213 nHits+=1;
214 dMO = (l_start<4 and l_test>=4) ? std::min(dMO, min_delta) : dMO;
215 dMM = (l_start<2 and l_test>=2 and l_test<4) or (l_start>=4 and l_start<5 and l_test>=6) ? std::min(dMM, min_delta) : dMM;
216 }
217 }
218
219 // if longest pattern found and the last hit is in a layer > BM doublet1, update result
220 if (nHits>nHits_pat and current_l > 1) {
221 nHits_pat=nHits;
222 result_dMO=dMO;
223 result_dMM=dMM;
224 phi_middle=phi_start;
225 phi_outer=current_phi;
226 }else if (nHits==nHits_pat and current_l > 1) {
227 // if same lenght but smallest dMM/dMO, update result
228 if (dMM<result_dMM or (dMM==result_dMM and dMO<result_dMO)){
229 result_dMO=dMO;
230 result_dMM=dMM;
231 phi_middle=phi_start;
232 phi_outer=current_phi;
233 }
234 }
235 }//for i_start
236 }//for l_start
237
238 if (nHits_pat>2) {
239 ATH_MSG_DEBUG("patfinder: BEST phi path dMM= "<<result_dMM <<" dMO= "<<result_dMO
240 <<" phi_middle= "<<phi_middle <<" phi_outer= "<<phi_outer);
241 return true;
242 }
243 return false;
244}
245
246// --------------------------------------------------------------------------------
247// --------------------------------------------------------------------------------
248
249bool TrigL2MuonSA::RpcPatFinder::deltaOK(int l1, int l2, double x1, double x2, int isphi, double &delta) const{
250
251
252 // ROAD tuned for ~20 GeV
253 /*
254 double delta_gasgap_eta = 0.004;
255 double delta_lowpt_eta = 0.005;
256 double delta_highpt_eta = 0.012;
257 double delta_feet_eta = 0.02;
258
259 double delta_gasgap_phi = 0.004;
260 double delta_lowpt_phi = 0.005;
261 double delta_highpt_phi = 0.008;
262 double delta_feet_phi = 0.02;
263 */
264
265 //OPEN road
266
267 const double delta_gasgap_eta = 0.01;
268 const double delta_lowpt_eta = 0.05;
269 const double delta_highpt_eta = 0.1;
270 const double delta_feet_eta = 0.05;
271
272 const double delta_gasgap_phi = 0.01;
273 const double delta_lowpt_phi = 0.03;
274 const double delta_highpt_phi = 0.04;
275 const double delta_feet_phi = 0.03;
276
277 // calculate delta-eta or delta-phi
278 if(isphi) delta=std::abs(std::acos(std::cos(x2-x1)));
279 else delta=std::abs(x2-x1);
280
281 double delta_max=0;
282 if (l1>l2) {
283 int tmp=l2;
284 l2=l1;
285 l1=tmp;
286 }
287 // calculate delta_max
288 if (isphi){
289 if (l2-l1==1&&(l1==0||l1==2||l1==4||l1==6)){
290 delta_max=delta_gasgap_phi;
291 } else if (l1<2&&l2<4) {
292 delta_max=delta_lowpt_phi;
293 }else if (l1<4&&l2>=4) {
294 delta_max=delta_highpt_phi;
295 }else if (l1<6&&l1>=4&&l2>=6) {
296 delta_max=delta_feet_phi;
297 }
298 } else {
299 if (l2-l1==1&&(l1==0||l1==2||l1==4||l1==6)){
300 delta_max=delta_gasgap_eta;
301 } else if (l1<2&&l2>=2&&l2<4) {
302 delta_max=delta_lowpt_eta;
303 }else if (l1<4&&l2>=4) {
304 delta_max=delta_highpt_eta;
305 }else if (l1<6&&l1>=4&&l2>=6) {
306 delta_max=delta_feet_eta;
307 }
308 }
309
310 // evaluate the result
311
312 bool OK=false;
313 if (delta<delta_max) OK=true;
314
315 return OK;
316
317}
318
319// --------------------------------------------------------------------------------
320// --------------------------------------------------------------------------------
321
322double TrigL2MuonSA::RpcPatFinder::calibR(const std::string& stationName, double R, double Phi) const{
323 double DeltaPhi, temp_phi;
324 double calibPhi = std::acos(std::cos(Phi)); // 0 < Phi < 2PI
325
326 if(std::string::npos != stationName.rfind('L')){//For Large , SP
327 DeltaPhi= 999; temp_phi=9999;
328 for(int inum=0;inum < 8;inum++){
329 temp_phi = std::abs((inum * M_PI/4.0 )- calibPhi);
330 if(temp_phi < DeltaPhi) DeltaPhi = temp_phi;
331 }
332 }else if(std::string::npos != stationName.rfind('S') ||
333 std::string::npos != stationName.rfind('F') ||
334 std::string::npos != stationName.rfind('G') ){
335 DeltaPhi= 999; temp_phi=9999;
336
337 for(int inum=0;inum < 8;inum++){
338 temp_phi = std::abs(inum *(M_PI/4.0 )+(M_PI/8.0) - calibPhi);
339 if(temp_phi < DeltaPhi) DeltaPhi = temp_phi;
340 }//for end
341 }else return R;
342
343 double calibR = R *std::cos(DeltaPhi);
344
345 return calibR;
346}//calbR()
347
348// --------------------------------------------------------------------------------
349// --------------------------------------------------------------------------------
350
351void TrigL2MuonSA::RpcPatFinder::abcal(const std::bitset<8>& result_pat,
352 const std::array<size_t, 8>& index,
353 std::array<std::reference_wrapper<double>, 3>& aw,
354 std::array<std::reference_wrapper<double>, 3>& bw,
355 const TrigL2MuonSA::RpcLayerHits& rpcLayerHits) const{
356 const float ZERO_LIMIT = 1.e-5;
357 const std::vector<std::vector<double>>& rpc_R {rpcLayerHits.hits_in_layer_R};
358 const std::vector<std::vector<double>>& rpc_Z {rpcLayerHits.hits_in_layer_Z};
359
360 // doublet companion
361 auto getCompanion = [](const int& l) -> int {
362 return (l%2==0) ? l+1 : l-1;
363 };
364
365 auto getAvgRZ= [&rpc_R, &rpc_Z, &result_pat, &index](double& R, double& Z, int l, int companion) -> void {
366 const auto idxAtl = index.at(l);
367 const auto idxAtComp = index.at(companion);
368 if (result_pat.test(companion)){
369 R = (rpc_R.at(l).at(idxAtl) + rpc_R.at(companion).at(idxAtComp)) / 2.0;
370 Z = (rpc_Z.at(l).at(idxAtl) + rpc_Z.at(companion).at(idxAtComp)) / 2.0;
371 return;
372 }
373 R = rpc_R.at(l).at(idxAtl);
374 Z = rpc_Z.at(l).at(idxAtl);
375 };
376
378 int l1 {4}, l2 {0};
379 double R1{0}, R2{0}, Z1{0}, Z2{0};
380 for(int i=0; i<4; i++){
381 if(!result_pat.test(i)) continue;
382 l1 = std::min(l1, i);
383 l2 = std::max(l2, i);
384 }
385 const int comp1{getCompanion(l1)}, comp2{getCompanion(l2)};
386 if (l1 != 4 and l1 != l2 and l2 != comp1){// we have two hits in BM and not in the same doublet
387
388 getAvgRZ(R1, Z1, l1, comp1);
389 getAvgRZ(R2, Z2, l2, comp2);
390
392 if(((result_pat & std::bitset<8>("00001111")).count() > 3) and std::abs(Z2-Z1) > ZERO_LIMIT){
393
394 double theta_m {std::atan2(R1, Z1)};
395 double theta_t {std::atan2(R2-R1, Z2-Z1)};
396 double theta_f {(theta_m+theta_t)/2.};
397
398 aw[0].get() = std::tan(theta_f);
399 bw[0].get() = R1 - Z1*aw[0].get();
400
401 }else{
402 aw[0].get() = R1/Z1;
403 bw[0].get() = 0.;
404 }
405
407 if (std::abs(Z2-Z1) > ZERO_LIMIT){
408 aw[1].get() = (R2-R1)/(Z2-Z1);
409 bw[1].get() = R2 - Z2*aw[1].get();
410 }
411 else{// if hits have very close z, we use only the earlier hit
412 aw[1].get() = R1/Z1;
413 bw[1].get() = 0.;
414 }
415 }
416 else if (l1 != 4){// either we have two hits in the same doublet or only one hit
417 getAvgRZ(R1, Z1, l1, comp1);
418 aw[0].get() = R1/Z1;
419 bw[0].get() = 0.;
420 aw[1].get() = aw[0].get();
421 bw[1].get() = 0.;
422
423 }// if no hits in BM, we will extrapolate the inner and BM slope using the first hit in BO
424
426 int l3 = 8, l4 = 0;
427 double R3{0}, R4{0}, Z3{0}, Z4{0};
428 for(int i=2; i<8; i++){
429 if(!result_pat.test(i)) continue;
430 l3 = std::min(l3, i);
431 l4 = std::max(l4, i);
432 }
433 const int comp3{getCompanion(l3)}, comp4{getCompanion(l4)};
434 if ( l3 != 8 and l3 != l4 and l4 != comp3){
435
436 getAvgRZ(R3, Z3, l3, comp3);
437 getAvgRZ(R4, Z4, l4, comp4);
438
439 if (std::abs(Z4-Z3) > ZERO_LIMIT){
440 aw[2].get() = (R4-R3)/(Z4-Z3);
441 bw[2].get() = R4 - Z4*aw[2].get();
442 }
443 else{// hits with very close Z, we use onl one hit.
444 aw[2].get() = R4/Z4;
445 bw[2].get() = 0.;
446 }
447 }
448 else if (l3 != 8){ // we have only one hit or they are in the same doublet
449 getAvgRZ(R3, Z3, l3, comp3);
450 aw[2].get() = R3/Z3;
451 bw[2].get() = 0.;
452 }// if no hits in outer layers, we will extrapolate the outer slope using the last hit in BM
453
454 if (std::abs(aw[0].get()) < ZERO_LIMIT){ // if no hits in BM, we use the first in in BO
455 getAvgRZ(R3, Z3, l3, comp3);
456 aw[0].get() = R3/Z3;
457 aw[1].get() = aw[0].get();
458 }
459 if (std::abs(aw[2].get()) < ZERO_LIMIT){ // if no hits in outer layers, we use the last in BM
460 getAvgRZ(R2, Z2, l2, comp2);
461 aw[2].get() = R2/Z2;
462 }
463
464
465}//abcal()
466
467// --------------------------------------------------------------------------------
468// --------------------------------------------------------------------------------
469
#define M_PI
#define ATH_MSG_DEBUG(x)
static const uint32_t nHits
size_t size() const
Number of registered mappings.
#define x
const float ZERO_LIMIT
void abcal(const std::bitset< 8 > &result_pat, const std::array< size_t, 8 > &index, std::array< std::reference_wrapper< double >, 3 > &aw, std::array< std::reference_wrapper< double >, 3 > &bw, const TrigL2MuonSA::RpcLayerHits &rpcLayerHits) const
bool findPatternEta(std::array< std::reference_wrapper< double >, 3 > &result_aw, std::array< std::reference_wrapper< double >, 3 > &result_bw, const TrigL2MuonSA::RpcLayerHits &rpcLayerHits) const
double calibR(const std::string &stationName, double R, double Phi) const
bool findPatternPhi(double &phi_middle, double &phi_outer, const TrigL2MuonSA::RpcLayerHits &rpcLayerHits) const
void addHit(const std::string &stationName, int stationEta, bool measuresPhi, unsigned int gasGap, unsigned int doubletR, double gPosX, double gPosY, double gPosZ, TrigL2MuonSA::RpcLayerHits &rpcLayerHits) const
bool deltaOK(int l1, int l2, double x1, double x2, int isphi, double &delta) const
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:148
Definition index.py:1
std::vector< std::vector< double > > hits_in_layer_eta
std::vector< std::vector< double > > hits_in_layer_Z
std::vector< std::vector< double > > hits_in_layer_phi
std::vector< std::vector< double > > hits_in_layer_R