Belle II Software light-2609-luna
FEIVariables.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9// Own header.
10#include <analysis/variables/FEIVariables.h>
11
12// include VariableManager
13#include <analysis/VariableManager/Manager.h>
14
15#include <analysis/dataobjects/Particle.h>
16#include <analysis/dataobjects/ParticleList.h>
17#include <analysis/utility/PCmsLabTransform.h>
18#include <framework/gearbox/Const.h>
19#include <mdst/dataobjects/MCParticle.h>
20#include <framework/datastore/StoreArray.h>
21#include <framework/datastore/StoreObjPtr.h>
22#include <map>
23#include <algorithm>
24#include <iterator>
25
26namespace Belle2 {
31 namespace Variable {
32
33 int mostcommonBTagIndex(const Particle* part)
34 {
35 std::map <int, int> tag_candidates;
36 const std::vector<const Particle*>& fsp_tag = part->getFinalStateDaughters();
37 for (const Particle* fsp : fsp_tag) {
38 const MCParticle* mc_fsp = fsp->getMCParticle();
39 if (mc_fsp) {
40 int tag_index = finddescendant(mc_fsp);
41 if (tag_candidates.find(tag_index) == tag_candidates.end()) {
42 tag_candidates[tag_index] = 1;
43 } else {
44 tag_candidates[tag_index]++;
45 }
46 }
47 }
48 int tag_index = -1;
49 int tag_N = 0;
50 for (const auto& [key, value] : tag_candidates) {
51 if (value > tag_N) {
52 tag_index = key;
53 tag_N = value;
54 }
55 }
56 return tag_index;
57 }
58 int finddescendant(const MCParticle* mcpart)
59 {
60 const MCParticle* i_mcpart = mcpart;
61 while (i_mcpart) {
62 const auto* i_mcpart_mother = i_mcpart->getMother();
63 if (i_mcpart_mother) {
64 constexpr std::array<int, 2> B_PDG = {511, 521};
65 auto result = std::find(B_PDG.begin(), B_PDG.end(), abs(i_mcpart_mother->getPDG()));
66 if (result != B_PDG.end()) {
67 return i_mcpart_mother->getArrayIndex();
68 }
69 i_mcpart = i_mcpart_mother;
70 } else {
71 return -1;
72 }
73 }
74 return -2;
75 }
76 std::vector<int> truthFSPTag(int BTag_index)
77 {
78 StoreArray<MCParticle> MC_Particle_list;
79 std::vector<int> fsp_truth_index;
80 for (const MCParticle& iMCParticle : MC_Particle_list) {
81 if ((BTag_index == finddescendant(&iMCParticle)) && (iMCParticle.hasStatus(MCParticle::c_StableInGenerator) == true)
82 && (iMCParticle.hasStatus(MCParticle::c_IsISRPhoton) == false) && iMCParticle.hasStatus(MCParticle::c_IsFSRPhoton) == false
83 && (iMCParticle.hasStatus(MCParticle::c_IsPHOTOSPhoton) == false)) {
84 fsp_truth_index.push_back(iMCParticle.getArrayIndex());
85 }
86 }
87 return fsp_truth_index;
88 }
89 double percentageMissingParticlesBTag(const Particle* part)
90 {
91 int index = mostcommonBTagIndex(part);
92 if (index == -1) {
93 return -1;
94 } else {
95 std::vector<int> fsp_FEI_index;
96 const std::vector<const Particle*>& fsp_tag = part->getFinalStateDaughters();
97 for (const Particle* fsp : fsp_tag) {
98 const MCParticle* mc_fsp = fsp->getMCParticle();
99 if (mc_fsp) {
100 int tag_index = finddescendant(mc_fsp);
101 if (tag_index == index) {
102 fsp_FEI_index.push_back(mc_fsp->getArrayIndex());
103 }
104 }
105 }
106 std::vector<int> diff;
107 std::vector<int> fsp_truth_index = truthFSPTag(index);
108 std::sort(fsp_truth_index.begin(), fsp_truth_index.end());
109 std::sort(fsp_FEI_index.begin(), fsp_FEI_index.end());
110 std::set_difference(fsp_truth_index.begin(), fsp_truth_index.end(), fsp_FEI_index.begin(), fsp_FEI_index.end(), std::inserter(diff,
111 diff.begin()));
112 return double(diff.size()) / double(fsp_truth_index.size());
113 }
114 }
115 double percentageWrongParticlesBTag(const Particle* part)
116 {
117 int index = mostcommonBTagIndex(part);
118 if (index == -1) {
119 return -1;
120 } else {
121 const std::vector<const Particle*>& fsp_tag = part->getFinalStateDaughters();
122 int wrong_FEI = 0;
123 for (const Particle* fsp : fsp_tag) {
124 const MCParticle* mc_fsp = fsp->getMCParticle();
125 if (mc_fsp) {
126 int tag_index = finddescendant(mc_fsp);
127 if (tag_index != index) {
128 wrong_FEI ++;
129 }
130 }
131 }
132 return double(wrong_FEI) / double(truthFSPTag(index).size());
133 }
134 }
135 double mostcommonBTagDeltaP(const Particle* part)
136 {
137 int idx = mostcommonBTagIndex(part);
138 if (idx < 0) return Const::doubleNaN;
139
140 StoreArray<MCParticle> mcParticles;
141 PCmsLabTransform T;
142 ROOT::Math::XYZVector recoP3 = (T.rotateLabToCms() * part->get4Vector()).Vect();
143 ROOT::Math::XYZVector genP3 = (T.rotateLabToCms() * mcParticles[idx]->get4Vector()).Vect();
144 return (recoP3 - genP3).R();
145 }
146
147 double mostcommonBTagPDG(const Particle* part)
148 {
149 int idx = mostcommonBTagIndex(part);
150 if (idx < 0) return Const::doubleNaN;
151
152 StoreArray<MCParticle> mcParticles;
153 return mcParticles[idx]->getPDG();
154 }
155
156 Manager::FunctionPtr sigProbRank(const std::vector<std::string>& arguments)
157 {
158 if (arguments.size() != 2) {
159 B2FATAL("sigProbRank requires exactly 2 arguments: bp_list and b0_list. "
160 "Received " << arguments.size() << " arguments.");
161 }
162
163 std::string bpListName = arguments[0];
164 std::string b0ListName = arguments[1];
165
166 auto func = [bpListName, b0ListName](const Particle * particle) -> int {
167 StoreObjPtr<ParticleList> bpList(bpListName);
168 StoreObjPtr<ParticleList> b0List(b0ListName);
169
170 if (!bpList.isValid() && !b0List.isValid())
171 B2FATAL("sigProbRank could not find either input list: bp_list='" << bpListName
172 << "', b0_list='" << b0ListName << "'");
173 if (!bpList.isValid())
174 B2FATAL("sigProbRank could not find the required bp_list: '" << bpListName << "'");
175 if (!b0List.isValid())
176 B2FATAL("sigProbRank could not find the required b0_list: '" << b0ListName << "'");
177
178 struct RankedCandidate {
179 double signalProbability;
180 const Particle* particle;
181 };
182
183 auto collectCandidates = [](const StoreObjPtr<ParticleList>& list,
184 const std::string & listLabel,
185 std::vector<RankedCandidate>& rankedCandidates)
186 {
187 for (unsigned int i = 0; i < list->getListSize(); ++i) {
188 const Particle* p = list->getParticle(i);
189 if (!p->hasExtraInfo("SignalProbability")) {
190 B2FATAL("sigProbRank requires every candidate in " << listLabel
191 << " to provide extraInfo('SignalProbability')");
192 }
193 rankedCandidates.push_back({p->getExtraInfo("SignalProbability"), p});
194 }
195 };
196
197 std::vector<RankedCandidate> rankedCandidates;
198 rankedCandidates.reserve(bpList->getListSize() + b0List->getListSize());
199 collectCandidates(bpList, bpListName, rankedCandidates);
200 collectCandidates(b0List, b0ListName, rankedCandidates);
201
202 std::stable_sort(rankedCandidates.begin(), rankedCandidates.end(),
203 [](const RankedCandidate & lhs, const RankedCandidate & rhs)
204 {
205 return lhs.signalProbability > rhs.signalProbability;
206 });
207
208 // Check if particle is a copy made by ParticleCopy::copyParticle
209 // (e.g. from setBeamConstrainedMomentum); copies store the original's
210 // array index in extraInfo("original_index")
211 int originalIndex = -1;
212 if (particle->hasExtraInfo("original_index"))
213 originalIndex = static_cast<int>(particle->getExtraInfo("original_index"));
214
215 for (unsigned int i = 0; i < rankedCandidates.size(); ++i)
216 {
217 const Particle* cand = rankedCandidates[i].particle;
218 if (cand == particle) {
219 return static_cast<int>(i) + 1;
220 }
221 if (originalIndex >= 0 && cand->getArrayIndex() == originalIndex) {
222 return static_cast<int>(i) + 1;
223 }
224 }
225
226 B2FATAL("sigProbRank: particle not found in the input lists: "
227 "bp_list='" << bpListName << "', b0_list='" << b0ListName << "'");
228 return -1;
229 };
230 return func;
231 }
232
233 VARIABLE_GROUP("FEIVariables");
234 REGISTER_VARIABLE("mostcommonBTagIndex", mostcommonBTagIndex, R"DOC(
235Returns the generator-level index of the :math:`B` meson candidate which is assigned the most reconstructed particles. Returns -1
236if no :math:`B` meson on the generator level is found.
237
238)DOC");
239 REGISTER_VARIABLE("percentageMissingParticlesBTag", percentageMissingParticlesBTag, R"DOC(
240Returns the percentage of missing particles calculated by the number of particles not reconstructed by the FEI divided by the number
241of generated particles. The latter is determined by using the generator-level index corresponding to the :math:`B` meson returned by
242``mostcommonBTagIndex``. Returns -1 if no :math:`B` meson on the generator level is found.
243
244)DOC");
245 REGISTER_VARIABLE("percentageWrongParticlesBTag", percentageWrongParticlesBTag, R"DOC(
246Returns the percentage of wrong particles calculated by the number of reconstructed particles originating from the other :math:`B` meson divided by the total
247number of generated final-state particles. The latter is determined by using the generator-level index corresponding to the :math:`B` meson returned by
248``mostcommonBTagIndex``. Returns -1 if no :math:`B` meson on the generator level is found.
249
250)DOC");
251 REGISTER_VARIABLE("mostcommonBTagDeltaP", mostcommonBTagDeltaP, R"DOC(
252Returns the magnitude of the 3-momentum difference in the CM frame between the reconstructed particles and the generated :math:`B` meson identified using
253``mostcommonBTagIndex``. Returns ``NaN`` if no :math:`B` meson on the generator level is found.
254
255)DOC", "GeV/c");
256 REGISTER_VARIABLE("mostcommonBTagPDG", mostcommonBTagPDG, R"DOC(
257Returns the PDG code of the generated :math:`B` meson identified using ``mostcommonBTagIndex``. Returns ``NaN`` if no :math:`B` meson on the generator level is found.
258
259.. note:: This is equivalent to ``genParticle(mostcommonBTagIndex, PDG)``.
260
261)DOC");
262 REGISTER_METAVARIABLE("sigProbRank(bp_list, b0_list)", sigProbRank, R"DOC(
263Returns the rank (starting at 1) of the given candidate when all candidates from the :math:`B^+` (``bp_list``) and :math:`B^0` (``b0_list``) particle lists
264are ordered together by descening signal probability.
265
266.. note:: The signal probability can be accessed using ``extraInfo(SignalProbability)``.
267
268)DOC", Manager::VariableDataType::c_int);
269 }
271}
static const double doubleNaN
quiet_NaN
Definition Const.h:704
@ c_IsFSRPhoton
bit 7: Particle is from final state radiation
Definition MCParticle.h:61
@ c_IsPHOTOSPhoton
bit 8: Particle is an radiative photon from PHOTOS
Definition MCParticle.h:63
@ c_StableInGenerator
bit 1: Particle is stable, i.e., not decaying in the generator.
Definition MCParticle.h:49
@ c_IsISRPhoton
bit 6: Particle is from initial state radiation
Definition MCParticle.h:59
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
Definition Manager.h:112
Abstract base class for different kinds of events.