|
| 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 | +} |
0 commit comments