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