Belle II Software prerelease-11-00-00a
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 // cppcheck-suppress unassignedVariable
51 for (const auto& [key, value] : tag_candidates) {
52 if (value > tag_N) {
53 tag_index = key;
54 tag_N = value;
55 }
56 }
57 return tag_index;
58 }
59 int finddescendant(const MCParticle* mcpart)
60 {
61 const MCParticle* i_mcpart = mcpart;
62 while (i_mcpart) {
63 auto* i_mcpart_mother = i_mcpart->getMother();
64 if (i_mcpart_mother) {
65 constexpr std::array<int, 2> B_PDG = {511, 521};
66 auto result = std::find(B_PDG.begin(), B_PDG.end(), abs(i_mcpart_mother->getPDG()));
67 if (result != B_PDG.end()) {
68 return i_mcpart_mother->getArrayIndex();
69 }
70 i_mcpart = i_mcpart_mother;
71 } else {
72 return -1;
73 }
74 }
75 return -2;
76 }
77 std::vector<int> truthFSPTag(int BTag_index)
78 {
79 StoreArray<MCParticle> MC_Particle_list;
80 std::vector<int> fsp_truth_index;
81 for (const MCParticle& iMCParticle : MC_Particle_list) {
82 if ((BTag_index == finddescendant(&iMCParticle)) && (iMCParticle.hasStatus(MCParticle::c_StableInGenerator) == true)
83 && (iMCParticle.hasStatus(MCParticle::c_IsISRPhoton) == false) && iMCParticle.hasStatus(MCParticle::c_IsFSRPhoton) == false
84 && (iMCParticle.hasStatus(MCParticle::c_IsPHOTOSPhoton) == false)) {
85 fsp_truth_index.push_back(iMCParticle.getArrayIndex());
86 }
87 }
88 return fsp_truth_index;
89 }
90 double percentageMissingParticlesBTag(const Particle* part)
91 {
92 int index = mostcommonBTagIndex(part);
93 if (index == -1) {
94 return -1;
95 } else {
96 std::vector<int> fsp_FEI_index;
97 const std::vector<const Particle*>& fsp_tag = part->getFinalStateDaughters();
98 for (const Particle* fsp : fsp_tag) {
99 const MCParticle* mc_fsp = fsp->getMCParticle();
100 if (mc_fsp) {
101 int tag_index = finddescendant(mc_fsp);
102 if (tag_index == index) {
103 fsp_FEI_index.push_back(mc_fsp->getArrayIndex());
104 }
105 }
106 }
107 std::vector<int> diff;
108 std::vector<int> fsp_truth_index = truthFSPTag(index);
109 std::sort(fsp_truth_index.begin(), fsp_truth_index.end());
110 std::sort(fsp_FEI_index.begin(), fsp_FEI_index.end());
111 std::set_difference(fsp_truth_index.begin(), fsp_truth_index.end(), fsp_FEI_index.begin(), fsp_FEI_index.end(), std::inserter(diff,
112 diff.begin()));
113 return double(diff.size()) / double(fsp_truth_index.size());
114 }
115 }
116 double percentageWrongParticlesBTag(const Particle* part)
117 {
118 int index = mostcommonBTagIndex(part);
119 if (index == -1) {
120 return -1;
121 } else {
122 const std::vector<const Particle*>& fsp_tag = part->getFinalStateDaughters();
123 int wrong_FEI = 0;
124 for (const Particle* fsp : fsp_tag) {
125 const MCParticle* mc_fsp = fsp->getMCParticle();
126 if (mc_fsp) {
127 int tag_index = finddescendant(mc_fsp);
128 if (tag_index != index) {
129 wrong_FEI ++;
130 }
131 }
132 }
133 return double(wrong_FEI) / double(truthFSPTag(index).size());
134 }
135 }
136 double mostcommonBTagDeltaP(const Particle* part)
137 {
138 int idx = mostcommonBTagIndex(part);
139 if (idx < 0) return Const::doubleNaN;
140
141 StoreArray<MCParticle> mcParticles;
142 PCmsLabTransform T;
143 ROOT::Math::XYZVector recoP3 = (T.rotateLabToCms() * part->get4Vector()).Vect();
144 ROOT::Math::XYZVector genP3 = (T.rotateLabToCms() * mcParticles[idx]->get4Vector()).Vect();
145 return (recoP3 - genP3).R();
146 }
147
148 double mostcommonBTagPDG(const Particle* part)
149 {
150 int idx = mostcommonBTagIndex(part);
151 if (idx < 0) return Const::doubleNaN;
152
153 StoreArray<MCParticle> mcParticles;
154 return mcParticles[idx]->getPDG();
155 }
156
157 Manager::FunctionPtr sigProbRank(const std::vector<std::string>& arguments)
158 {
159 if (arguments.size() != 2) {
160 B2FATAL("sigProbRank requires exactly 2 arguments: bp_list and b0_list. "
161 "Received " << arguments.size() << " arguments.");
162 }
163
164 std::string bpListName = arguments[0];
165 std::string b0ListName = arguments[1];
166
167 auto func = [bpListName, b0ListName](const Particle * particle) -> int {
168 StoreObjPtr<ParticleList> bpList(bpListName);
169 StoreObjPtr<ParticleList> b0List(b0ListName);
170
171 if (!bpList.isValid() && !b0List.isValid())
172 B2FATAL("sigProbRank could not find either input list: bp_list='" << bpListName
173 << "', b0_list='" << b0ListName << "'");
174 if (!bpList.isValid())
175 B2FATAL("sigProbRank could not find the required bp_list: '" << bpListName << "'");
176 if (!b0List.isValid())
177 B2FATAL("sigProbRank could not find the required b0_list: '" << b0ListName << "'");
178
179 struct RankedCandidate {
180 double signalProbability;
181 const Particle* particle;
182 };
183
184 auto collectCandidates = [](const StoreObjPtr<ParticleList>& list,
185 const std::string & listLabel,
186 std::vector<RankedCandidate>& rankedCandidates)
187 {
188 for (unsigned int i = 0; i < list->getListSize(); ++i) {
189 const Particle* p = list->getParticle(i);
190 if (!p->hasExtraInfo("SignalProbability")) {
191 B2FATAL("sigProbRank requires every candidate in " << listLabel
192 << " to provide extraInfo('SignalProbability')");
193 }
194 rankedCandidates.push_back({p->getExtraInfo("SignalProbability"), p});
195 }
196 };
197
198 std::vector<RankedCandidate> rankedCandidates;
199 rankedCandidates.reserve(bpList->getListSize() + b0List->getListSize());
200 collectCandidates(bpList, bpListName, rankedCandidates);
201 collectCandidates(b0List, b0ListName, rankedCandidates);
202
203 std::stable_sort(rankedCandidates.begin(), rankedCandidates.end(),
204 [](const RankedCandidate & lhs, const RankedCandidate & rhs)
205 {
206 return lhs.signalProbability > rhs.signalProbability;
207 });
208
209 // Check if particle is a copy made by ParticleCopy::copyParticle
210 // (e.g. from setBeamConstrainedMomentum); copies store the original's
211 // array index in extraInfo("original_index")
212 int originalIndex = -1;
213 if (particle->hasExtraInfo("original_index"))
214 originalIndex = static_cast<int>(particle->getExtraInfo("original_index"));
215
216 for (unsigned int i = 0; i < rankedCandidates.size(); ++i)
217 {
218 const Particle* cand = rankedCandidates[i].particle;
219 if (cand == particle) {
220 return static_cast<int>(i) + 1;
221 }
222 if (originalIndex >= 0 && cand->getArrayIndex() == originalIndex) {
223 return static_cast<int>(i) + 1;
224 }
225 }
226
227 B2FATAL("sigProbRank: particle not found in the input lists: "
228 "bp_list='" << bpListName << "', b0_list='" << b0ListName << "'");
229 return -1;
230 };
231 return func;
232 }
233
234 VARIABLE_GROUP("FEIVariables");
235 REGISTER_VARIABLE("mostcommonBTagIndex", mostcommonBTagIndex,
236 "By giving e.g. a FEI B meson candidate the B meson index on generator level is determined, where most reconstructed particles can be assigned to. If no B meson found on generator level -1 is returned.");
237 REGISTER_VARIABLE("percentageMissingParticlesBTag", percentageMissingParticlesBTag,
238 "Get the percentage of missing particles by using the mostcommonBTagIndex. So the number of particles not reconstructed by e.g. the FEI are determined and divided by the number of generated particles using the given index of the B meson. If no B meson found on generator level -1 is returned.");
239 REGISTER_VARIABLE("percentageWrongParticlesBTag", percentageWrongParticlesBTag,
240 "Get the percentage of wrong particles by using the mostcommonBTagIndex. In this context wrong means that the reconstructed particles originated from the other B meson. The absolute number is divided by the total number of generated FSP from the given B meson index. If no B meson found on generator level -1 is returned.");
241 REGISTER_VARIABLE("mostcommonBTagDeltaP", mostcommonBTagDeltaP,
242 "Returns the magnitude of the 3-momentum difference in CMS frame between the "
243 "reconstructed particle and the generated B meson identified by mostcommonBTagIndex. "
244 "Returns NaN if no B meson is found on generator level.", "GeV/c");
245 REGISTER_VARIABLE("mostcommonBTagPDG", mostcommonBTagPDG,
246 "Returns the PDG code of the generated B meson identified by mostcommonBTagIndex. "
247 "Returns NaN if no B meson is found on generator level. "
248 "Note: this is equivalent to ``genParticle(mostcommonBTagIndex, PDG)``. "
249 "Other variables can be accessed the same way by replacing ``PDG`` with any variable.");
250 REGISTER_METAVARIABLE("sigProbRank(bp_list, b0_list)", sigProbRank,
251 "Returns the rank (starting at 1) of the candidate when all candidates from the B+ list (bp_list) "
252 "and B0 list (b0_list) are ordered together by descending ``extraInfo(SignalProbability)``.", Manager::VariableDataType::c_int);
253 }
255}
static const double doubleNaN
quiet_NaN
Definition Const.h:703
@ 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.