ATLAS Offline Software
Loading...
Searching...
No Matches
SiGNNTrackFinderTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
6#include "ExaTrkXUtils.hpp"
7
8// Framework include(s).
11
12#include <cmath>
13#include <random> // std::random_device, std::mt19937, std::random_shuffle
14
16 const std::string& type, const std::string& name, const IInterface* parent):
17 base_class(type, name, parent)
18 {
19 declareInterface<IGNNTrackFinder>(this);
20 }
21
23 ATH_CHECK( m_embedSessionTool.retrieve() );
24 m_embedSessionTool->printModelInfo();
25
26 ATH_CHECK( m_filterSessionTool.retrieve() );
27 m_filterSessionTool->printModelInfo();
28
29 ATH_CHECK( m_gnnSessionTool.retrieve() );
30 m_gnnSessionTool->printModelInfo();
31
32 // tokenize the feature names by comma and push to the vector
33 auto split_fn = [](const std::string& s, auto convert_fn) {
34 using ReturnType = std::decay_t<decltype(convert_fn(std::declval<std::string>()))>;
35 std::vector<ReturnType> tokens;
36 std::string token;
37 std::istringstream tokenStream(s);
38 while (std::getline(tokenStream, token, ',')) {
39 token = token.substr(token.find_first_not_of(" "), token.find_last_not_of(" ") + 1);
40 tokens.push_back(convert_fn(token));
41 }
42 return tokens;
43 };
44 auto convert_to_float = [](const std::string& s) -> float { return std::stof(s); };
45 auto convert_to_str = [](const std::string& s) -> std::string { return s; };
46
47 m_embeddingFeatureNamesVec = split_fn(m_embeddingFeatureNames, convert_to_str);
48 m_embeddingFeatureScalesVec = split_fn(m_embeddingFeatureScales, convert_to_float);
50
51 m_filterFeatureNamesVec = split_fn(m_filterFeatureNames, convert_to_str);
52 m_filterFeatureScalesVec = split_fn(m_filterFeatureScales, convert_to_float);
54
55 m_gnnFeatureNamesVec = split_fn(m_gnnFeatureNames, convert_to_str);
56 m_gnnFeatureScalesVec = split_fn(m_gnnFeatureScales, convert_to_float);
57 assert(m_gnnFeatureNamesVec.size() == m_gnnFeatureScalesVec.size());
58
59 return StatusCode::SUCCESS;
60}
61
62MsgStream& InDet::SiGNNTrackFinderTool::dump( MsgStream& out ) const
63{
64 out<<std::endl;
65 return dumpevent(out);
66}
67
68std::ostream& InDet::SiGNNTrackFinderTool::dump( std::ostream& out ) const
69{
70 return out;
71}
72
73MsgStream& InDet::SiGNNTrackFinderTool::dumpevent( MsgStream& out ) const
74{
75 out<<"|---------------------------------------------------------------------|"
76 <<std::endl;
77 out<<"| Number output tracks | "<<std::setw(12)
78 <<" |"<<std::endl;
79 out<<"|---------------------------------------------------------------------|"
80 <<std::endl;
81 return out;
82}
83
85 const std::vector<const Trk::SpacePoint*>& spacepoints,
86 std::vector<std::vector<uint32_t> >& tracks,
87 std::unordered_map<int, std::unordered_map<int, float>>* /*edgeMap*/) const
88{
89 int64_t numSpacepoints = (int64_t)spacepoints.size();
90 std::vector<float> eNodeFeatures;
91 std::vector<float> fNodeFeatures;
92 std::vector<float> gNodeFeatures;
93 std::vector<uint32_t> spacepointIDs;
94 std::vector<int> regions;
95
96 int sp_idx = 0;
97 for(const auto& sp: spacepoints){
98 auto featureMap = m_spacepointFeatureTool->getFeatures(sp);
99 regions.push_back(featureMap["region"]);
100 // fill embedding node features.
101 for(size_t i = 0; i < m_embeddingFeatureNamesVec.size(); i++){
102 eNodeFeatures.push_back(
104 }
105
106 // fill filtering node features.
107 for(size_t i = 0; i < m_filterFeatureNamesVec.size(); i++){
108 fNodeFeatures.push_back(
110 }
111
112 // fill gnn node features.
113 for(size_t i = 0; i < m_gnnFeatureNamesVec.size(); i++){
114 gNodeFeatures.push_back(
115 featureMap[m_gnnFeatureNamesVec[i]] / m_gnnFeatureScalesVec[i]);
116 }
117
118 spacepointIDs.push_back(sp_idx++);
119 }
120 // ************
121 // Embedding
122 // ************
123 std::vector<int64_t> eInputShape{numSpacepoints, (long int) m_embeddingFeatureNamesVec.size()};
124 std::vector<Ort::Value> eInputTensor;
125 ATH_CHECK( m_embedSessionTool->addInput(eInputTensor, eNodeFeatures, 0, numSpacepoints) );
126
127 std::vector<Ort::Value> eOutputTensor;
128 std::vector<float> eOutputData;
129 ATH_CHECK( m_embedSessionTool->addOutput(eOutputTensor, eOutputData, 0, numSpacepoints) );
130
131 ATH_CHECK( m_embedSessionTool->inference(eInputTensor, eOutputTensor) );
132
133 // ************
134 // Building Edges
135 // ************
136 std::vector<int64_t> senders;
137 std::vector<int64_t> receivers;
138 ExaTrkXUtils::buildEdges(eOutputData, senders, receivers, numSpacepoints, m_embeddingDim, m_rVal, m_knnVal);
139 int64_t numEdges = senders.size();
140
141 // clean up embedding data.
142 eNodeFeatures.clear();
143 eInputTensor.clear();
144 eOutputData.clear();
145 eOutputTensor.clear();
146
147 // sort the edge list and remove duplicate edges.
148 std::vector<std::pair<int64_t, int64_t>> edgePairs;
149 for(int64_t idx = 0; idx < numEdges; idx ++ ) {
150 edgePairs.push_back({senders[idx], receivers[idx]});
151 }
152 std::sort(edgePairs.begin(), edgePairs.end());
153 edgePairs.erase(std::unique(edgePairs.begin(), edgePairs.end()), edgePairs.end());
154
155 // random shuffle the edge list.
156 std::random_device rd;
157 std::mt19937 rdm_gen(rd());
158 std::random_shuffle(edgePairs.begin(), edgePairs.end());
159
160 // sort the edge list by the sender * numSpacepoints + receiver.
161 std::sort(edgePairs.begin(), edgePairs.end(),
162 [numSpacepoints](const std::pair<int64_t, int64_t>& a, const std::pair<int64_t, int64_t>& b){
163 return a.first * numSpacepoints + a.second < b.first * numSpacepoints + b.second;
164 });
165
166 // convert the edge list to senders and receivers.
167 senders.clear();
168 receivers.clear();
169 for(const auto& edge: edgePairs){
170 senders.push_back(edge.first);
171 receivers.push_back(edge.second);
172 }
173
174 edgePairs.clear();
175
176 // ************
177 // Filtering
178 // ************
179 std::vector<Ort::Value> fInputTensor;
180 ATH_CHECK( m_filterSessionTool->addInput(fInputTensor, fNodeFeatures, 0, numSpacepoints) );
181
182 std::vector<int64_t> edgeList(numEdges * 2);
183 std::copy(senders.begin(), senders.end(), edgeList.begin());
184 std::copy(receivers.begin(), receivers.end(), edgeList.begin() + senders.size());
185
186
187 ATH_CHECK( m_filterSessionTool->addInput(fInputTensor, edgeList, 1, numEdges) );
188
189 std::vector<float> fOutputData;
190 std::vector<Ort::Value> fOutputTensor;
191 ATH_CHECK( m_filterSessionTool->addOutput(fOutputTensor, fOutputData, 0, numEdges) );
192
193 ATH_CHECK( m_filterSessionTool->inference(fInputTensor, fOutputTensor) );
194
195 // apply sigmoid to the filtering output data
196 // and remove edges with score < filterCut
197 // and sort the edge list so that sender idx < receiver.
198 std::vector<int64_t> rowIndices;
199 std::vector<int64_t> colIndices;
200 for (int64_t i = 0; i < numEdges; i++){
201 float v = 1.f / (1.f + std::exp(-fOutputData[i])); // sigmoid, float type
202 if (v >= m_filterCut){
203 auto src = edgeList[i];
204 auto dst = edgeList[numEdges + i];
205 if (src > dst) {
206 std::swap(src, dst);
207 }
208 rowIndices.push_back(src);
209 colIndices.push_back(dst);
210 };
211 };
212 int64_t numEdgesAfterF = rowIndices.size();
213
214 // clean up filtering data.
215 fNodeFeatures.clear();
216 fInputTensor.clear();
217 fOutputData.clear();
218 fOutputTensor.clear();
219 // clean up sender and receiver list.
220 senders.clear();
221 receivers.clear();
222
223 std::vector<int64_t> edgesAfterFiltering(numEdgesAfterF * 2);
224 std::copy(rowIndices.begin(), rowIndices.end(), edgesAfterFiltering.begin());
225 std::copy(colIndices.begin(), colIndices.end(), edgesAfterFiltering.begin() + senders.size());
226
227 // ************
228 // GNN
229 // ************
230
231 // use the same features for regions (2, 6)
232 for(size_t idx = 0; idx < static_cast<size_t>(numSpacepoints); idx++){
233 if (regions[idx] == 2 || regions[idx] == 6){
234 for(size_t i = 4; i < m_gnnFeatureNamesVec.size(); i++){
235 gNodeFeatures[idx * m_gnnFeatureNamesVec.size() + i] = gNodeFeatures[idx * m_gnnFeatureNamesVec.size() + i % 4];
236 }
237 }
238 }
239
240 std::vector<Ort::Value> gInputTensor;
241 ATH_CHECK( m_gnnSessionTool->addInput(gInputTensor, gNodeFeatures, 0, numSpacepoints) );
242 ATH_CHECK( m_gnnSessionTool->addInput(gInputTensor, edgesAfterFiltering, 1, numEdgesAfterF) );
243
244 // calculate the edge features.
245 std::vector<float> gnnEdgeFeatures;
246 ExaTrkXUtils::calculateEdgeFeatures(gNodeFeatures, numSpacepoints, rowIndices, colIndices, gnnEdgeFeatures);
247 ATH_CHECK( m_gnnSessionTool->addInput(gInputTensor, gnnEdgeFeatures, 2, numEdgesAfterF) );
248
249 // gnn outputs
250 std::vector<float> gOutputData;
251 std::vector<Ort::Value> gOutputTensor;
252 ATH_CHECK( m_gnnSessionTool->addOutput(gOutputTensor, gOutputData, 0, numEdgesAfterF) );
253
254 ATH_CHECK( m_gnnSessionTool->inference(gInputTensor, gOutputTensor) );
255 // apply sigmoid to the gnn output data
256 for(auto& v : gOutputData){
257 v = 1.f / (1.f + std::exp(-v));
258 };
259
260 // clean up GNN data.
261 gNodeFeatures.clear();
262 gInputTensor.clear();
263 edgesAfterFiltering.clear();
264
265 // ************
266 // Track Labeling with cugraph::connected_components
267 // ************
268 tracks.clear();
270 numSpacepoints,
271 rowIndices, colIndices, gOutputData,
272 tracks, m_ccCut, m_walkMin, m_walkMax
273 );
274
275 return StatusCode::SUCCESS;
276}
277
#define ATH_CHECK
Evaluate an expression and check for errors.
static Double_t sp
static Double_t a
static const std::vector< std::string > regions
virtual StatusCode getTracks(const std::vector< const Trk::SpacePoint * > &spacepoints, std::vector< std::vector< uint32_t > > &tracks, std::unordered_map< int, std::unordered_map< int, float > > *edgeMap=nullptr) const override
Get track candidates from a list of space points.
std::vector< float > m_gnnFeatureScalesVec
ToolHandle< AthOnnx::IOnnxRuntimeInferenceTool > m_filterSessionTool
ToolHandle< ISpacepointFeatureTool > m_spacepointFeatureTool
virtual StatusCode initialize() override
UnsignedIntegerProperty m_knnVal
UnsignedIntegerProperty m_embeddingDim
std::vector< float > m_filterFeatureScalesVec
std::vector< std::string > m_embeddingFeatureNamesVec
MsgStream & dumpevent(MsgStream &out) const
ToolHandle< AthOnnx::IOnnxRuntimeInferenceTool > m_embedSessionTool
std::vector< std::string > m_gnnFeatureNamesVec
std::vector< float > m_embeddingFeatureScalesVec
ToolHandle< AthOnnx::IOnnxRuntimeInferenceTool > m_gnnSessionTool
std::vector< std::string > m_filterFeatureNamesVec
virtual MsgStream & dump(MsgStream &out) const override
void CCandWalk(vertex_t numSpacepoints, const std::vector< int64_t > &rowIndices, const std::vector< int64_t > &colIndices, const std::vector< weight_t > &edgeWeights, std::vector< std::vector< uint32_t > > &tracks, float ccCut, float walkMin, float walkMax)
void calculateEdgeFeatures(const std::vector< float > &gNodeFeatures, int64_t numSpacepoints, const std::vector< int64_t > &rowIndices, const std::vector< int64_t > &colIndices, std::vector< float > &edgeFeatures)
void buildEdges(const std::vector< float > &embedFeatures, std::vector< int64_t > &senders, std::vector< int64_t > &receivers, int64_t numSpacepoints, int embeddingDim, float rVal, int kVal)
DataModel_detail::iterator< DVL > unique(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of unique for DataVector/List.
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
void swap(ElementLinkVector< DOBJ > &lhs, ElementLinkVector< DOBJ > &rhs)