File indexing completed on 2026-05-23 08:12:14
0001 #pragma once
0002
0003 #include <fastjet/PseudoJet.hh>
0004 #include <vector>
0005 #include <map>
0006 #include <string>
0007 #include <stdexcept>
0008 #include <algorithm>
0009 #include <cmath>
0010 #include <format>
0011
0012 R__LOAD_LIBRARY(libVandyClasses.so)
0013
0014
0015
0016
0017
0018
0019
0020
0021 enum class Mode { kFull, kHalf, kData, kVtx };
0022
0023 inline std::string ModeLabel(Mode mode)
0024 {
0025 switch (mode) {
0026 case Mode::kFull: return "fullClosure";
0027 case Mode::kHalf: return "halfClosure";
0028 case Mode::kData: return "dataClosure";
0029 case Mode::kVtx: return "vtx";
0030 default: return "unknown";
0031 }
0032 }
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 const std::vector<double> recoLeadPtBins = { 15, 20, 30, 40, 50, 60, 80 };
0053
0054 const std::vector<double> recoSublPtBins = { 8, 15, 20, 30, 40, 50, 60, 80 };
0055
0056 const int nRecoLead = (int)recoLeadPtBins.size() - 1;
0057 const int nRecoSubl = (int)recoSublPtBins.size() - 1;
0058
0059
0060 const std::vector<double> trueLeadPtBins = { 15, 20, 30, 40, 50, 60, 80 };
0061 const std::vector<double> trueSublPtBins = { 8, 15, 20, 30, 40, 50, 60, 80 };
0062 const int nTrueLead = (int)trueLeadPtBins.size() - 1;
0063 const int nTrueSubl = (int)trueSublPtBins.size() - 1;
0064
0065
0066 const std::vector<double>& leadPtBins = recoLeadPtBins;
0067 const std::vector<double>& sublPtBins = recoSublPtBins;
0068 const int nLead = nRecoLead;
0069 const int nSubl = nRecoSubl;
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104 struct DijetPair { int iL, iS; };
0105
0106
0107
0108
0109 inline std::vector<DijetPair> MakeRecoPairs()
0110 {
0111 std::vector<DijetPair> v;
0112 for (int iL = 0; iL < nRecoLead; ++iL)
0113 for (int iS = 0; iS < nRecoSubl; ++iS)
0114 if (recoSublPtBins[iS] < recoLeadPtBins[iL+1])
0115 v.push_back({iL, iS});
0116 return v;
0117 }
0118 inline std::map<std::pair<int,int>,int> MakeRecoFlatMap(const std::vector<DijetPair>& pairs)
0119 {
0120 std::map<std::pair<int,int>,int> m;
0121 for (int f = 0; f < (int)pairs.size(); ++f)
0122 m[{pairs[f].iL, pairs[f].iS}] = f;
0123 return m;
0124 }
0125
0126
0127 inline std::vector<DijetPair> MakeTruePairs()
0128 {
0129 std::vector<DijetPair> v;
0130 for (int iL = 0; iL < nTrueLead; ++iL)
0131 for (int iS = 0; iS < nTrueSubl; ++iS)
0132 if (trueSublPtBins[iS] < trueLeadPtBins[iL+1])
0133 v.push_back({iL, iS});
0134 return v;
0135 }
0136 inline std::map<std::pair<int,int>,int> MakeTrueFlatMap(const std::vector<DijetPair>& pairs)
0137 {
0138 std::map<std::pair<int,int>,int> m;
0139 for (int f = 0; f < (int)pairs.size(); ++f)
0140 m[{pairs[f].iL, pairs[f].iS}] = f;
0141 return m;
0142 }
0143
0144
0145 inline const std::vector<DijetPair> gRecoPairs = MakeRecoPairs();
0146 inline const std::map<std::pair<int,int>,int> gRecoFlatMap = MakeRecoFlatMap(gRecoPairs);
0147 inline const std::vector<DijetPair> gTruePairs = MakeTruePairs();
0148 inline const std::map<std::pair<int,int>,int> gTrueFlatMap = MakeTrueFlatMap(gTruePairs);
0149
0150
0151
0152
0153 inline int nRecoFlat () { return (int)gRecoPairs.size(); }
0154 inline int nTrueFlat () { return (int)gTruePairs.size(); }
0155
0156
0157 inline int RecoFlatIndex(int iL, int iS)
0158 {
0159 auto it = gRecoFlatMap.find({iL, iS});
0160 return (it != gRecoFlatMap.end()) ? it->second : -1;
0161 }
0162 inline int TrueFlatIndex(int iL, int iS)
0163 {
0164 auto it = gTrueFlatMap.find({iL, iS});
0165 return (it != gTrueFlatMap.end()) ? it->second : -1;
0166 }
0167 inline void RecoFlatToIJ(int f, int& iL, int& iS)
0168 { iL = gRecoPairs[f].iL; iS = gRecoPairs[f].iS; }
0169 inline void TrueFlatToIJ(int f, int& iL, int& iS)
0170 { iL = gTruePairs[f].iL; iS = gTruePairs[f].iS; }
0171 inline double RecoFlatBinCenter(int f) { return f + 0.5; }
0172 inline double TrueFlatBinCenter(int f) { return f + 0.5; }
0173
0174
0175 inline int FlatIndex (int iL, int iS) { return RecoFlatIndex(iL, iS); }
0176 inline void FlatToIJ (int f, int& iL, int& iS) { RecoFlatToIJ(f, iL, iS); }
0177 inline double FlatBinCenter(int f) { return RecoFlatBinCenter(f); }
0178
0179 inline int nFlat() { return nRecoFlat(); }
0180
0181
0182
0183
0184 const std::vector<double> original_dPhiBins = {
0185 0.0000000, 0.041592654,
0186 0.14159265, 0.24159265, 0.34159265, 0.44159265, 0.54159265,
0187 0.64159265, 0.74159265, 0.84159265, 0.94159265, 1.0415927,
0188 1.1415927, 1.2415927, 1.3415927, 1.4415927, 1.5415927,
0189 1.6415927, 1.7415927, 1.8415927, 1.9415927, 2.0415927,
0190 2.1415927, 2.2415927, 2.3415927, 2.4415927, 2.5415927,
0191 2.6415927, 2.7415927, 2.8415927, 2.9415927, 3.0415927,
0192 3.1415927
0193 };
0194 const std::vector<double> new_dPhiBins = {
0195
0196 0.0000000, 0.14159265,
0197 0.34159265, 0.54159265, 0.74159265, 0.94159265,
0198 1.2415927, 1.5415927, 1.8415927, 2.1415927,
0199 2.3415927, 2.5415927, 2.7415927, 2.9415927,
0200 3.0415927, 3.1415927
0201 };
0202
0203
0204 const std::vector<double> dPhiBins = new_dPhiBins;
0205 const int nDphi = (int)dPhiBins.size() - 1;
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215 const int nPairWeight = 17;
0216 const double pairWeightMin = 0.0;
0217 const double pairWeightMax = 2.0;
0218 const double pairWeightLogMin = 5e-5;
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228 inline std::vector<double> MakePairWeightBins()
0229 {
0230 std::vector<double> edges(nPairWeight + 1);
0231
0232 edges[0] = 0.0;
0233
0234 const int nLogBins = nPairWeight-2;
0235 const double logMin = std::log10(pairWeightLogMin);
0236 const double logMax = std::log10(0.2);
0237 for (int i = 0; i <= nLogBins; ++i)
0238 edges[i + 1] = std::pow(10.0, logMin + (logMax - logMin) * i / nLogBins);
0239
0240 edges[nPairWeight] = pairWeightMax;
0241 return edges;
0242 }
0243 const std::vector<double> pairWeightBins = MakePairWeightBins();
0244
0245
0246
0247
0248
0249 static const std::map<int,double> xsec = {
0250 {12, 1.4903e+06},
0251 {20, 6.2623e+04},
0252 {30, 2.5298e+03},
0253 {40, 1.3553e+02},
0254 {50, 7.3113e+00},
0255 {60, 3.3261e-01}
0256 };
0257 inline double getSampleWeight(int jetSample)
0258 {
0259 return xsec.at(jetSample) / 9600000.0;
0260 }
0261
0262
0263
0264
0265 inline float get_jet_pTLow(int sample)
0266 {
0267 switch (sample) {
0268 case 5: return 7;
0269 case 12: return 14;
0270 case 20: return 21;
0271 case 30: return 32;
0272 case 40: return 42;
0273 case 50: return 52;
0274 case 60: return 62;
0275 default: throw std::invalid_argument("Invalid jet sample");
0276 }
0277 }
0278 inline float get_jet_pTHigh(int sample)
0279 {
0280 switch (sample) {
0281 case 5: return 14;
0282 case 12: return 21;
0283 case 20: return 32;
0284 case 30: return 42;
0285 case 40: return 52;
0286 case 50: return 62;
0287 case 60: return 1000;
0288 default: throw std::invalid_argument("Invalid jet sample");
0289 }
0290 }
0291
0292
0293
0294
0295 const double recoLeadMin = 20.0;
0296 const double recoSublMin = 8.0;
0297 const double trueLeadMin = 15.0;
0298 const double trueSublMin = 8.0;
0299
0300
0301
0302
0303
0304
0305
0306 const double geoMatchDR = 0.3;
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323 inline bool IsRecoAccessible(int iL, int iS)
0324 {
0325 return trueLeadPtBins[iL + 1] > 30 &&
0326 trueSublPtBins[iS + 1] > 15;
0327 }
0328
0329
0330
0331
0332 inline int FindBin(double val, const std::vector<double>& edges)
0333 {
0334 int bin = (int)(std::upper_bound(edges.begin(), edges.end(), val)
0335 - edges.begin()) - 1;
0336 return (bin >= 0 && bin < (int)edges.size() - 1) ? bin : -1;
0337 }
0338
0339
0340
0341
0342 inline double DeltaPhi(double phi1, double phi2)
0343 {
0344 double dphi = std::abs(phi1 - phi2);
0345 if (dphi > TMath::Pi()) dphi = 2.0 * TMath::Pi() - dphi;
0346 return dphi;
0347 }
0348
0349
0350
0351
0352 inline double DeltaR(double eta1, double phi1, double eta2, double phi2)
0353 {
0354 double deta = eta1 - eta2;
0355 double dphi = DeltaPhi(phi1, phi2);
0356 return std::sqrt(deta*deta + dphi*dphi);
0357 }
0358
0359
0360
0361
0362 inline bool GetGeoMatch(
0363 std::vector<JetInfo>& recoJets,
0364 std::vector<JetInfo>& truthJets,
0365 double rLeadPT, double rSublPT,
0366 double tLeadPT, double tSublPT)
0367 {
0368
0369
0370
0371 const double pTtol = 0.01;
0372
0373 JetInfo* rLead = nullptr;
0374 JetInfo* rSubl = nullptr;
0375 JetInfo* tLead = nullptr;
0376 JetInfo* tSubl = nullptr;
0377
0378 for (auto& j : recoJets) {
0379 if (!rLead && std::abs(j.pt() - rLeadPT) < pTtol) rLead = &j;
0380 else if (!rSubl && std::abs(j.pt() - rSublPT) < pTtol) rSubl = &j;
0381 }
0382 for (auto& j : truthJets) {
0383 if (!tLead && std::abs(j.pt() - tLeadPT) < pTtol) tLead = &j;
0384 else if (!tSubl && std::abs(j.pt() - tSublPT) < pTtol) tSubl = &j;
0385 }
0386
0387
0388 if (!rLead || !rSubl || !tLead || !tSubl) return false;
0389
0390 fastjet::PseudoJet rL(rLead->px(), rLead->py(), rLead->pz(), rLead->e());
0391 fastjet::PseudoJet rS(rSubl->px(), rSubl->py(), rSubl->pz(), rSubl->e());
0392 fastjet::PseudoJet tL(tLead->px(), tLead->py(), tLead->pz(), tLead->e());
0393 fastjet::PseudoJet tS(tSubl->px(), tSubl->py(), tSubl->pz(), tSubl->e());
0394
0395 return DeltaR(rL.pseudorapidity(), rL.phi_std(),
0396 tL.pseudorapidity(), tL.phi_std()) < geoMatchDR &&
0397 DeltaR(rS.pseudorapidity(), rS.phi_std(),
0398 tS.pseudorapidity(), tS.phi_std()) < geoMatchDR;
0399 }
0400
0401
0402
0403
0404 inline std::string SimFilePath(int jetSample, int seg)
0405 {
0406 return std::format(
0407 "/sphenix/tg/tg01/jets/sgross/VandyDSTs/Jet{0}/"
0408 "VandyDSTs_run2pp_ana521_2025p007_v001_Jet{0}-28-{1:06d}_to-{2:06d}.root",
0409 jetSample, seg, seg + 24);
0410 }
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421 const std::vector<double> etaEdges = {
0422 -1.1000000, -1.0083333, -0.91666667, -0.82500000, -0.73333333,
0423 -0.64166667, -0.55000000, -0.45833333, -0.36666667, -0.27500000,
0424 -0.18333333, -0.091666667, 1.1102230e-16, 0.091666667, 0.18333333,
0425 0.27500000, 0.36666667, 0.45833333, 0.55000000, 0.64166667,
0426 0.73333333, 0.82500000, 0.91666667, 1.0083333, 1.1000000 };
0427
0428 const std::vector<double> phiEdges = {
0429 -0.053619781, 0.044554989, 0.14272976, 0.24090453, 0.33907930,
0430 0.43725407, 0.53542884, 0.63360361, 0.73177838, 0.82995315,
0431 0.92812792, 1.0263027, 1.1244775, 1.2226522, 1.3208270,
0432 1.4190018, 1.5171765, 1.6153513, 1.7135261, 1.8117009,
0433 1.9098756, 2.0080504, 2.1062252, 2.2043999, 2.3025747,
0434 2.4007495, 2.4989242, 2.5970990, 2.6952738, 2.7934486,
0435 2.8916233, 2.9897981, 3.0879729, 3.1861476, 3.2843224,
0436 3.3824972, 3.4806720, 3.5788467, 3.6770215, 3.7751963,
0437 3.8733710, 3.9715458, 4.0697206, 4.1678953, 4.2660701,
0438 4.3642449, 4.4624197, 4.5605944, 4.6587692, 4.7569440,
0439 4.8551187, 4.9532935, 5.0514683, 5.1496431, 5.2478178,
0440 5.3459926, 5.4441674, 5.5423421, 5.6405169, 5.7386917,
0441 5.8368664, 5.9350412, 6.0332160, 6.1313908, 6.2295655 };
0442
0443 std::vector<double> shiftedEtaEdges;
0444 const double R = 124.5;
0445
0446 void shiftEtaEdges(double vtx)
0447 {
0448 shiftedEtaEdges.clear();
0449 for (auto edge : etaEdges) {
0450 double z = R * sinh(edge);
0451 shiftedEtaEdges.push_back(asinh((z - vtx) / R));
0452 }
0453 }
0454
0455 double getEtaCenter(int etaBin, double vtx)
0456 {
0457 if (vtx != 0.0)
0458 return 0.5 * (shiftedEtaEdges[etaBin] + shiftedEtaEdges[etaBin+1]);
0459 return 0.5 * (etaEdges[etaBin] + etaEdges[etaBin+1]);
0460 }
0461
0462 double getPhiCenter(int phiBin)
0463 {
0464 return 0.5 * (phiEdges[phiBin] + phiEdges[phiBin+1]);
0465 }
0466
0467 int getEtaBin(double eta, double vtx)
0468 {
0469 const std::vector<double>& edges = (vtx != 0) ? shiftedEtaEdges : etaEdges;
0470 return FindBin(eta, edges);
0471 }
0472
0473 int getPhiBin(double phi)
0474 {
0475 while (phi < phiEdges.front()) phi += 2 * TMath::Pi();
0476 while (phi > phiEdges.back()) phi -= 2 * TMath::Pi();
0477 return FindBin(phi, phiEdges);
0478 }
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490 const int nFlat2D = nDphi * nPairWeight;
0491
0492 inline int Flat2DIndex(int iDphi, int iPw) { return iDphi * nPairWeight + iPw; }
0493 inline void Flat2DToIJ (int iF2D, int& iDphi, int& iPw)
0494 { iDphi = iF2D / nPairWeight; iPw = iF2D % nPairWeight; }
0495 inline double Flat2DBinCenter(int iF2D) { return iF2D + 0.5; }
0496
0497
0498
0499 inline TH2D* Flat1DToTH2D(TH1D* h1D, const char* name, const char* title = "")
0500 {
0501 TH2D* h2D = new TH2D(name, title,
0502 nDphi, dPhiBins.data(),
0503 nPairWeight, pairWeightBins.data());
0504 h2D->Sumw2();
0505 for (int iF2D = 0; iF2D < nFlat2D; ++iF2D) {
0506 int iDphi, iPw; Flat2DToIJ(iF2D, iDphi, iPw);
0507 h2D->SetBinContent(iDphi+1, iPw+1, h1D->GetBinContent(iF2D+1));
0508 h2D->SetBinError (iDphi+1, iPw+1, h1D->GetBinError (iF2D+1));
0509 }
0510 return h2D;
0511 }
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526
0527
0528
0529 inline int nRecoFlat3D() { return nRecoFlat() * nPairWeight; }
0530 inline int nTrueFlat3D() { return nTrueFlat() * nPairWeight; }
0531
0532
0533 inline int RecoFlat3DIndex(int iL, int iS, int iPw)
0534 {
0535 int f2 = RecoFlatIndex(iL, iS);
0536 return (f2 >= 0) ? f2 * nPairWeight + iPw : -1;
0537 }
0538 inline void RecoFlat3DToIJK(int iF, int& iL, int& iS, int& iPw)
0539 {
0540 int f2 = iF / nPairWeight;
0541 iPw = iF % nPairWeight;
0542 RecoFlatToIJ(f2, iL, iS);
0543 }
0544 inline double RecoFlat3DBinCenter(int iF) { return iF + 0.5; }
0545
0546
0547 inline int TrueFlat3DIndex(int iL, int iS, int iPw)
0548 {
0549 int f2 = TrueFlatIndex(iL, iS);
0550 return (f2 >= 0) ? f2 * nPairWeight + iPw : -1;
0551 }
0552 inline void TrueFlat3DToIJK(int iF, int& iL, int& iS, int& iPw)
0553 {
0554 int f2 = iF / nPairWeight;
0555 iPw = iF % nPairWeight;
0556 TrueFlatToIJ(f2, iL, iS);
0557 }
0558 inline double TrueFlat3DBinCenter(int iF) { return iF + 0.5; }
0559
0560
0561
0562
0563
0564 inline void ProjectWEEC3DSlice(TH1D* h1D, double& val, double& err)
0565 {
0566 double sum = 0.0, sumw2 = 0.0;
0567 for (int ft = 0; ft < nTrueFlat(); ++ft) {
0568 int iL, iS; TrueFlatToIJ(ft, iL, iS);
0569 if (!IsRecoAccessible(iL, iS)) continue;
0570 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0571 int iF = ft * nPairWeight + iPw;
0572 double wCen = 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0573 double v = h1D->GetBinContent(iF + 1);
0574 double e = h1D->GetBinError (iF + 1);
0575 sum += wCen * v;
0576 sumw2 += wCen * wCen * e * e;
0577 }
0578 }
0579 val = sum;
0580 err = std::sqrt(sumw2);
0581 }
0582
0583
0584
0585
0586
0587 inline void ProjectWEEC3DSliceForBin(TH1D* h1D, int iL, int iS,
0588 double& val, double& err)
0589 {
0590 val = 0; err = 0;
0591 int ft = TrueFlatIndex(iL, iS);
0592 if (ft < 0) return;
0593 double sum = 0.0, sumw2 = 0.0;
0594 int iF0 = ft * nPairWeight;
0595 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0596 double wCen = 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0597 double v = h1D->GetBinContent(iF0 + iPw + 1);
0598 double e = h1D->GetBinError (iF0 + iPw + 1);
0599 sum += wCen * v;
0600 sumw2 += wCen * wCen * e * e;
0601 }
0602 val = sum;
0603 err = std::sqrt(sumw2);
0604 }
0605
0606
0607
0608
0609
0610
0611
0612 inline void ProjectWEEC3DSlice(TH1D* h1D, double& val, double& err,
0613 TH1D* hPWNum, TH1D* hPWDen)
0614 {
0615 double sum = 0.0, sumw2 = 0.0;
0616 for (int ft = 0; ft < nTrueFlat(); ++ft) {
0617 int iL, iS; TrueFlatToIJ(ft, iL, iS);
0618 if (!IsRecoAccessible(iL, iS)) continue;
0619 int iF0 = ft * nPairWeight;
0620 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0621 int iF = iF0 + iPw;
0622 double den = hPWDen ? hPWDen->GetBinContent(iF + 1) : 0.0;
0623 double wMean = (den > 0)
0624 ? hPWNum->GetBinContent(iF + 1) / den
0625 : 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0626 double v = h1D->GetBinContent(iF + 1);
0627 double e = h1D->GetBinError (iF + 1);
0628 sum += wMean * v;
0629 sumw2 += wMean * wMean * e * e;
0630 }
0631 }
0632 val = sum;
0633 err = std::sqrt(sumw2);
0634 }
0635
0636 inline void ProjectWEEC3DSliceForBin(TH1D* h1D, int iL, int iS,
0637 double& val, double& err,
0638 TH1D* hPWNum, TH1D* hPWDen)
0639 {
0640 val = 0; err = 0;
0641 int ft = TrueFlatIndex(iL, iS);
0642 if (ft < 0) return;
0643 double sum = 0.0, sumw2 = 0.0;
0644 int iF0 = ft * nPairWeight;
0645 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0646 int iF = iF0 + iPw;
0647 double den = hPWDen ? hPWDen->GetBinContent(iF + 1) : 0.0;
0648 double wMean = (den > 0)
0649 ? hPWNum->GetBinContent(iF + 1) / den
0650 : 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0651 double v = h1D->GetBinContent(iF + 1);
0652 double e = h1D->GetBinError (iF + 1);
0653 sum += wMean * v;
0654 sumw2 += wMean * wMean * e * e;
0655 }
0656 val = sum;
0657 err = std::sqrt(sumw2);
0658 }
0659
0660
0661
0662
0663
0664
0665
0666
0667
0668
0669
0670
0671 inline void ProjectWEEC3DSlice(TH1D* h1D, double& val, double& err,
0672 const TMatrixD* cov)
0673 {
0674 double sum = 0.0, var = 0.0;
0675
0676 std::vector<std::pair<int,double>> bins;
0677 for (int ft = 0; ft < nTrueFlat(); ++ft) {
0678 int iL, iS; TrueFlatToIJ(ft, iL, iS);
0679 if (!IsRecoAccessible(iL, iS)) continue;
0680 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0681 int iF = ft * nPairWeight + iPw;
0682 double wCen = 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0683 sum += wCen * h1D->GetBinContent(iF + 1);
0684 bins.push_back({iF, wCen});
0685 }
0686 }
0687 if (cov) {
0688 for (auto [i, wi] : bins)
0689 for (auto [j, wj] : bins)
0690 var += wi * wj * (*cov)(i, j);
0691 } else {
0692 for (auto [i, wi] : bins) {
0693 double e = h1D->GetBinError(i + 1);
0694 var += wi * wi * e * e;
0695 }
0696 }
0697 val = sum;
0698 err = std::sqrt(std::max(var, 0.0));
0699 }
0700
0701 inline void ProjectWEEC3DSliceForBin(TH1D* h1D, int iL, int iS,
0702 double& val, double& err,
0703 const TMatrixD* cov)
0704 {
0705 val = 0; err = 0;
0706 int ft = TrueFlatIndex(iL, iS);
0707 if (ft < 0) return;
0708 double sum = 0.0, var = 0.0;
0709 int iF0 = ft * nPairWeight;
0710 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0711 int iF = iF0 + iPw;
0712 double wCen = 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0713 sum += wCen * h1D->GetBinContent(iF + 1);
0714 }
0715 if (cov) {
0716 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0717 int iF = iF0 + iPw;
0718 double wi = 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0719 for (int jPw = 0; jPw < nPairWeight; ++jPw) {
0720 int jF = iF0 + jPw;
0721 double wj = 0.5 * (pairWeightBins[jPw] + pairWeightBins[jPw+1]);
0722 var += wi * wj * (*cov)(iF, jF);
0723 }
0724 }
0725 } else {
0726 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0727 int iF = iF0 + iPw;
0728 double wCen = 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0729 double e = h1D->GetBinError(iF + 1);
0730 var += wCen * wCen * e * e;
0731 }
0732 }
0733 val = sum;
0734 err = std::sqrt(std::max(var, 0.0));
0735 }
0736
0737
0738 inline void ProjectWEEC3DSlice(TH1D* h1D, double& val, double& err,
0739 TH1D* hPWNum, TH1D* hPWDen,
0740 const TMatrixD* cov)
0741 {
0742 double sum = 0.0, var = 0.0;
0743 std::vector<std::pair<int,double>> bins;
0744 for (int ft = 0; ft < nTrueFlat(); ++ft) {
0745 int iL, iS; TrueFlatToIJ(ft, iL, iS);
0746 if (!IsRecoAccessible(iL, iS)) continue;
0747 int iF0 = ft * nPairWeight;
0748 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0749 int iF = iF0 + iPw;
0750 double den = hPWDen ? hPWDen->GetBinContent(iF + 1) : 0.0;
0751 double w = (den > 0)
0752 ? hPWNum->GetBinContent(iF + 1) / den
0753 : 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0754 sum += w * h1D->GetBinContent(iF + 1);
0755 bins.push_back({iF, w});
0756 }
0757 }
0758 if (cov) {
0759 for (auto [i, wi] : bins)
0760 for (auto [j, wj] : bins)
0761 var += wi * wj * (*cov)(i, j);
0762 } else {
0763 for (auto [i, wi] : bins) {
0764 double e = h1D->GetBinError(i + 1);
0765 var += wi * wi * e * e;
0766 }
0767 }
0768 val = sum;
0769 err = std::sqrt(std::max(var, 0.0));
0770 }
0771
0772 inline void ProjectWEEC3DSliceForBin(TH1D* h1D, int iL, int iS,
0773 double& val, double& err,
0774 TH1D* hPWNum, TH1D* hPWDen,
0775 const TMatrixD* cov)
0776 {
0777 val = 0; err = 0;
0778 int ft = TrueFlatIndex(iL, iS);
0779 if (ft < 0) return;
0780 double sum = 0.0, var = 0.0;
0781 int iF0 = ft * nPairWeight;
0782
0783 std::vector<double> ws(nPairWeight);
0784 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0785 int iF = iF0 + iPw;
0786 double den = hPWDen ? hPWDen->GetBinContent(iF + 1) : 0.0;
0787 ws[iPw] = (den > 0)
0788 ? hPWNum->GetBinContent(iF + 1) / den
0789 : 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0790 sum += ws[iPw] * h1D->GetBinContent(iF + 1);
0791 }
0792 if (cov) {
0793 for (int iPw = 0; iPw < nPairWeight; ++iPw)
0794 for (int jPw = 0; jPw < nPairWeight; ++jPw)
0795 var += ws[iPw] * ws[jPw] * (*cov)(iF0 + iPw, iF0 + jPw);
0796 } else {
0797 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0798 double e = h1D->GetBinError(iF0 + iPw + 1);
0799 var += ws[iPw] * ws[iPw] * e * e;
0800 }
0801 }
0802 val = sum;
0803 err = std::sqrt(std::max(var, 0.0));
0804 }
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815 inline TH1D* ProjectWEEC(TH1D* h1D, const char* name)
0816 {
0817 TH1D* hProj = new TH1D(name, ";#Delta#phi;wEEC",
0818 nDphi, dPhiBins.data());
0819 hProj->Sumw2();
0820 for (int iDphi = 0; iDphi < nDphi; ++iDphi) {
0821 double sum = 0.0;
0822 double sumw2 = 0.0;
0823 for (int iPw = 0; iPw < nPairWeight; ++iPw) {
0824 int iF2D = Flat2DIndex(iDphi, iPw);
0825 double wCen = 0.5 * (pairWeightBins[iPw] + pairWeightBins[iPw+1]);
0826 double val = h1D->GetBinContent(iF2D + 1);
0827 double err = h1D->GetBinError (iF2D + 1);
0828 sum += wCen * val;
0829 sumw2 += wCen * wCen * err * err;
0830 }
0831 hProj->SetBinContent(iDphi + 1, sum);
0832 hProj->SetBinError (iDphi + 1, std::sqrt(sumw2));
0833 }
0834 return hProj;
0835 }
0836
0837
0838
0839 inline bool NormalizeWEEC(TH1D* h)
0840 {
0841 double integral = h->Integral();
0842 if (integral <= 0) return false;
0843 h->Scale(1.0 / integral);
0844 h->Scale(1.0, "width");
0845 return true;
0846 }
0847
0848
0849
0850
0851
0852
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865 constexpr double vtxZMin = -10.0;
0866 constexpr double vtxZMax = 10.0;
0867 constexpr int nVtxBins = 20;
0868 constexpr double vtxBinWidth = (vtxZMax - vtxZMin) / nVtxBins;
0869
0870
0871
0872
0873 constexpr double vtxWeights[nVtxBins] = {
0874 0.962696,
0875 0.987321,
0876 1.006085,
0877 1.020161,
0878 1.034171,
0879 1.037306,
0880 1.046184,
0881 1.040758,
0882 1.041977,
0883 1.042028,
0884 1.027416,
0885 1.030098,
0886 1.012770,
0887 1.012976,
0888 0.996425,
0889 0.975807,
0890 0.966945,
0891 0.944144,
0892 0.921764,
0893 0.888391,
0894 };
0895
0896
0897
0898
0899 inline double GetVtxWeight(double vtx_z)
0900 {
0901 if (vtx_z < vtxZMin || vtx_z >= vtxZMax) return 0.0;
0902 int bin = static_cast<int>((vtx_z - vtxZMin) / vtxBinWidth);
0903 if (bin < 0 || bin >= nVtxBins) return 0.0;
0904 return vtxWeights[bin];
0905 }