ATLAS Offline Software
Loading...
Searching...
No Matches
FPGATrackSimConstGenAlgo.cxx
Go to the documentation of this file.
1// Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
9
11#include "GaudiKernel/MsgStream.h"
12#include "GaudiKernel/ITHistSvc.h"
13
18
19#include "TH1F.h"
20#include "TTree.h"
21#include "TFile.h"
22#include "TMath.h"
23#include "TROOT.h"
24#include "TMatrixD.h"
25
26#include <sstream>
27#include <iostream>
28#include <fstream>
29#include <cmath>
30#include <string>
31#include <stdio.h>
32#include <math.h>
33#include <stdlib.h>
34#include <cassert>
35#include <format>
36#include <stdexcept>
37
38#include <TVectorD.h>
39#include <TDecompLU.h>
40
41#define MIN_TRACK_SEC 50 // min number of tracks per sector
42
43using namespace std;
44
45namespace {
46 template<typename ...Ptr>
47 bool
48 anyNullPtr(Ptr&&...p){
49 return ((p!=nullptr) && ...) ;
50 }
51}
52
54// Initialize
56
57FPGATrackSimConstGenAlgo::FPGATrackSimConstGenAlgo(const std::string& name, ISvcLocator* pSvcLocator) :
58 AthAlgorithm(name, pSvcLocator)
59{
60}
61
62
64{
65 ATH_MSG_DEBUG("initialize()");
66 ATH_MSG_DEBUG("Are we going to dump missing hist constants? " << m_dumpMissingHitsConstants);
68 ATH_CHECK(m_EvtSel.retrieve());
69 m_pmap = (m_isSecondStage ? m_FPGATrackSimMapping->PlaneMap_2nd(0) : m_FPGATrackSimMapping->PlaneMap_1st(0) );
70
71 ATH_CHECK(m_tHistSvc.retrieve());
73
74 // Input file
75 ATH_MSG_DEBUG("reading " << m_cfpath.value());
76 m_mafile = TFile::Open(m_cfpath.value().c_str());
77 gROOT->cd();
78 // Copy the slice tree
80
81 // Read sizing
82 m_matrix_tree = (TTree*)m_mafile->Get(("am" + std::to_string(0)).c_str());
83 m_matrix_tree->SetBranchAddress("ndim", &m_nCoords);
84 m_matrix_tree->SetBranchAddress("nplanes", &m_nLayers);
85 m_matrix_tree->GetEntry(0);
89
90 if (static_cast<size_t>(m_nLayers) == m_FPGATrackSimMapping->PlaneMap_2nd(0)->getNLogiLayers())
91 m_pmap = m_FPGATrackSimMapping->PlaneMap_2nd(0);
92 else if (static_cast<size_t>(m_nLayers) == m_FPGATrackSimMapping->PlaneMap_1st(0)->getNLogiLayers())
93 m_pmap = m_FPGATrackSimMapping->PlaneMap_1st(0);
94 else
95 ATH_MSG_ERROR("nLayers " << m_nLayers << " doesn't match any pmap");
96
98
99 // Read skip list
100 if (!m_skipFile.empty()) readSkipList(m_matrix_tree->GetEntries());
101
102 // Prepare output contstants tree
104
105 // Create the good tree
106 std::string tree_name = "am" + std::to_string(0);
107 std::string tree_title = "Ambank " + std::to_string(0) + " matrices";
108 m_good_tree = new TTree(tree_name.c_str(), tree_title.c_str());
109 ATH_CHECK(m_tHistSvc->regTree(("/TRIGFPGATrackSimTREEGOODOUT/"+tree_name).c_str(), m_good_tree));
110
111 // Run the constant generation
113
114 return StatusCode::SUCCESS;
115}
116
117
119{
120 //usage guide:
121 //https://acode-browser.usatlas.bnl.gov/lxr/source/Gaudi/GaudiSvc/src/THistSvc/README.md
122 auto h_vc = std::make_unique<TH1F>("h_vc","h_vc",500,-1e-4,1e-4);
123 auto h_vd = std::make_unique<TH1F>("h_vd","h_vd",500,-1e-2,1e-2);
124 auto h_vf = std::make_unique<TH1F>("h_vf","h_vf",500,-1e-2,1e-2);
125 auto h_vz = std::make_unique<TH1F>("h_vz","h_vz",500,-1e-2,1e-2);
126 auto h_veta = std::make_unique<TH1F>("h_veta","h_veta",500,-1e-2,1e-2);
127 ATH_CHECK(m_tHistSvc->regHist("/TRIGFPGATrackSimTREEGOODOUT/h_vc",std::move(h_vc)));
128 ATH_CHECK(m_tHistSvc->regHist("/TRIGFPGATrackSimTREEGOODOUT/h_vd",std::move(h_vd)));
129 ATH_CHECK(m_tHistSvc->regHist("/TRIGFPGATrackSimTREEGOODOUT/h_vf",std::move(h_vf)));
130 ATH_CHECK(m_tHistSvc->regHist("/TRIGFPGATrackSimTREEGOODOUT/h_vz",std::move(h_vz)));
131 ATH_CHECK(m_tHistSvc->regHist("/TRIGFPGATrackSimTREEGOODOUT/h_veta",std::move(h_veta)));
132
133 return StatusCode::SUCCESS;
134}
135
136
138{
139 // Read old tree
140 TTree *old_tree = (TTree*)file->Get("slice");
141 old_tree->SetBranchAddress("c_max", &m_sliceMax.qOverPt);
142 old_tree->SetBranchAddress("c_min", &m_sliceMin.qOverPt);
143 old_tree->SetBranchAddress("c_slices", &m_sliceNBins.qOverPt);
144
145 old_tree->SetBranchAddress("phi_max", &m_sliceMax.phi);
146 old_tree->SetBranchAddress("phi_min", &m_sliceMin.phi);
147 old_tree->SetBranchAddress("phi_slices", &m_sliceNBins.phi);
148
149 old_tree->SetBranchAddress("d0_max", &m_sliceMax.d0);
150 old_tree->SetBranchAddress("d0_min", &m_sliceMin.d0);
151 old_tree->SetBranchAddress("d0_slices", &m_sliceNBins.d0);
152
153 old_tree->SetBranchAddress("z0_max", &m_sliceMax.z0);
154 old_tree->SetBranchAddress("z0_min", &m_sliceMin.z0);
155 old_tree->SetBranchAddress("z0_slices", &m_sliceNBins.z0);
156
157 old_tree->SetBranchAddress("eta_max", &m_sliceMax.eta);
158 old_tree->SetBranchAddress("eta_min", &m_sliceMin.eta);
159 old_tree->SetBranchAddress("eta_slices", &m_sliceNBins.eta);
160
161 old_tree->GetEntry(0);
162
163 // Write new tree
164 TTree *new_tree = new TTree("slice", "Slice boundaries");
165 ATH_CHECK(m_tHistSvc->regTree("/TRIGFPGATrackSimTREEGOODOUT/slice", new_tree));
166
167 new_tree->Branch("c_max", &m_sliceMax.qOverPt);
168 new_tree->Branch("c_min", &m_sliceMin.qOverPt);
169 new_tree->Branch("c_slices", &m_sliceNBins.qOverPt);
170
171 new_tree->Branch("phi_max", &m_sliceMax.phi);
172 new_tree->Branch("phi_min", &m_sliceMin.phi);
173 new_tree->Branch("phi_slices", &m_sliceNBins.phi);
174
175 new_tree->Branch("d0_max", &m_sliceMax.d0);
176 new_tree->Branch("d0_min", &m_sliceMin.d0);
177 new_tree->Branch("d0_slices", &m_sliceNBins.d0);
178
179 new_tree->Branch("z0_max", &m_sliceMax.z0);
180 new_tree->Branch("z0_min", &m_sliceMin.z0);
181 new_tree->Branch("z0_slices", &m_sliceNBins.z0);
182
183 new_tree->Branch("eta_max", &m_sliceMax.eta);
184 new_tree->Branch("eta_min", &m_sliceMin.eta);
185 new_tree->Branch("eta_slices", &m_sliceNBins.eta);
186
187 new_tree->Fill();
188
189 return StatusCode::SUCCESS;
190}
191
192
194{
195 // Dummy variables for typing
196 int anInt;
197 float aFloat;
198 double aDouble;
199
200 std::string tree_name = "am" + std::to_string(0);
201 std::string tree_title = "Ambank " + std::to_string(0) + " constants";
202 m_ctree = new TTree(tree_name.c_str(), tree_title.c_str());
203
204 m_ctree->Branch("ndim", &m_nCoords, "ndim/I");
205 m_ctree->Branch("ndim2", &m_nCoords_2, "ndim2/I");
206 m_ctree->Branch("nkernel", &m_nKernel, "nkernel/I");
207 m_ctree->Branch("nkaverages", &m_nKAverages, "nkaverages/I");
208 m_ctree->Branch("nplane", &m_nLayers, "nplane/I");
209
210 m_ctree->Branch("sectorID", &anInt, "sectorID[nplane]/I");
211 m_ctree->Branch("hashID", &anInt, "hashID[nplane]/I");
212 m_ctree->Branch("nhit", &aFloat, "nhit/F");
213
214 m_ctree->Branch("Cd", &aDouble, "Cd/D");
215 m_ctree->Branch("Cc", &aDouble, "Cc/D");
216 m_ctree->Branch("Cf", &aDouble, "Cf/D");
217 m_ctree->Branch("Cz0", &aDouble, "Cz0/D");
218 m_ctree->Branch("Co", &aDouble, "Co/D");
219
220 m_ctree->Branch("Vc", &aDouble, "Vc[ndim]/D");
221 m_ctree->Branch("Vd", &aDouble, "Vd[ndim]/D");
222 m_ctree->Branch("Vf", &aDouble, "Vf[ndim]/D");
223 m_ctree->Branch("Vz0", &aDouble, "Vz0[ndim]/D");
224 m_ctree->Branch("Vo", &aDouble, "Vo[ndim]/D");
225
226 m_ctree->Branch("kernel", &aDouble, "kernel[nkernel]/D");
227 m_ctree->Branch("kaverages", &aDouble, "kaverages[nkaverages]/D");
228
229 ATH_CHECK(m_tHistSvc->regTree(("/TRIGFPGATrackSimCTREEOUT/"+tree_name).c_str(), m_ctree));
230 return StatusCode::SUCCESS;
231}
232
233
235{
236 m_skipList.resize(nSectors);
237
238 std::ifstream file(m_skipFile);
239 if (!file.is_open()) return;
240
241 size_t count = 0;
242 size_t sector;
243 while (file >> sector)
244 {
245 if (sector >= nSectors)
246 {
247 ATH_MSG_ERROR("Bad sector " << sector << "/" << nSectors);
248 return;
249 }
250 m_skipList[sector] = true;
251 count++;
252 }
253 ATH_MSG_INFO("Skipping " << count << " sectors out of " << nSectors);
254 file.close();
255}
256
257
258
259// Main function. Generates constants into m_geo_consts, and copies the good matrices into m_good_tree.
261{
264 for (size_t entry = 0; entry < (size_t)m_matrix_tree->GetEntries(); entry++)
265 {
266 // Read the entry
267 if (!m_skipList.empty() && m_skipList[entry]) continue;
268 reader.readEntry(entry);
269 std::vector<module_t> & modules = reader.getModules();
270 FPGATrackSimMatrixAccumulator & acc = reader.getAccumulator();
271
272 // Check for sufficient statistics
273 if (acc.track_bins.size() < MIN_TRACK_SEC)
274 {
275 ATH_MSG_DEBUG("Insufficient tracks in sector " << reader.getEntry());
276 continue;
277 }
278
279 // Scale and normalize the accumulated variables
281
282 // Create the constants
284 bool success = GetConstants(acc_norm, geo, entry);
285 if (!success) continue;
286
287 // Fill the constant tree and good matrix tree
288 fillConstTree(modules, acc, geo);
289 writer.fill(modules, acc);
290 m_geo_consts.push_back(std::move(geo));
291
292 // If needed, we generate the same as above but dropping/ignoring each potential hit
294 }
295}
296
298{
299 for (int ip = 0; ip < m_nLayers; ip++)
300 {
301 int missing = m_pmap->getCoordOffset(ip); // this is the coordinate we are missing
302 if (!acc_norm.coords_usable[missing]) // just skip ahead if we aren't using this coordinate already
303 {
304 geo_constants emptyGeo(m_nCoords);
305 m_geo_consts_with_missinghit[ip].push_back(std::move(emptyGeo));
306 continue;
307 }
308
309 unsigned int nusable = acc_norm.nusable() - 1;
310 std::vector<bool> coordsToUse = acc_norm.coords_usable;
311 coordsToUse[missing] = false;
312
313 if (m_pmap->getDim(ip) == 2)
314 {
315 coordsToUse[missing+1] = false;
316 nusable--;
317 }
318
319
321 bool success = GetConstants(acc_norm, geo, entry, coordsToUse, nusable);
322 if (!success)
323 {
324 // push this back to keep the order correct (ie same numbering as nominal constants)
325 geo_constants emptyGeo(m_nCoords);
326 m_geo_consts_with_missinghit[ip].push_back(std::move(emptyGeo));
327 }
328 else
329 {
330 m_geo_consts_with_missinghit[ip].push_back(std::move(geo));
331 }
332 }
333}
334
336{
337 return GetConstants(acc_norm, geo, entryNumber, acc_norm.coords_usable, acc_norm.nusable());
338}
339
340bool FPGATrackSimConstGenAlgo::GetConstants(FPGATrackSimMatrixAccumulator const &acc_norm, geo_constants &geo, int entryNumber, std::vector<bool> const &coordsToUse, unsigned int nusable)
341{
342 // Get the reduced matrix and invert it
343 TMatrixD mtx_reduced = getReducedMatrix(m_nCoords, acc_norm.covariance, coordsToUse, nusable);
344 if (isSingular(mtx_reduced))
345 {
346 ATH_MSG_DEBUG("Singular matrix in sector " << entryNumber);
347 return false;
348 }
349 std::vector<double> inv_covariance = invert(m_nCoords, mtx_reduced, coordsToUse);
350
351 // Calculate the eigen system
352 std::vector<double> eigvals;
353 vector2D<double> eigvecs;
354
355 eigen(nusable, m_nCoords, mtx_reduced, coordsToUse, eigvals, eigvecs);
356
357 // Calculate the constants
358 geo = makeConsts(acc_norm, coordsToUse, inv_covariance, eigvals, eigvecs);
359
360 if (failedConstants(geo, coordsToUse))
361 {
362 ATH_MSG_DEBUG("Failed constants in sector " << entryNumber);
363 return false;
364 }
365
366 return true;
367}
368
370{
371 float coverage = static_cast<float>(acc.track_bins.size());
372 m_ctree->SetBranchAddress("sectorID", acc.FTK_modules.data());
373 m_ctree->SetBranchAddress("hashID", modules.data());
374 m_ctree->SetBranchAddress("nhit", &coverage);
375
376 m_ctree->SetBranchAddress("Cc", &geo.pars.qOverPt);
377 m_ctree->SetBranchAddress("Cd", &geo.pars.d0);
378 m_ctree->SetBranchAddress("Cf", &geo.pars.phi);
379 m_ctree->SetBranchAddress("Cz0", &geo.pars.z0);
380 m_ctree->SetBranchAddress("Co", &geo.pars.eta);
381
382 m_ctree->SetBranchAddress("Vc", geo.Vcurvature.data());
383 m_ctree->SetBranchAddress("Vd", geo.Vd0.data());
384 m_ctree->SetBranchAddress("Vf", geo.Vphi.data());
385 m_ctree->SetBranchAddress("Vz0", geo.Vz0.data());
386 m_ctree->SetBranchAddress("Vo", geo.Veta.data());
387
388 m_ctree->SetBranchAddress("kaverages", geo.kaverages.data());
389 m_ctree->SetBranchAddress("kernel", geo.kernel.data());
390
391 m_ctree->Fill();
392
393 if (m_Monitor)
394 {
395 const std::string prefix{"/TRIGFPGATrackSimTREEGOODOUT/"};
396 auto getHistogram = [&](const std::string & suffix)->TH1*{
397 TH1 * ptr{};
398 const auto sc = m_tHistSvc->getHist(prefix+suffix, ptr);
399 return (sc == StatusCode::SUCCESS) ? ptr: nullptr;
400 };
401 auto h_vc = getHistogram("h_vc");
402 auto h_vd = getHistogram("h_vd");
403 auto h_vf = getHistogram("h_vf");
404 auto h_vz = getHistogram("h_vz");
405 auto h_veta = getHistogram("h_veta");
406 if (anyNullPtr(h_vc, h_vd, h_vf, h_vz, h_veta)){
407 ATH_MSG_ERROR("FPGATrackSimConstGenAlgo::fillConstTree; nullptr");
408 return;
409 }
410 for (int i = 0; i < m_nCoords; i++)
411 {
412 h_vc->Fill(geo.Vcurvature[i]);
413 h_vd->Fill(geo.Vd0[i]);
414 h_vf->Fill(geo.Vphi[i]);
415 h_vz->Fill(geo.Vz0[i]);
416 h_veta->Fill(geo.Veta[i]);
417 }
418 }
419}
420
421
422bool FPGATrackSimConstGenAlgo::isNAN(double value, const char* name)
423{
424 if (TMath::IsNaN(value))
425 {
426 ATH_MSG_WARNING("NaN found in " << name);
427 return true;
428 }
429 return false;
430}
431
432#define CHECK_NAN(var) (isNAN((var), #var))
433
434// Check if constants are bad (eg, contain "nan")
435bool FPGATrackSimConstGenAlgo::failedConstants(geo_constants const & geo, std::vector<bool> const & usable)
436{
437 geo_constants gco = calculate_gcorth(geo, m_nCoords, usable);
438
439 //if (CHECK_NAN(gco.pars.qOverPt)) return true; commenting out all gco's to gret more sectors. we do not use this anyways... for the meanwhile
440 if (CHECK_NAN(geo.pars.qOverPt)) return true;
441 //if (CHECK_NAN(gco.pars.d0)) return true;
442 if (CHECK_NAN(geo.pars.d0)) return true;
443 //if (CHECK_NAN(gco.pars.phi)) return true;
444 if (CHECK_NAN(geo.pars.phi)) return true;
445 //if (CHECK_NAN(gco.pars.z0)) return true;
446 if (CHECK_NAN(geo.pars.z0)) return true;
447 //if (CHECK_NAN(gco.pars.eta)) return true;
448 if (CHECK_NAN(geo.pars.eta)) return true;
449
450 for (int i = 0; i < m_nCoords; i++)
451 {
452 //if (CHECK_NAN(gco.Vcurvature[i])) return true;
453 if (CHECK_NAN(geo.Vcurvature[i])) return true;
454 //if (CHECK_NAN(gco.Vd0[i])) return true;
455 if (CHECK_NAN(geo.Vd0[i])) return true;
456 //if (CHECK_NAN(gco.Vphi[i])) return true;
457 if (CHECK_NAN(geo.Vphi[i])) return true;
458 //if (CHECK_NAN(gco.Vz0[i])) return true;
459 if (CHECK_NAN(geo.Vz0[i])) return true;
460 //if (CHECK_NAN(gco.Veta[i])) return true;
461 if (CHECK_NAN(geo.Veta[i])) return true;
462 }
463
464 for (int i = 0; i < m_nCoords - FPGATrackSimTrackPars::NPARS; i++)
465 {
466 if (CHECK_NAN(geo.kaverages[i])) return true;
467 for (int j = 0; j < m_nCoords; j++)
468 if (CHECK_NAN(geo.kernel(i,j))) return true;
469 }
470
471 return false;
472}
473
474
476// Arithmetic Functions
478
479/*
480 * This function normalizes the accumulated variables in acc_raw into the actual
481 * averages needed for constant generation. The pars and hit_coords are averaged
482 * using the coverage. The covariance field, which currently stores sum(x_i x_j),
483 * is converted into the actual covariance matrix. The hix_x_par fields are
484 * converted from sum(x_k p_i) to <x_k p_i> - <x_k> <p_i>.
485 */
487{
489 double coverage = static_cast<double>(acc.track_bins.size());
490 size_t nCoords = acc.hit_coords.size();
491
492 for (unsigned i = 0; i < FPGATrackSimTrackPars::NPARS; i++)
493 acc.pars[i] /= coverage;
494
495 for (unsigned i = 0; i < nCoords; i++)
496 {
497 acc.hit_coords[i] /= coverage;
498 if (std::abs(acc.hit_coords[i]) < MTX_TOLERANCE) acc.coords_usable[i] = false;
499 else acc.coords_usable[i] = true;
500 }
501
502 // Divide by n-1 for the sample variance (Bessel's correction)
503 for (unsigned i = 0; i < nCoords; i++)
504 {
505 acc.hit_x_QoP[i] = (acc.hit_x_QoP[i] - acc.hit_coords[i] * acc.pars.qOverPt * coverage) / (coverage-1);
506 acc.hit_x_d0[i] = (acc.hit_x_d0[i] - acc.hit_coords[i] * acc.pars.d0 * coverage) / (coverage-1);
507 acc.hit_x_z0[i] = (acc.hit_x_z0[i] - acc.hit_coords[i] * acc.pars.z0 * coverage) / (coverage-1);
508 acc.hit_x_phi[i] = (acc.hit_x_phi[i] - acc.hit_coords[i] * acc.pars.phi * coverage) / (coverage-1);
509 acc.hit_x_eta[i] = (acc.hit_x_eta[i] - acc.hit_coords[i] * acc.pars.eta * coverage) / (coverage-1);
510
511 // Covariance (and symmetrize)
512 for (unsigned j = i ; j < nCoords; ++j)
513 {
514 acc.covariance[j * nCoords + i] = acc.covariance[i * nCoords + j] =
515 (acc.covariance[i * nCoords + j] - acc.hit_coords[i] * acc.hit_coords[j] * coverage) / (coverage-1);
516 }
517 }
518
519 return acc;
520}
521
522
524 std::vector<double> const & inv_covariance,
525 std::vector<double> const & eigvals, vector2D<double> const & eigvecs)
526{
527 size_t nCoords = acc.hit_coords.size();
528 geo_constants geo(nCoords);
529
530 geo.Vcurvature = matrix_multiply(inv_covariance, acc.hit_x_QoP);
531 geo.Vd0 = matrix_multiply(inv_covariance, acc.hit_x_d0);
532 geo.Vphi = matrix_multiply(inv_covariance, acc.hit_x_phi);
533 geo.Vz0 = matrix_multiply(inv_covariance, acc.hit_x_z0);
534 geo.Veta = matrix_multiply(inv_covariance, acc.hit_x_eta);
535
536 for (size_t i = 0; i < nCoords - FPGATrackSimTrackPars::NPARS; i++)
537 {
538 if (!usable[i]) continue; // vectors are filled with 0's by default
539 for (size_t j = 0; j < nCoords; j++)
540 {
541 if (!usable[j]) continue;
542 if (eigvals[i] > 0)
543 geo.kernel(i, j) = eigvecs(i, j) / sqrt(eigvals[i]);
544
545 geo.kaverages[i] += -geo.kernel(i, j) * acc.hit_coords[j];
546 }
547 }
548
549 geo.pars = acc.pars;
550 for (size_t i = 0; i < nCoords; i++)
551 {
552 geo.pars.d0 += -geo.Vd0[i] * acc.hit_coords[i];
553 geo.pars.qOverPt += -geo.Vcurvature[i] * acc.hit_coords[i];
554 geo.pars.phi += -geo.Vphi[i] * acc.hit_coords[i];
555 geo.pars.z0 += -geo.Vz0[i] * acc.hit_coords[i];
556 geo.pars.eta += -geo.Veta[i] * acc.hit_coords[i];
557 }
558
559 geo.real = static_cast<int>(acc.track_bins.size());
560 return geo;
561}
562
563
564/*
565 * Calculates matrix multiplication x = A * b;
566 *
567 * @param A - (n*n) matrix
568 * @param b - length-n vector
569 * @return A * b (length-n vector)
570 */
571std::vector<double> FPGATrackSimConstGenAlgo::matrix_multiply(std::vector<double> const & A, std::vector<double> const & b)
572{
573 size_t n = b.size();
574 std::vector<double> x(n);
575
576 for (size_t i = 0; i < n; i++)
577 for (size_t j = 0; j < n; j++)
578 x[i] += A[i * n + j] * b[j];
579
580 return x;
581}
582//TMatrixD is 264 bytes passed by value
583//coverity[pass_by_value]
585{
586 TDecompLU dc(mtx); // note mtx is a copy
587 bool ok = dc.InvertLU(mtx, MTX_TOLERANCE);
588 return !ok;
589}
590
591
600TMatrixD FPGATrackSimConstGenAlgo::getReducedMatrix(size_t n, std::vector<double> const & mtx_v, std::vector<bool> const & usable, size_t nDimToUse)
601{
602 TMatrixD mtx(n, n, mtx_v.data());
603 TMatrixD newmtx(nDimToUse, nDimToUse);
604
605 size_t counteri = 0;
606 for (size_t i = 0; i < n; i++)
607 {
608 if (!usable[i]) continue;
609
610 size_t counterj = 0;
611 for (size_t j = 0; j < n; j++)
612 {
613 if (!usable[j]) continue;
614 newmtx[counteri][counterj] = mtx[i][j]; // if we use this coordinate, copy it over
615 counterj++; // iterate counter
616 }
617 assert(counterj == nDimToUse);
618 counteri++;
619 }
620 assert(counteri == nDimToUse);
621
622 return newmtx;
623}
624
625
633std::vector<double> FPGATrackSimConstGenAlgo::invert(size_t n_full, TMatrixD mtx, std::vector<bool> const & usable)
634{
635 // Output
636 std::vector<double> inv(n_full * n_full); // filled with 0s
637
638 mtx.Invert();
639
640 size_t counteri = 0;
641 for (size_t i = 0; i < n_full; i++)
642 {
643 if (!usable[i]) continue;
644
645 size_t counterj = 0;
646 for (size_t j = 0; j < n_full; j++)
647 {
648 if (!usable[j]) continue;
649 inv[i*n_full + j] = mtx[counteri][counterj];
650 counterj++;
651 }
652 counteri++;
653 }
654
655 return inv;
656}
657
658
659/*
660 * Calculates the eigensystem of mtx_v, storing it into eigvals_v and eigvecs_v.
661 * This functions accepts a reduced matrix (0 rows and columns removed) but
662 * returns the full-size eigensystem (padding with 0s as defined by usable).
663 * The eigensystem is sorted by increasing |eigenvalue|.
664 *
665 * @param n_redu - Size of reduced system
666 * @param n_full - Size of full system
667 * @param mtx_v - Input matrix (n_redu * n_redu)
668 * @param usable - List of usable rows/columns in the full matrix (n_full)
669 * @param eigvals_v - Output eigenvalues (n_full), with !usable indices filled with 0
670 * @param eigvecs_v - Output eigenvectors (n_full * n_full, ROW! oriented), with !usable rows & columns filled with 0
671 */
672void FPGATrackSimConstGenAlgo::eigen(size_t n_redu, size_t n_full, TMatrixD &mtx, std::vector<bool> const & usable, std::vector<double> & eigvals_full, vector2D<double> & eigvecs_full)
673{
674
675 // Reduced system (these are sorted by decreasing |eigenvalue|)
676 TVectorD eigvals_redu;
677 TMatrixD eigvecs_redu = mtx.EigenVectors(eigvals_redu);
678
679 // Full system (to be copied into)
680 eigvals_full.resize(n_full, 0);
681 eigvecs_full.resize(n_full, n_full, 0);
682
683 // Reverse order AND transpose. First row in eigvecs_full = last column in eigvecs_redu.
684 // Here, i = row index, j = column index.
685 size_t j_redu = n_redu - 1;
686 for (size_t i_full = 0; i_full < n_full; i_full++)
687 {
688 if (!usable[i_full]) continue;
689
690 size_t i_redu = 0;
691 for (size_t j_full = 0; j_full < n_full; j_full++)
692 {
693 if (!usable[j_full]) continue;
694 eigvecs_full(i_full, j_full) = eigvecs_redu[i_redu][j_redu];
695 i_redu++;
696 }
697 eigvals_full[i_full] = eigvals_redu[j_redu];
698 j_redu--;
699 }
700}
701
702
703double FPGATrackSimConstGenAlgo::dot(const double* vec1, const double* vec2, size_t size)
704{
705 double total = 0;
706 for (size_t i = 0; i < size; i++)
707 total += vec1[i] * vec2[i];
708 return total;
709}
710//geo_constants is 232 bytes passed by value
711//coverity[pass_by_value]
712geo_constants FPGATrackSimConstGenAlgo::calculate_gcorth(geo_constants geo, int nCoords, std::vector<bool> const & usable)
713{
714 for (int i = 0; i < nCoords - FPGATrackSimTrackPars::NPARS;i++)
715 {
716 if (!usable[i]) continue;
717 double norm = dot(geo.kernel[i], geo.kernel[i], nCoords);
718
719 auto project = [&](std::vector<double> & hit_x_par, double & par)
720 {
721 double pr = dot(hit_x_par.data(), geo.kernel[i], nCoords) / norm;
722 for (int j = 0; j < nCoords; j++) hit_x_par[j] += -geo.kernel(i,j) * pr;
723 par += -geo.kaverages[i] * pr;
724 };
725
726 project(geo.Vd0, geo.pars.d0);
727 project(geo.Vcurvature, geo.pars.qOverPt);
728 project(geo.Vphi, geo.pars.phi);
729 project(geo.Vz0, geo.pars.z0);
730 project(geo.Veta, geo.pars.eta);
731 }
732
733 return geo;
734}
735
736
738{
739 // Do nothing; this class does not process events. The main algorithm is
740 // called in initialize() and finalize().
741 return StatusCode::SUCCESS;
742}
743
744
746// Finalize
748
749
751{
752 ATH_MSG_DEBUG("finalize()");
753
754 std::string filename = "corrgen_raw_" + std::to_string(m_nLayers) + "L_reg" + std::to_string(m_region) + "_checkGood" + std::to_string(m_CheckGood2ndStage) + ".gcon";
755
757
759 for (int missing = 0; missing < m_nLayers; missing++) {
760 filename = "corrgen_raw_" + std::to_string(m_nLayers) + "L_reg" + std::to_string(m_region) + "_checkGood" + std::to_string(m_CheckGood2ndStage) + "_skipPlane" + std::to_string(missing) + ".gcon";
761 // pick up only the ones for this missing plane
763 }
764 }
765
767
768 ATH_CHECK(m_tHistSvc->finalize());
769 m_mafile->Close();
770
771 return StatusCode::SUCCESS;
772}
773
774
776{
777 // Create FPGATrackSimSectorSlice
780 FPGATrackSimSectorSlice slice(m_geo_consts.size(), m_sliceNBins, copymin, copymax);
781
782 // Open files
783 std::string sector_filename = "sectors_raw_" + std::to_string(m_nLayers) + "L_reg" + std::to_string(m_region) + "_checkGood" + std::to_string(m_CheckGood2ndStage) + ".patt";
784 std::string sectorHW_filename = "sectorsHW_raw_" + std::to_string(m_nLayers) + "L_reg" + std::to_string(m_region) + "_checkGood" + std::to_string(m_CheckGood2ndStage) + ".patt";
785 FILE *sector_file = fopen(sector_filename.c_str(),"w");
786 if (!sector_file) {
787 ATH_MSG_ERROR("Cannot open output file " << sector_filename);
788 return StatusCode::FAILURE;
789 }
790 FILE *sectorHW_file = fopen(sectorHW_filename.c_str(),"w");
791 if (!sectorHW_file) {
792 ATH_MSG_ERROR("Cannot open output file " << sectorHW_filename);
793 fclose (sector_file);
794 return StatusCode::FAILURE;
795 }
796
797 fprintf(sector_file,"%zu %d\n",m_geo_consts.size(),m_nLayers);
798 fprintf(sectorHW_file,"%zu %d\n",m_geo_consts.size(),m_nLayers);
799
800 // Write sectors
802 while (reader.nextEntry())
803 {
804 FPGATrackSimMatrixAccumulator const & acc = reader.getAccumulator();
805 size_t sector = reader.getEntry();
806
807 fprintf(sector_file,"%zu ", sector);
808 fprintf(sectorHW_file,"%zu ", sector);
809 for(int i=0;i<m_nLayers;i++)
810 {
811 fprintf(sector_file,"%d ", acc.FTK_modules[i]);
812 fprintf(sectorHW_file,"%d ", reader.getModules()[i]);
813 }
814 fprintf(sector_file,"0 %zu", acc.track_bins.size());
815 fprintf(sector_file,"\n");
816 fprintf(sectorHW_file,"0 %zu", acc.track_bins.size());
817 fprintf(sectorHW_file,"\n");
818
819 for (FPGATrackSimTrackParsI const & pars : acc.track_bins)
820 slice.addSectorToSlice(sector, pars);
821 }
822
823 fclose(sector_file);
824 fclose(sectorHW_file);
825 std::string slice_filename = "slices_" + std::to_string(m_nLayers) + "L_reg" + std::to_string(m_region) + ".root";
826 slice.saveSlices(slice_filename);
827
828 return StatusCode::SUCCESS;
829}
830
831
832// ASCII file writeout
833StatusCode FPGATrackSimConstGenAlgo::DumpConstants(std::vector<geo_constants> &geo_consts, std::string & filename)
834{
835 FILE *const_file = fopen(filename.c_str(),"w");
836 if (!const_file) {
837 ATH_MSG_ERROR("Cannot open output file " << filename);
838 return StatusCode::FAILURE;
839 }
840
841 fprintf(const_file,"! *** RECONSTRUCTION GEOMETRY CONSTANTS ***\n");
842 fprintf(const_file,"\n");
843 fprintf(const_file,"Version 2 ! File format version number\n");
844 fprintf(const_file,"\n");
845 fprintf(const_file,"! *** PHI is now in GLOBAL coordinate system ***\n");
846 fprintf(const_file," NPLANES\n");
847 fprintf(const_file," %d\n",m_nLayers);
848 fprintf(const_file," NSECTORS\n");
849 fprintf(const_file,"%zu\n",geo_consts.size());
850 fprintf(const_file," NDIM\n");
851 fprintf(const_file," 2\n");
852
853 std::string str_hex;
854
855 for (size_t sector = 0; sector < geo_consts.size(); sector++)
856 {
857 //gcon file
858 fprintf(const_file,"sector\n");
859 fprintf(const_file,"%zu\n", sector);
860
861 fprintf(const_file," Vc \n");
862 for(int i=0;i<m_nCoords;i++){
863 fprintf(const_file,"%e\n",geo_consts[sector].Vcurvature[i]);
864 }
865
866 fprintf(const_file," Vd \n");
867 for(int i=0;i<m_nCoords;i++){
868 fprintf(const_file,"%e\n",geo_consts[sector].Vd0[i]);
869 }
870
871 fprintf(const_file," Vf \n");
872 for(int i=0;i<m_nCoords;i++){
873 fprintf(const_file,"%e\n",geo_consts[sector].Vphi[i]);
874 }
875
876 fprintf(const_file," Vz0 \n");
877 for(int i=0;i<m_nCoords;i++){
878 fprintf(const_file,"%e\n",geo_consts[sector].Vz0[i]);
879 }
880
881 fprintf(const_file," Vo \n");
882 for(int i=0;i<m_nCoords;i++){
883 fprintf(const_file,"%e\n",geo_consts[sector].Veta[i]);
884 }
885
886 fprintf(const_file,"kaverages\n");
887 for(int i=0;i<m_nCoords-FPGATrackSimTrackPars::NPARS;i++){
888 fprintf(const_file,"%e\n",m_geo_consts[sector].kaverages[i]);
889 }
890
891 fprintf(const_file,"kernel\n");
892 for(int i=0;i<m_nCoords-FPGATrackSimTrackPars::NPARS;i++){
893 for(int j=0;j<m_nCoords;j++){
894 fprintf(const_file,"%e\n",geo_consts[sector].kernel(i, j));
895 }
896 }
897
898 fprintf(const_file,"Cc\n");
899 fprintf(const_file,"%e\n",geo_consts[sector].pars.qOverPt);
900
901 fprintf(const_file,"Cd\n");
902 fprintf(const_file,"%e\n",geo_consts[sector].pars.d0);
903
904 fprintf(const_file,"Cf\n");
905 fprintf(const_file,"%e\n",geo_consts[sector].pars.phi);
906
907 fprintf(const_file,"Cz0\n");
908 fprintf(const_file,"%e\n",geo_consts[sector].pars.z0);
909
910 fprintf(const_file,"Co\n");
911 fprintf(const_file,"%e\n",geo_consts[sector].pars.eta);
912 }
913
914 fclose(const_file);
915
916 return StatusCode::SUCCESS;
917}
918
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define MIN_TRACK_SEC
#define CHECK_NAN(var)
Algorithm to generate fit constants.
#define MTX_TOLERANCE
Classes to read/write matrix files event by event.
Maps physical layers to logical layers.
Stores the range of eta/phi/etc. of each sector.
static Double_t sc
T_ResultType project(ParameterMapping::type< N > parameter_map, const T_Matrix &matrix)
#define x
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor with parameters:
ServiceHandle< IFPGATrackSimEventSelectionSvc > m_EvtSel
ServiceHandle< ITHistSvc > m_tHistSvc
std::vector< std::vector< geo_constants > > m_geo_consts_with_missinghit
geo_constants calculate_gcorth(geo_constants geo, int nCoords, std::vector< bool > const &usable)
bool isNAN(double value, const char *name)
double dot(const double *vec1, const double *vec2, size_t size)
Gaudi::Property< std::string > m_skipFile
TMatrixD getReducedMatrix(size_t n, std::vector< double > const &mtx_v, std::vector< bool > const &usable, size_t nDimToUse)
Removes the rows/columns specified by !usable.
std::vector< double > matrix_multiply(std::vector< double > const &A, std::vector< double > const &b)
void eigen(size_t n_redu, size_t n_full, TMatrixD &mtx, std::vector< bool > const &usable, std::vector< double > &eigvals_v, vector2D< double > &eigvecs_v)
FPGATrackSimTrackParsI m_sliceNBins
std::vector< geo_constants > m_geo_consts
Gaudi::Property< bool > m_dumpMissingHitsConstants
FPGATrackSimMatrixAccumulator normalize(FPGATrackSimMatrixAccumulator const &acc_raw)
bool GetConstants(FPGATrackSimMatrixAccumulator const &acc_norm, geo_constants &geo, int entryNumber)
geo_constants makeConsts(FPGATrackSimMatrixAccumulator const &acc, std::vector< bool > const &usable, std::vector< double > const &inv_covariance, std::vector< double > const &eigvals, vector2D< double > const &eigvecs)
FPGATrackSimConstGenAlgo(const std::string &name, ISvcLocator *pSvcLocator)
void createMissingHitsConstants(FPGATrackSimMatrixAccumulator const &acc_norm, size_t entry)
std::vector< double > invert(size_t n_full, TMatrixD mtx, std::vector< bool > const &usable)
Inverts a reduced matrix, then pads with zeros to recover a full-sized matrix.
Gaudi::Property< bool > m_Monitor
StatusCode copySliceTree(TFile *file)
Gaudi::Property< bool > m_isSecondStage
StatusCode DumpConstants(std::vector< geo_constants > &geo_consts, std::string &filename)
const FPGATrackSimPlaneMap * m_pmap
Gaudi::Property< std::string > m_cfpath
Gaudi::Property< bool > m_CheckGood2ndStage
ServiceHandle< IFPGATrackSimMappingSvc > m_FPGATrackSimMapping
void fillConstTree(std::vector< module_t > &modules, FPGATrackSimMatrixAccumulator &acc, geo_constants &geo)
bool failedConstants(geo_constants const &geo, std::vector< bool > const &usable)
void resize(size_t x1, size_t x2, T const &t=T())
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 dot.py:1
STL namespace.
hold the test vectors and ease the comparison
TFile * file