ATLAS Offline Software
Loading...
Searching...
No Matches
FPGATrackSimGNNGraphConstructionTool.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
4
5#include <TFile.h>
6#include <TTree.h>
8
10// AthAlgTool
11
12FPGATrackSimGNNGraphConstructionTool::FPGATrackSimGNNGraphConstructionTool(const std::string& algname, const std::string &name, const IInterface *ifc)
13 : AthAlgTool(algname, name, ifc) {}
14
16{
18 if(m_graphTool == "ModuleMap") {
19 if (m_FPGATrackSimMapping->getGNNModuleMapString() != "") {
20 m_moduleMapPath = m_FPGATrackSimMapping->getGNNModuleMapString();
21 }
22 else {
23 ATH_MSG_ERROR("Path to 1st stage NN-based fake track removal ONNX file is empty! If you want to run this pipeline, you need to provide an input file.");
24 return StatusCode::FAILURE;
25 }
26
27 if(m_moduleMapType == "doublet") {
28 loadDoubletModuleMap(); // Load the doublet module map and store entry branches in vectors
29 }
30 }
31 else if(m_graphTool == "MetricLearning") {
32 ATH_CHECK( m_MLInferenceTool.retrieve() );
33 m_MLInferenceTool->printModelInfo();
34 assert(m_MLFeatureNamesVec.size() == m_MLFeatureScalesVec.size());
35 }
36
37 return StatusCode::SUCCESS;
38}
39
41// Functions
42
43StatusCode FPGATrackSimGNNGraphConstructionTool::getEdges(const std::vector<std::shared_ptr<FPGATrackSimGNNHit>> & hits, std::vector<std::shared_ptr<FPGATrackSimGNNEdge>> & edges)
44{
45 if(m_graphTool == "ModuleMap") {
46 doModuleMap(hits, edges);
47 }
48 else if(m_graphTool == "MetricLearning") {
49 doMetricLearning(hits, edges);
50 }
51
52 return StatusCode::SUCCESS;
53}
54
56{
57 std::unique_ptr<TFile> file(TFile::Open(m_moduleMapPath.c_str()));
58 std::unique_ptr<TTree> tree(static_cast<TTree*>(file->Get("TreeModuleDoublet")));
59
60 unsigned int mid1_value = 0;
61 unsigned int mid2_value = 0;
62 float z0min_12_value = 0.0;
63 float dphimin_12_value = 0.0;
64 float phislopemin_12_value = 0.0;
65 float detamin_12_value = 0.0;
66 float z0max_12_value = 0.0;
67 float dphimax_12_value = 0.0;
68 float phislopemax_12_value = 0.0;
69 float detamax_12_value = 0.0;
70
71 tree->SetBranchAddress("Module1", &mid1_value);
72 tree->SetBranchAddress("Module2", &mid2_value);
73 tree->SetBranchAddress("z0min_12", &z0min_12_value);
74 tree->SetBranchAddress("dphimin_12", &dphimin_12_value);
75 tree->SetBranchAddress("phiSlopemin_12", &phislopemin_12_value);
76 tree->SetBranchAddress("detamin_12", &detamin_12_value);
77 tree->SetBranchAddress("z0max_12", &z0max_12_value);
78 tree->SetBranchAddress("dphimax_12", &dphimax_12_value);
79 tree->SetBranchAddress("phiSlopemax_12", &phislopemax_12_value);
80 tree->SetBranchAddress("detamax_12", &detamax_12_value);
81
82 int64_t nEntries = tree->GetEntries();
83 for (int64_t i = 0; i < nEntries; ++i) {
84 tree->GetEntry(i);
85 m_mid1.emplace_back(mid1_value);
86 m_mid2.emplace_back(mid2_value);
87 m_z0min_12.emplace_back(z0min_12_value);
88 m_dphimin_12.emplace_back(dphimin_12_value);
89 m_phislopemin_12.emplace_back(phislopemin_12_value);
90 m_detamin_12.emplace_back(detamin_12_value);
91 m_z0max_12.emplace_back(z0max_12_value);
92 m_dphimax_12.emplace_back(dphimax_12_value);
93 m_phislopemax_12.emplace_back(phislopemax_12_value);
94 m_detamax_12.emplace_back(detamax_12_value);
95 }
96}
97
98void FPGATrackSimGNNGraphConstructionTool::doModuleMap(const std::vector<std::shared_ptr<FPGATrackSimGNNHit>> & hits, std::vector<std::shared_ptr<FPGATrackSimGNNEdge>> & edges)
99{
100 // Use Module Map method for edge building
101 // Two types of module maps: Doublet and Triplet
102 // For each type of module map there is three functions: minmax, meanrms, and hybrid
103 // Use the proper configuration set by the input script and passed as Gaudi::Property variables
104 // Currently only Doublet Module Map with minmax cuts exist, but others can be implemented later on as desired
105
106 if(m_moduleMapType == "doublet") {
107 getDoubletEdges(hits, edges);
108 }
109}
110
111void FPGATrackSimGNNGraphConstructionTool::getDoubletEdges(const std::vector<std::shared_ptr<FPGATrackSimGNNHit>> & hits, std::vector<std::shared_ptr<FPGATrackSimGNNEdge>> & edges)
112{
113 // Take the list of hits and use the doublet module map to generate all the edges between hits that pass the doublet cuts
114
115 for (size_t i = 0; i < m_mid2.size(); i++) {
116 std::vector<std::shared_ptr<FPGATrackSimGNNHit>> hit1_matches;
117 std::vector<std::shared_ptr<FPGATrackSimGNNHit>> hit2_matches;
118
119 std::vector<int> hit1_indices;
120 std::vector<int> hit2_indices;
121
122 for (size_t j = 0; j < hits.size(); j++) {
123 if (hits[j]->getIdentifier() == m_mid1[i]) {
124 hit1_matches.emplace_back(hits[j]);
125 hit1_indices.emplace_back(j);
126 }
127 if (hits[j]->getIdentifier() == m_mid2[i]) {
128 hit2_matches.emplace_back(hits[j]);
129 hit2_indices.emplace_back(j);
130 }
131 }
132
133 for (size_t h1 = 0; h1 < hit1_matches.size(); h1++) {
134 for (size_t h2 = 0; h2 < hit2_matches.size(); h2++) {
135 applyDoubletCuts(hit1_matches[h1], hit2_matches[h2], edges, hit1_indices[h1], hit2_indices[h2], i);
136 }
137 }
138 }
139}
140
141void FPGATrackSimGNNGraphConstructionTool::applyDoubletCuts(const std::shared_ptr<FPGATrackSimGNNHit> & hit1, const std::shared_ptr<FPGATrackSimGNNHit> & hit2, std::vector<std::shared_ptr<FPGATrackSimGNNEdge>> & edges, int hit1_index, int hit2_index, unsigned int modulemap_id)
142{
143 // Four types of doublet cuts (dEta, z0, dPhi, phiSlope)
144 // If an edge passes all four, then it is a valid edge and can be stored
145
146 // delta_eta cuts
147 float deta = hit1->getEta() - hit2->getEta();
148 if(!doMask(deta, m_detamin_12[modulemap_id], m_detamax_12[modulemap_id])) return;
149
150 // z0 cuts
151 float dz = hit2->getZ() - hit1->getZ();
152 float dr = hit2->getR() - hit1->getR();
153 float z0 = dr==0. ? 0. : hit1->getZ() - (hit1->getR() * dz / dr);
154 if(!doMask(z0, m_z0min_12[modulemap_id], m_z0max_12[modulemap_id])) return;
155
156 // delta_phi cuts
157 float dphi = P4Helpers::deltaPhi(hit2->getPhi(),hit1->getPhi());
158 if(!doMask(dphi, m_dphimin_12[modulemap_id], m_dphimax_12[modulemap_id])) return;
159
160 // phislope cuts
161 float phislope = dr==0. ? 0. : dphi / dr;
162 if(!doMask(phislope, m_phislopemin_12[modulemap_id], m_phislopemax_12[modulemap_id])) return;
163
164 // if pass all doublet cuts, then record the edge information
165 std::shared_ptr<FPGATrackSimGNNEdge> edge = std::make_shared<FPGATrackSimGNNEdge>();
166 edge->setEdgeIndex1(hit1_index);
167 edge->setEdgeIndex2(hit2_index);
168 edges.emplace_back(edge);
169}
170
172{
173 bool mask = false;
174 if(m_moduleMapFunc == "minmax") {
175 mask = doMinMaxMask(val, min, max);
176 }
177
178 return mask;
179}
180
182{
183 bool mask = false;
184
185 if((val <= max * (1.0 + featureSign(max) * m_moduleMapTol)) &&
186 (val >= min * (1.0 - featureSign(min) * m_moduleMapTol))) {
187 mask = true;
188 }
189
190 return mask;
191}
192
194{
195 if(feature < 0.0) { return -1.0; }
196 else if(feature > 0.0) { return 1.0; }
197 else { return 0.0; }
198}
199
200void FPGATrackSimGNNGraphConstructionTool::doMetricLearning(const std::vector<std::shared_ptr<FPGATrackSimGNNHit>> & hits, std::vector<std::shared_ptr<FPGATrackSimGNNEdge>> & edges)
201{
202 // Use Metric Learning for edge construction
203 // Clustering properties can be set in the input scripta as Gaudi::Property variables
204 std::vector<float> gNodeFeatures = getNodeFeatures(hits);
205 std::vector<float> gEmbedded = embed(hits);
206 doClustering(hits, edges, gEmbedded);
207}
208
209std::vector<float> FPGATrackSimGNNGraphConstructionTool::getNodeFeatures(const std::vector<std::shared_ptr<FPGATrackSimGNNHit>> & hits)
210{
211 std::vector<float> gNodeFeatures;
212
213 for(auto hit : hits) {
214 std::map<std::string, float> features;
215 features["r"] = hit->getR();
216 features["phi"] = hit->getPhi();
217 features["z"] = hit->getZ();
218
219 for(size_t i = 0; i < m_MLFeatureNamesVec.size(); i++){
220 gNodeFeatures.push_back(
221 features[m_MLFeatureNamesVec[i]] / m_MLFeatureScalesVec[i]);
222 }
223 }
224 return gNodeFeatures;
225}
226
227std::vector<float> FPGATrackSimGNNGraphConstructionTool::embed(const std::vector<std::shared_ptr<FPGATrackSimGNNHit>> & hits)
228{
229 // Use the ML network to embed the hits in a 12-dim latent space
230 std::vector<float> gNodeFeatures = getNodeFeatures(hits);
231 std::vector<float> gEmbedded;
232
233 std::vector<Ort::Value> gInputTensor;
234 StatusCode s = m_MLInferenceTool->addInput(gInputTensor, gNodeFeatures, 0, hits.size());
235 std::vector<Ort::Value> gOutputTensor;
236 s = m_MLInferenceTool->addOutput(gOutputTensor, gEmbedded, 0, hits.size());
237 s = m_MLInferenceTool->inference(gInputTensor, gOutputTensor);
238
239 return gEmbedded;
240}
241
242void FPGATrackSimGNNGraphConstructionTool::doClustering(const std::vector<std::shared_ptr<FPGATrackSimGNNHit>> & hits, std::vector<std::shared_ptr<FPGATrackSimGNNEdge>> & edges,
243 std::vector<float> & gEmbedded)
244{
245 // Create graph edges based on the hits distance in the latent space
246 // Creates a directed graph
247 int n_dim = 12;
248 int size = hits.size();
249 float r_squared = m_metricLearningR*m_metricLearningR;
250 int index1 = 0;
251 int index2 = 0;
252 int count = 0;
253 float distance = 0.;
254 std::vector<float> start(n_dim);
255
256 // Loop over all hits
257 for(int k = 0; k < size; ++k){
258 count = 0;
259 // Setup current hit
260 for(int j = 0; j < n_dim; ++j){
261 start[j] = gEmbedded[k*n_dim + j];
262 }
263 // Loop over the hits not yet checked
264 for (int i = k + 1; i < size; ++i){
265 distance = 0.;
266 for(int d = 0; d < n_dim; ++d){
267 distance += (start[d] - gEmbedded[i*n_dim + d]) * (start[d] - gEmbedded[i*n_dim + d]);
268 }
269 // Store edge if the distance between the hits meets is below the limit
270 if(distance < r_squared){
271 std::shared_ptr<FPGATrackSimGNNEdge> edge = std::make_shared<FPGATrackSimGNNEdge>();
272 // Set order of edge indices to make a directed graph
273 float d_i_sq = (hits[i]->getR() * hits[i]->getR()) + (hits[i]->getZ() * hits[i]->getZ());
274 float d_k_sq = (hits[k]->getR() * hits[k]->getR()) + (hits[k]->getZ() * hits[k]->getZ());
275 if (d_i_sq < d_k_sq){
276 index1 = i;
277 index2 = k;
278 } else {
279 index1 = k;
280 index2 = i;
281 }
282
283 edge->setEdgeIndex1(index1);
284 edge->setEdgeIndex2(index2);
285 edges.emplace_back(edge);
286 ++count;
287 }
288 // Upper limit for connections of the same hit
290 break;
291 }
292 }
293
294 }
295}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
Implements graph construction tool to build edges (connections) between hits.
#define min(a, b)
Definition cfImp.cxx:40
#define max(a, b)
Definition cfImp.cxx:41
AthAlgTool(const std::string &type, const std::string &name, const IInterface *parent)
Constructor with parameters:
ToolHandle< AthOnnx::IOnnxRuntimeInferenceTool > m_MLInferenceTool
virtual StatusCode getEdges(const std::vector< std::shared_ptr< FPGATrackSimGNNHit > > &hits, std::vector< std::shared_ptr< FPGATrackSimGNNEdge > > &edges)
void getDoubletEdges(const std::vector< std::shared_ptr< FPGATrackSimGNNHit > > &hits, std::vector< std::shared_ptr< FPGATrackSimGNNEdge > > &edges)
std::vector< float > getNodeFeatures(const std::vector< std::shared_ptr< FPGATrackSimGNNHit > > &hits)
void applyDoubletCuts(const std::shared_ptr< FPGATrackSimGNNHit > &hit1, const std::shared_ptr< FPGATrackSimGNNHit > &hit2, std::vector< std::shared_ptr< FPGATrackSimGNNEdge > > &edges, int hit1_index, int hit2_index, unsigned int modulemap_id)
std::vector< float > embed(const std::vector< std::shared_ptr< FPGATrackSimGNNHit > > &hits)
void doClustering(const std::vector< std::shared_ptr< FPGATrackSimGNNHit > > &hits, std::vector< std::shared_ptr< FPGATrackSimGNNEdge > > &edges, std::vector< float > &gEmbedded)
void doMetricLearning(const std::vector< std::shared_ptr< FPGATrackSimGNNHit > > &hits, std::vector< std::shared_ptr< FPGATrackSimGNNEdge > > &edges)
FPGATrackSimGNNGraphConstructionTool(const std::string &, const std::string &, const IInterface *)
void doModuleMap(const std::vector< std::shared_ptr< FPGATrackSimGNNHit > > &hits, std::vector< std::shared_ptr< FPGATrackSimGNNEdge > > &edges)
ServiceHandle< IFPGATrackSimMappingSvc > m_FPGATrackSimMapping
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
double deltaPhi(double phiA, double phiB)
delta Phi in range [-pi,pi[
Definition P4Helpers.h:34
TChain * tree
TFile * file