37 if (conn_fileName.empty()) {
38 ATH_MSG_FATAL(
"Cannot find layer connections file " << conn_fileName);
39 return StatusCode::FAILURE;
43 std::ifstream ifs(conn_fileName.c_str());
50 ATH_MSG_INFO(
"Layer connections are initialized from file " << conn_fileName);
55 std::copy(pVL->begin(),pVL->end(), std::back_inserter(
m_layerGeometry));
62 if (lut_fileName.empty()) {
63 ATH_MSG_FATAL(
"Cannot find ML predictor LUT file " << lut_fileName);
64 return StatusCode::FAILURE;
68 std::ifstream ifs(lut_fileName.c_str());
70 float cl_width, min1, max1, min2, max2;
71 ifs >> cl_width >> min1 >> max1 >> min2 >> max2;
73 std::array<float, 5> lut_line = {cl_width, min1, max1, min2, max2};
77 ATH_MSG_INFO(
"ML predictor is initialized from file " << lut_fileName<<
" LUT has "<<
m_mlLUT.size()<<
" entries");
90 return StatusCode::SUCCESS;
101 struct GBTS_SlidingWindow {
103 GBTS_SlidingWindow() : m_first_it(0), m_deltaPhi(0.0), m_has_nodes(
false), m_bin(
nullptr) {};
105 unsigned int m_first_it;
114 const float cut_dphi_max =
m_LRTmode ? 0.07f : 0.012f;
115 const float cut_dcurv_max =
m_LRTmode ? 0.015f : 0.001f;
119 const float min_deltaPhi =
m_LRTmode ? 0.01f : 0.001f;
120 const float tau_ratio_precut = 0.009f;
122 const float maxOuterRadius =
m_LRTmode ? 1050.0 : 550.0;
124 const float cut_zMinU = min_z0 + maxOuterRadius*roi.
dzdrMinus();
125 const float cut_zMaxU = max_z0 + maxOuterRadius*roi.
dzdrPlus();
127 constexpr float ptCoeff = 0.29997*1.9972/2.0;
129 float tripletPtMin = 0.8f*
m_minPt;
130 const float pt_scale = 900.0f/
m_minPt;
132 float maxCurv = ptCoeff/tripletPtMin;
134 float maxKappa_high_eta =
m_LRTmode ? 1.0f*maxCurv : std::sqrt(0.8f)*maxCurv;
135 float maxKappa_low_eta =
m_LRTmode ? 1.0f*maxCurv : std::sqrt(0.6f)*maxCurv;
138 maxKappa_high_eta = 4.75e-4f*pt_scale;
139 maxKappa_low_eta = 3.75e-4f*pt_scale;
142 const float dphi_coeff =
m_LRTmode ? 1.0f*maxCurv : 0.68f*maxCurv;
144 const float minDeltaRadius = 2.0;
148 unsigned int nConnections = 0;
154 float z0_histo_coeff = 16/(max_z0 - min_z0 + 1e-6);
156 for(
const auto& bg :
m_geo->bin_groups()) {
160 if(B1.
empty())
continue;
166 const bool isBarrel1 = (lk1 / 10000) == 8;
170 std::vector<GBTS_SlidingWindow> vSLW;
172 vSLW.resize(bg.second.size());
176 for(
const auto& b2_idx : bg.second) {
190 float abs_dr = std::fabs(rb2-rb1);
192 deltaPhi = min_deltaPhi + dphi_coeff*abs_dr;
196 deltaPhi = 0.002f + 4.33e-4f*pt_scale*abs_dr;
198 deltaPhi = 0.015f + 2.2e-4f*pt_scale*abs_dr;
203 vSLW[win_idx].m_bin = &B2;
204 vSLW[win_idx].m_has_nodes =
true;
205 vSLW[win_idx].m_deltaPhi =
deltaPhi;
209 for(
unsigned int n1Idx = 0;n1Idx<B1.
m_vn.size();n1Idx++) {
213 unsigned short num_created_edges = 0;
215 bool is_connected =
false;
217 std::array<unsigned char, 16> z0_histo = {};
219 const std::array<float, 5>& n1pars = B1.
m_params[n1Idx];
221 float phi1 = n1pars[2];
222 float r1 = n1pars[3];
223 float z1 = n1pars[4];
225 for(
unsigned int winIdx = 0; winIdx < vSLW.size(); winIdx++) {
227 GBTS_SlidingWindow& slw = vSLW[winIdx];
229 if (!slw.m_has_nodes)
continue;
235 const bool isBarrel2 = (lk2 / 10000) == 8;
244 for(
unsigned int n2PhiIdx = slw.m_first_it; n2PhiIdx<B2.
m_vPhiNodes.size();n2PhiIdx++) {
249 slw.m_first_it = n2PhiIdx;
252 if(phi2 > maxPhi)
break;
254 unsigned int n2Idx = B2.
m_vPhiNodes[n2PhiIdx].second;
258 if ((lk1 == 80000) && (node_info == 0) )
continue;
261 unsigned short n2_num_edges = B2.
m_vNumEdges[n2Idx];
262 unsigned int n2_last_edge = n2_first_edge + n2_num_edges;
264 const std::array<float, 5>& n2pars = B2.
m_params[n2Idx];
266 float r2 = n2pars[3];
270 if(dr < minDeltaRadius) {
274 float z2 = n2pars[4];
278 float ftau = std::fabs(tau);
283 if(ftau < n1pars[0])
continue;
284 if(ftau > n1pars[1])
continue;
286 if(ftau < n2pars[0])
continue;
287 if(ftau > n2pars[1])
continue;
289 float z0 = z1 - r1*tau;
300 if(z0 < min_z0 || z0 > max_z0)
continue;
302 float zouter = z0 + maxOuterRadius*tau;
304 if(zouter < cut_zMinU || zouter > cut_zMaxU)
continue;
307 float curv = (phi2-phi1)/dr;
308 float abs_curv = std::abs(curv);
311 if(abs_curv > maxKappa_low_eta) {
316 if(abs_curv > maxKappa_high_eta) {
321 float exp_eta = std::sqrt(1.f+tau*tau) - tau;
325 bool isGood = n2_num_edges <= 2;
329 float uat_1 = 1.0f/exp_eta;
331 for(
unsigned int n2_in_idx = n2_first_edge; n2_in_idx < n2_last_edge; n2_in_idx++) {
333 float tau2 = edgeStorage.at(n2_in_idx).m_p[0];
334 float tau_ratio = tau2*uat_1 - 1.0f;
336 if(std::fabs(tau_ratio) > tau_ratio_precut){
349 float dPhi2 = curv*r2;
350 float dPhi1 = curv*r1;
354 edgeStorage.emplace_back(B1.
m_vn[n1Idx], B2.
m_vn[n2Idx], exp_eta, curv, phi1 + dPhi1);
358 int outEdgeIdx = nEdges;
360 float uat_2 = 1.f/exp_eta;
361 float Phi2 = phi2 + dPhi2;
364 for(
unsigned int inEdgeIdx = n2_first_edge; inEdgeIdx < n2_last_edge; inEdgeIdx++) {
370 const unsigned int lk3 =
m_geo->getTrigFTF_GNN_LayerKeyByIndex(pS->
m_n2->
m_layer);
372 const bool isBarrel3 = (lk3 / 10000) == 8;
374 float abs_tau_ratio = std::abs(pS->
m_p[0]*uat_2 - 1.0f);
375 float add_tau_ratio_corr = 0;
379 if (isBarrel1 && isBarrel2 && isBarrel3) {
380 bool no_gap = ((lk3-lk2) == 1000) && ((lk2-lk1) == 1000);
386 bool mixed_triplet = isBarrel1 && isBarrel2 && !isBarrel3;
393 if(abs_tau_ratio > cut_tau_ratio_max + add_tau_ratio_corr){
397 float dPhi = Phi2 - pS->
m_p[2];
402 if(std::abs(dPhi) > cut_dphi_max) {
406 float dcurv = curv2 - pS->
m_p[1];
408 if(dcurv < -cut_dcurv_max || dcurv > cut_dcurv_max) {
414 if (isBarrel1 && isBarrel2 && isBarrel3) {
416 std::array<const GNN_Node*, 3> sps = {B1.
m_vn[n1Idx], B2.
m_vn[n2Idx], pS->
m_n2};
418 if (!
validate_triplet(sps, tripletPtMin, abs_tau_ratio, cut_tau_ratio_max) )
continue;
428 int z0_bin_index = z0_histo_coeff*(z0 - min_z0);
430 ++z0_histo[z0_bin_index];
446 unsigned short z0_bitmask = 0x0;
448 for(
unsigned int bIdx = 0; bIdx < 16; bIdx++) {
450 if (z0_histo[bIdx] == 0)
continue;
452 z0_bitmask |= (1 << bIdx);
462 ATH_MSG_WARNING(
"Maximum number of graph edges exceeded - possible efficiency loss "<< nEdges);
465 return std::make_pair(nEdges, nConnections);
470 constexpr int maxIter = 15;
476 std::vector<TrigFTF_GNN_Edge*> v_old;
478 for(
int edgeIndex=0;edgeIndex<nEdges;edgeIndex++) {
481 if(pS->
m_nNei == 0)
continue;
486 std::vector<TrigFTF_GNN_Edge*> v_new;
487 v_new.reserve(v_old.size());
489 for(;iter<maxIter;iter++) {
494 for(
auto pS : v_old) {
496 int next_level = pS->m_level;
498 for(
int nIdx=0;nIdx<pS->m_nNei;nIdx++) {
500 unsigned int nextEdgeIdx = pS->m_vNei[nIdx];
504 if(pS->m_level == pN->
m_level) {
505 next_level = pS->m_level + 1;
511 pS->m_next = next_level;
518 for(
auto pS : v_new) {
519 if(pS->m_next != pS->m_level) {
521 pS->m_level = pS->m_next;
522 if(maxLevel < pS->m_level) maxLevel = pS->m_level;
526 if(nChanges == 0)
break;
538 const float edge_mask_min_eta = 1.5;
539 const float hit_share_threshold = 0.49;
540 const float max_eta_for_seed_split = 0.6;
541 const float max_inv_rad_diff = 0.7e-2;
549 if(maxLevel < minLevel)
return;
551 std::vector<GNN_Edge*> vSeeds;
553 vSeeds.reserve(nEdges/2);
555 for(
int edgeIndex = 0; edgeIndex < nEdges; edgeIndex++) {
557 GNN_Edge* pS = &(edgeStorage.at(edgeIndex));
559 if(pS->
m_level < minLevel)
continue;
561 vSeeds.push_back(pS);
564 if(vSeeds.empty())
return;
570 std::vector<std::tuple<float, int, std::vector<const GNN_Node*>,
int > > vSeedCandidates;
572 vSeedCandidates.reserve(vSeeds.size());
574 std::vector<std::pair<float, unsigned int> > vArgSort;
576 vArgSort.reserve(vSeeds.size());
578 unsigned int seed_counter = 0;
580 auto tFilter = std::make_unique<TrigFTF_GNN_TrackingFilter>(
m_layerGeometry, edgeStorage);
582 for(
auto pS : vSeeds) {
584 if(pS->m_level == -1)
continue;
588 tFilter->followTrack(pS,
rs);
590 if(!
rs.m_initialized) {
594 if(
static_cast<int>(
rs.m_vs.size()) < minLevel)
continue;
596 float seed_eta = std::abs(-std::log(pS->m_p[0]));
598 std::vector<const GNN_Node*> vN;
600 for(std::vector<GNN_Edge*>::reverse_iterator sIt=
rs.m_vs.rbegin();sIt!=
rs.m_vs.rend();++sIt) {
602 if (seed_eta > edge_mask_min_eta) {
603 (*sIt)->m_level = -1;
606 if(sIt ==
rs.m_vs.rbegin()) {
607 vN.push_back((*sIt)->m_n1);
610 vN.push_back((*sIt)->m_n2);
614 if(vN.size()<3)
continue;
616 unsigned int orig_seed_size = vN.size();
618 float orig_seed_quality = -
rs.m_J/orig_seed_size;
620 int seed_split_flag = (seed_eta < max_eta_for_seed_split) && (orig_seed_size > 3) && (orig_seed_size <= 5) ? 1 : 0;
622 if (seed_split_flag) {
624 std::array< std::array<const GNN_Node*, 3>, 3> triplets;
626 std::array<float, 3> inv_rads;
628 triplets[0] = {vN[0], vN[orig_seed_size/2], vN[orig_seed_size-1]};
630 std::vector<const GNN_Node*> drop_out1 = {vN.begin()+1, vN.end()};
632 triplets[1] = {drop_out1[0], drop_out1[(orig_seed_size-1)/2], drop_out1[orig_seed_size-2]};
634 std::vector<const GNN_Node*> drop_out2;
636 drop_out2.reserve(orig_seed_size-1);
638 for(
unsigned int k = 0; k < orig_seed_size; k++) {
640 if (k == orig_seed_size/2)
continue;
642 drop_out2.emplace_back(vN[k]);
645 triplets[2] = {drop_out2[0], drop_out2[(orig_seed_size-1)/2], drop_out2[orig_seed_size-2]};
647 for (
unsigned int k = 0; k < inv_rads.size(); k++) {
653 float diffs[3] = {std::abs(inv_rads[1] - inv_rads[0]), std::abs(inv_rads[2] - inv_rads[0]), std::abs(inv_rads[2] - inv_rads[1])};
655 bool confirmed = diffs[0] < max_inv_rad_diff && diffs[1] < max_inv_rad_diff && diffs[2] < max_inv_rad_diff;
663 vSeedCandidates.emplace_back(orig_seed_quality, 0, vN, seed_split_flag);
665 vArgSort.emplace_back(orig_seed_quality, seed_counter);
673 std::sort(vArgSort.begin(), vArgSort.end());
675 std::vector<int> H2T(
nHits + 1, 0);
680 for(
const auto& ags : vArgSort) {
682 const auto& seed = vSeedCandidates[ags.second];
686 for(
const auto&
h : std::get<2>(seed) ) {
688 unsigned int hit_id =
h->sp_idx() + 1;
690 int tid = H2T[hit_id];
692 if(tid == 0 || tid > trackId) {
694 H2T[hit_id] = trackId;
700 unsigned int trackIdx = 0;
702 for(
const auto& ags : vArgSort) {
704 const auto& seed = std::get<2>(vSeedCandidates[ags.second]);
706 int nTotal = seed.size();
710 int trackId = trackIdx + 1;
714 for(
const auto&
h : seed ) {
716 unsigned int hit_id =
h->sp_idx() + 1;
718 int tid = H2T[hit_id];
725 if (nOther > hit_share_threshold*nTotal) {
726 std::get<1>(vSeedCandidates[ags.second]) = -1;
731 vOutputSeeds.reserve(vSeedCandidates.size());
735 for(
const auto& ags : vArgSort) {
737 const auto& seed = vSeedCandidates[ags.second];
739 if (std::get<1>(seed) != 0)
continue;
741 const auto& vN = std::get<2>(seed);
743 if (std::get<3>(seed) == 0) {
747 std::vector<unsigned int> vSpIdx;
749 vSpIdx.resize(vN.size());
751 for(
unsigned int k = 0; k < vSpIdx.size(); k++) {
752 vSpIdx[k] = vN[k]->sp_idx();
755 vOutputSeeds.emplace_back(std::get<0>(seed), vSpIdx);
763 unsigned int seedSize = vN.size();
765 std::array<std::size_t, 2> indices2drop = {0, seedSize / 2ul};
767 for(
const auto& skipIdx : indices2drop) {
769 std::vector<unsigned int> new_seed;
771 new_seed.reserve(seedSize-1);
773 for (
unsigned int k = 0; k < seedSize; k++) {
775 if (k == skipIdx)
continue;
777 new_seed.emplace_back(vN[k]->sp_idx());
780 vOutputSeeds.emplace_back(std::get<0>(seed), new_seed);