Skip to content

Commit 54a9c78

Browse files
committed
A3: add new LUT writer
- align executables with names - manage FastTracker variable space
1 parent d8b84ce commit 54a9c78

File tree

6 files changed

+384
-37
lines changed

6 files changed

+384
-37
lines changed

ALICE3/Core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ o2physics_target_root_dictionary(ALICE3Core
2424
o2physics_add_library(FastTracker
2525
SOURCES FastTracker.cxx
2626
DetLayer.cxx
27+
DelphesO2LutWriter.cxx
2728
PUBLIC_LINK_LIBRARIES O2::Framework
2829
O2Physics::AnalysisCore)
2930

ALICE3/Core/DelphesO2LutWriter.cxx

Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2+
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3+
// All rights not expressly granted are reserved.
4+
//
5+
// This software is distributed under the terms of the GNU General Public
6+
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7+
//
8+
// In applying this license CERN does not waive the privileges and immunities
9+
// granted to it by virtue of its status as an Intergovernmental Organization
10+
// or submit itself to any jurisdiction.
11+
12+
///
13+
/// @file DelphesO2LutWriter.cxx
14+
/// @brief Porting to O2Physics of DelphesO2 code.
15+
/// Minimal changes have been made to the original code for adaptation purposes, formatting and commented parts have been considered.
16+
/// Relevant sources:
17+
/// DelphesO2/src/lutWrite.cc https://github.com/AliceO2Group/DelphesO2/blob/master/src/lutWrite.cc
18+
/// @author: Roberto Preghenella
19+
/// @email: preghenella@bo.infn.it
20+
///
21+
22+
#include "ALICE3/Core/DelphesO2TrackSmearer.h"
23+
#include "iostream"
24+
#include "TMatrixD.h"
25+
#include "TVectorD.h"
26+
#include "TMatrixDSymEigen.h"
27+
#include "TDatabasePDG.h"
28+
#include "TLorentzVector.h"
29+
#include "ALICE3/Core/FastTracker.h"
30+
#include "ALICE3/Core/TrackUtilities.h"
31+
32+
// #define USE_FWD_PARAM
33+
#ifdef USE_FWD_PARAM
34+
#include "fwdRes.C"
35+
#endif
36+
37+
o2::fastsim::FastTracker fat;
38+
void diagonalise(lutEntry_t& lutEntry);
39+
static float etaMaxBarrel = 1.75;
40+
41+
bool usePara = true; // use fwd parameterisation
42+
bool useDipole = false; // use dipole i.e. flat parametrization for efficiency and momentum resolution
43+
bool useFlatDipole = false; // use dipole i.e. flat parametrization outside of the barrel
44+
45+
void printLutWriterConfiguration()
46+
{
47+
std::cout << " --- Printing configuration of LUT writer --- " << std::endl;
48+
std::cout << " -> etaMaxBarrel = " << etaMaxBarrel << std::endl;
49+
std::cout << " -> usePara = " << usePara << std::endl;
50+
std::cout << " -> useDipole = " << useDipole << std::endl;
51+
std::cout << " -> useFlatDipole = " << useFlatDipole << std::endl;
52+
}
53+
54+
bool fatSolve(lutEntry_t& lutEntry,
55+
float pt = 0.1,
56+
float eta = 0.0,
57+
const int mass = 0.13957000,
58+
int itof = 0,
59+
int otof = 0,
60+
int q = 1)
61+
{
62+
lutEntry.valid = false;
63+
64+
static TLorentzVector tlv;
65+
tlv.SetPtEtaPhiM(pt, eta, 0., mass);
66+
o2::track::TrackParCov trkIn;
67+
o2::upgrade::convertTLorentzVectorToO2Track(q, tlv, {0., 0., 0.}, trkIn);
68+
69+
o2::track::TrackParCov trkOut;
70+
if (fat.FastTrack(trkIn, trkOut, 1) < 0) {
71+
Printf(" --- fatSolve: FastTrack failed --- \n");
72+
tlv.Print();
73+
return false;
74+
}
75+
lutEntry.valid = true;
76+
lutEntry.itof = fat.GetGoodHitProb(itof);
77+
lutEntry.otof = fat.GetGoodHitProb(otof);
78+
for (int i = 0; i < 15; ++i)
79+
lutEntry.covm[i] = trkOut.getCov()[i];
80+
81+
// define the efficiency
82+
auto totfake = 0.;
83+
lutEntry.eff = 1.;
84+
for (int i = 1; i < 20; ++i) {
85+
auto igoodhit = fat.GetGoodHitProb(i);
86+
if (igoodhit <= 0. || i == itof || i == otof)
87+
continue;
88+
lutEntry.eff *= igoodhit;
89+
auto pairfake = 0.;
90+
for (int j = i + 1; j < 20; ++j) {
91+
auto jgoodhit = fat.GetGoodHitProb(j);
92+
if (jgoodhit <= 0. || j == itof || j == otof)
93+
continue;
94+
pairfake = (1. - igoodhit) * (1. - jgoodhit);
95+
break;
96+
}
97+
totfake += pairfake;
98+
}
99+
lutEntry.eff2 = (1. - totfake);
100+
101+
return true;
102+
}
103+
104+
#ifdef USE_FWD_PARAM
105+
bool fwdSolve(float* covm, float pt = 0.1, float eta = 0.0, float mass = 0.13957000)
106+
#else
107+
bool fwdSolve(float*, float, float, float)
108+
#endif
109+
{
110+
#ifdef USE_FWD_PARAM
111+
if (fwdRes(covm, pt, eta, mass) < 0)
112+
return false;
113+
#endif
114+
return true;
115+
}
116+
117+
bool fwdPara(lutEntry_t& lutEntry, float pt = 0.1, float eta = 0.0, float mass = 0.13957000, float Bfield = 0.5)
118+
{
119+
lutEntry.valid = false;
120+
121+
// parametrised forward response; interpolates between FAT at eta = 1.75 and a fixed parametrisation at eta = 4; only diagonal elements
122+
if (fabs(eta) < etaMaxBarrel || fabs(eta) > 4)
123+
return false;
124+
125+
if (!fatSolve(lutEntry, pt, etaMaxBarrel, mass))
126+
return false;
127+
float covmbarrel[15] = {0};
128+
for (int i = 0; i < 15; ++i) {
129+
covmbarrel[i] = lutEntry.covm[i];
130+
}
131+
132+
// parametrisation at eta = 4
133+
double beta = 1. / sqrt(1 + mass * mass / pt / pt / cosh(eta) / cosh(eta));
134+
float dca_pos = 2.5e-4 / sqrt(3); // 2.5 micron/sqrt(3)
135+
float r0 = 0.5; // layer 0 radius [cm]
136+
float r1 = 1.3;
137+
float r2 = 2.5;
138+
float x0layer = 0.001; // material budget (rad length) per layer
139+
double sigma_alpha = 0.0136 / beta / pt * sqrt(x0layer * cosh(eta)) * (1 + 0.038 * log(x0layer * cosh(eta)));
140+
double dcaxy_ms = sigma_alpha * r0 * sqrt(1 + r1 * r1 / (r2 - r0) / (r2 - r0));
141+
double dcaxy2 = dca_pos * dca_pos + dcaxy_ms * dcaxy_ms;
142+
143+
double dcaz_ms = sigma_alpha * r0 * cosh(eta);
144+
double dcaz2 = dca_pos * dca_pos + dcaz_ms * dcaz_ms;
145+
146+
float Leta = 2.8 / sinh(eta) - 0.01 * r0; // m
147+
double relmomres_pos = 10e-6 * pt / 0.3 / Bfield / Leta / Leta * sqrt(720. / 15.);
148+
149+
float relmomres_barrel = sqrt(covmbarrel[14]) * pt;
150+
float Router = 1; // m
151+
float relmomres_pos_barrel = 10e-6 * pt / 0.3 / Bfield / Router / Router / sqrt(720. / 15.);
152+
float relmomres_MS_barrel = sqrt(relmomres_barrel * relmomres_barrel - relmomres_pos_barrel * relmomres_pos_barrel);
153+
154+
// interpolate MS contrib (rel resolution 0.4 at eta = 4)
155+
float relmomres_MS_eta4 = 0.4 / beta * 0.5 / Bfield;
156+
float relmomres_MS = relmomres_MS_eta4 * pow(relmomres_MS_eta4 / relmomres_MS_barrel, (fabs(eta) - 4.) / (4. - etaMaxBarrel));
157+
float momres_tot = pt * sqrt(relmomres_pos * relmomres_pos + relmomres_MS * relmomres_MS); // total absolute mom reso
158+
159+
// Fill cov matrix diag
160+
for (int i = 0; i < 15; ++i)
161+
lutEntry.covm[i] = 0;
162+
163+
lutEntry.covm[0] = covmbarrel[0];
164+
if (dcaxy2 > lutEntry.covm[0])
165+
lutEntry.covm[0] = dcaxy2;
166+
lutEntry.covm[2] = covmbarrel[2];
167+
if (dcaz2 > lutEntry.covm[2])
168+
lutEntry.covm[2] = dcaz2;
169+
lutEntry.covm[5] = covmbarrel[5]; // sigma^2 sin(phi)
170+
lutEntry.covm[9] = covmbarrel[9]; // sigma^2 tanl
171+
lutEntry.covm[14] = momres_tot * momres_tot / pt / pt / pt / pt; // sigma^2 1/pt
172+
return true;
173+
}
174+
175+
void lutWrite(const char* filename = "lutCovm.dat", int pdg = 211, float field = 0.2, int itof = 0, int otof = 0)
176+
{
177+
178+
if (useFlatDipole && useDipole) {
179+
Printf("Both dipole and dipole flat flags are on, please use only one of them");
180+
return;
181+
}
182+
183+
// output file
184+
std::ofstream lutFile(filename, std::ofstream::binary);
185+
if (!lutFile.is_open()) {
186+
Printf("Did not manage to open output file!!");
187+
return;
188+
}
189+
190+
// write header
191+
lutHeader_t lutHeader;
192+
// pid
193+
lutHeader.pdg = pdg;
194+
lutHeader.mass = TDatabasePDG::Instance()->GetParticle(pdg)->Mass();
195+
const int q = std::abs(TDatabasePDG::Instance()->GetParticle(pdg)->Charge()) / 3;
196+
if (q <= 0) {
197+
Printf("Negative or null charge (%f) for pdg code %i. Fix the charge!", TDatabasePDG::Instance()->GetParticle(pdg)->Charge(), pdg);
198+
return;
199+
}
200+
lutHeader.field = field;
201+
// nch
202+
lutHeader.nchmap.log = true;
203+
lutHeader.nchmap.nbins = 20;
204+
lutHeader.nchmap.min = 0.5;
205+
lutHeader.nchmap.max = 3.5;
206+
// radius
207+
lutHeader.radmap.log = false;
208+
lutHeader.radmap.nbins = 1;
209+
lutHeader.radmap.min = 0.;
210+
lutHeader.radmap.max = 100.;
211+
// eta
212+
lutHeader.etamap.log = false;
213+
lutHeader.etamap.nbins = 80;
214+
lutHeader.etamap.min = -4.;
215+
lutHeader.etamap.max = 4.;
216+
// pt
217+
lutHeader.ptmap.log = true;
218+
lutHeader.ptmap.nbins = 200;
219+
lutHeader.ptmap.min = -2;
220+
lutHeader.ptmap.max = 2.;
221+
lutFile.write(reinterpret_cast<char*>(&lutHeader), sizeof(lutHeader));
222+
223+
// entries
224+
const int nnch = lutHeader.nchmap.nbins;
225+
const int nrad = lutHeader.radmap.nbins;
226+
const int neta = lutHeader.etamap.nbins;
227+
const int npt = lutHeader.ptmap.nbins;
228+
lutEntry_t lutEntry;
229+
230+
// write entries
231+
for (int inch = 0; inch < nnch; ++inch) {
232+
auto nch = lutHeader.nchmap.eval(inch);
233+
lutEntry.nch = nch;
234+
fat.SetdNdEtaCent(nch);
235+
std::cout << " --- setting FAT dN/deta: " << nch << std::endl;
236+
for (int irad = 0; irad < nrad; ++irad) {
237+
for (int ieta = 0; ieta < neta; ++ieta) {
238+
auto eta = lutHeader.etamap.eval(ieta);
239+
lutEntry.eta = lutHeader.etamap.eval(ieta);
240+
for (int ipt = 0; ipt < npt; ++ipt) {
241+
lutEntry.pt = lutHeader.ptmap.eval(ipt);
242+
lutEntry.valid = true;
243+
if (fabs(eta) <= etaMaxBarrel) { // full lever arm ends at etaMaxBarrel
244+
// printf(" --- fatSolve: pt = %f, eta = %f, mass = %f, field=%f \n", lutEntry.pt, lutEntry.eta, lutHeader.mass, lutHeader.field);
245+
if (!fatSolve(lutEntry, lutEntry.pt, lutEntry.eta, lutHeader.mass, itof, otof, q)) {
246+
// printf(" --- fatSolve: error \n");
247+
lutEntry.valid = false;
248+
lutEntry.eff = 0.;
249+
lutEntry.eff2 = 0.;
250+
for (int i = 0; i < 15; ++i)
251+
lutEntry.covm[i] = 0.;
252+
}
253+
} else {
254+
// printf(" --- fwdSolve: pt = %f, eta = %f, mass = %f, field=%f \n", lutEntry.pt, lutEntry.eta, lutHeader.mass, lutHeader.field);
255+
lutEntry.eff = 1.;
256+
lutEntry.eff2 = 1.;
257+
bool retval = true;
258+
if (useFlatDipole) { // Using the parametrization at the border of the barrel
259+
retval = fatSolve(lutEntry, lutEntry.pt, etaMaxBarrel, lutHeader.mass, itof, otof, q);
260+
} else if (usePara) {
261+
retval = fwdPara(lutEntry, lutEntry.pt, lutEntry.eta, lutHeader.mass, field);
262+
} else {
263+
retval = fwdSolve(lutEntry.covm, lutEntry.pt, lutEntry.eta, lutHeader.mass);
264+
}
265+
if (useDipole) { // Using the parametrization at the border of the barrel only for efficiency and momentum resolution
266+
lutEntry_t lutEntryBarrel;
267+
retval = fatSolve(lutEntryBarrel, lutEntry.pt, etaMaxBarrel, lutHeader.mass, itof, otof, q);
268+
lutEntry.valid = lutEntryBarrel.valid;
269+
lutEntry.covm[14] = lutEntryBarrel.covm[14];
270+
lutEntry.eff = lutEntryBarrel.eff;
271+
lutEntry.eff2 = lutEntryBarrel.eff2;
272+
}
273+
if (!retval) {
274+
// printf(" --- fwdSolve: error \n");
275+
lutEntry.valid = false;
276+
for (int i = 0; i < 15; ++i)
277+
lutEntry.covm[i] = 0.;
278+
}
279+
}
280+
diagonalise(lutEntry);
281+
lutFile.write(reinterpret_cast<char*>(&lutEntry), sizeof(lutEntry_t));
282+
}
283+
}
284+
}
285+
}
286+
287+
lutFile.close();
288+
}
289+
290+
void diagonalise(lutEntry_t& lutEntry)
291+
{
292+
TMatrixDSym m(5);
293+
double fcovm[5][5];
294+
for (int i = 0, k = 0; i < 5; ++i)
295+
for (int j = 0; j < i + 1; ++j, ++k) {
296+
fcovm[i][j] = lutEntry.covm[k];
297+
fcovm[j][i] = lutEntry.covm[k];
298+
}
299+
m.SetMatrixArray((double*)fcovm);
300+
TMatrixDSymEigen eigen(m);
301+
// eigenvalues vector
302+
TVectorD eigenVal = eigen.GetEigenValues();
303+
for (int i = 0; i < 5; ++i)
304+
lutEntry.eigval[i] = eigenVal[i];
305+
// eigenvectors matrix
306+
TMatrixD eigenVec = eigen.GetEigenVectors();
307+
for (int i = 0; i < 5; ++i)
308+
for (int j = 0; j < 5; ++j)
309+
lutEntry.eigvec[i][j] = eigenVec[i][j];
310+
// inverse eigenvectors matrix
311+
eigenVec.Invert();
312+
for (int i = 0; i < 5; ++i)
313+
for (int j = 0; j < 5; ++j)
314+
lutEntry.eiginv[i][j] = eigenVec[i][j];
315+
}

ALICE3/Core/FastTracker.cxx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
// or submit itself to any jurisdiction.
1111

1212
#include <vector>
13+
#include <string>
1314
#include "TMath.h"
1415
#include "TMatrixD.h"
1516
#include "TRandom.h"
@@ -214,7 +215,7 @@ float FastTracker::Dist(float z, float r)
214215
if (i == nSteps - 1)
215216
index = 1;
216217
z0 = -4 * sigmaD + i * dz0;
217-
dist += index * (dz0 / 3.) * (1 / o2::math_utils::sqrt(o2::constants::math::TwoPI) / sigmaD) * exp(-z0 * z0 / 2. / sigmaD / sigmaD) * (1 / o2::math_utils::sqrt((z - z0) * (z - z0) + r * r));
218+
dist += index * (dz0 / 3.) * (1 / o2::math_utils::sqrt(o2::constants::math::TwoPI) / sigmaD) * std::exp(-z0 * z0 / 2. / sigmaD / sigmaD) * (1 / o2::math_utils::sqrt((z - z0) * (z - z0) + r * r));
218219
if (index != 4)
219220
index = 4;
220221
else
@@ -295,7 +296,7 @@ float FastTracker::ProbGoodChiSqHit(float radius, float searchRadiusRPhi, float
295296

296297
// function to provide a reconstructed track from a perfect input track
297298
// returns number of intercepts (generic for now)
298-
int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, float nch)
299+
int FastTracker::FastTrack(o2::track::TrackParCov inputTrack, o2::track::TrackParCov& outputTrack, const float nch)
299300
{
300301
hits.clear();
301302
nIntercepts = 0;

0 commit comments

Comments
 (0)