29 using parent_mask_t =
unsigned long long;
31 parent_mask_t matchMask(
const std::vector<MatchedParent>& matches) {
32 parent_mask_t
mask = 0x0;
33 for (
const auto&
match: matches) {
34 constexpr
size_t max_idx = std::numeric_limits<decltype(
mask)>::digits;
35 if (
match.parent_index > max_idx) {
36 throw std::runtime_error(
37 "parent index overflowed the match mask "
47 std::string
join(
const std::vector<std::string>&
v,
const std::string&
sep =
", ") {
49 for (
unsigned int pos = 0;
pos <
v.size();
pos++) {
56 std::vector<std::string>
stringify(
const T& container) {
57 std::vector<std::string>
out;
64 std::vector<std::string>
output;
65 for (
unsigned int child_n = 0; child_n <
p->nChildren(); child_n++) {
68 if (
output.empty())
return "none";
77 unsigned int n_cascade_candidates = 0;
78 for (
auto& cascade: cascades_raw) {
79 n_cascade_candidates += cascade->size();
82 "n_targets: " << targets->size() <<
", "
83 "n_parents: " << truth->size() <<
", "
84 "n_cascade_candidates: " << n_cascade_candidates <<
101 std::map<int, std::set<int>> findAllDescendants(
int parent,
const Barcodex& barcodex, std::set<int> history = {})
103 using return_t = std::map<int,std::set<int>>;
104 auto itr = barcodex.find(
parent);
105 if (itr == barcodex.end()) {
107 throw std::runtime_error(
111 const std::set<int>&
children = itr->second;
113 if (!history.insert(
parent).second) {
117 return_t all_children;
122 for (
auto& [dec,
dh]: findAllDescendants(child, barcodex, history)) {
123 all_children[dec].merge(
dh);
133 if (barkids.size() > 1) {
134 std::set<int> pdg_ids;
135 TLorentzVector sum_p4;
138 sum_p4 += dupkid->
p4();
139 pdg_ids.insert(dupkid->pdgId());
140 if (dupkid->nChildren() > child->
nChildren()) child = dupkid;
142 if (pdg_ids.size() != 1) {
143 throw std::runtime_error(
"same barcode, different pdgid: [" +
join(
stringify(pdg_ids)) +
"]");
145 if (
float dr = child->
p4().DeltaR(sum_p4);
dr > 0.001) {
155 for (
unsigned int parent_n = 0; parent_n <
p->nParents(); parent_n++) {
157 if (!
parent)
throw std::runtime_error(
"broken truth record");
158 if (
parent->pdgId() ==
p->pdgId())
return false;
167 if (
int n_parents =
p->nParents(); n_parents != 1) {
168 throw std::logic_error(
"can't get parent [n_parents: " +
std::to_string(n_parents) +
"]");
174 return (
parent->hasCharm() ||
parent->hasBottom()) &&
p->isChLepton();
178 return parent->hasBottom() &&
p->hasCharm();
194 unsigned char n_match = 0;
197 if (
parent.cascade_pids.contains(
pid)) n_match++;
269 return StatusCode::SUCCESS;
281 using uc_t =
unsigned char;
292 if (targets->empty())
return StatusCode::SUCCESS;
297 std::vector<const xAOD::TruthParticle*> psort;
299 if (!parentids.contains(
p->pdgId()))
continue;
300 if (!isOriginal(
p))
continue;
304 std::sort(psort.begin(), psort.end(),[](
const auto*
p1,
const auto*
p2) {return p1->m() > p2->m();});
306 constexpr
size_t max_idx = std::numeric_limits<parent_mask_t>::digits;
307 if (psort.size() > max_idx) {
309 "Found too many parent particles to store in parent match mask "
310 "truncating the parent collection [max: " << max_idx <<
", "
311 "n: " << psort.size() <<
"]");
312 psort.resize(max_idx);
316 std::vector<SG::ReadHandle<TPC>> cascades_raw;
318 cascades_raw.emplace_back(
key, cxt);
320 logInputs(msgStream(), targets, phandle, cascades_raw);
328 for (
auto& cascade: cascades_raw) {
331 logIPMap(
msg(), ipmap);
333 ATH_MSG_DEBUG(
"merged cascade contains " << barcodex.size() <<
" particles");
338 std::unordered_map<const J*, std::vector<MatchedParent>> labeled_targets;
339 unsigned int n_parents = 0;
340 for (
const auto*
p: psort) {
341 unsigned int parent_index = n_parents++;
343 for (
auto& [cbar, histbars]: findAllDescendants(
HepMC::uniqueID(
p), barcodex)) {
344 IPMap::mapped_type& barkids = ipmap.at(cbar);
346 std::vector<std::pair<float, const J*>> drs;
348 const J* drsMinMatch = 0;
349 for (
const auto* j: *targets) {
350 if(j->p4().DeltaR(child->
p4()) < drsMinDR) {
351 drsMinDR=j->
p4().DeltaR(child->
p4());
359 match.deltaR = drsMinDR;
360 match.parent_index = parent_index;
362 for (
auto& histbar: histbars) {
363 match.cascade_pids.insert(selectChild(ipmap.at(histbar))->pdgId());
366 labeled_targets[drsMinMatch].push_back(
match);
376 for (
const J* j: *targets) {
377 if (labeled_targets.contains(j)) {
378 const std::vector<MatchedParent>& matches = labeled_targets.at(j);
380 return p1.deltaR <
p2.deltaR;
383 matches.begin(), matches.end(),
min_dr);
385 pdgid(*j) =
p->pdgId();
387 auto* container =
dynamic_cast<const TPC*
>(
p->container());
388 link(*j) =
JL(*container,
p->index());
390 nMatched(*j) = matches.size();
391 mask(*j) = matchMask(matches);
393 matchPdgId(*j) = child->
pdgId();
394 matchChildCount(*j) = child->
nChildren();
395 auto* matchedContainer =
dynamic_cast<const TPC*
>(child->
container());
396 matchLink(*j) =
JL(*matchedContainer, child->
index());
398 cascadeCount.decorate(*j, matches);
408 matchChildCount(*j) = 0;
409 matchLink(*j) =
JL();
411 cascadeCount.decorateDefault(*j);
421 dec.lock(targets.get());
424 return StatusCode::SUCCESS;
445 return StatusCode::SUCCESS;
455 auto cascadeWants = [
462 if (
int n_parents =
p->nParents(); n_parents == 1) {
463 if (vsl && isSoftLepton(
p))
return false;
464 if (vsc && isSoftCharm(
p))
return false;
466 if (targid.contains(
p->pdgId()))
return true;
467 if (
b &&
p->hasBottom())
return true;
468 if (
c &&
p->hasCharm())
return true;
479 if (cascadeWants(
p)) {
480 auto& child_set = insert(
p);
481 for (
unsigned int child_n = 0; child_n <
p->nChildren(); child_n++) {
492 if(ok_missing.contains(
p->pdgId())) {
496 "null truth child [barcode={},pdg_id={},child={}of{}]",
499 if (warn_missing.contains(
p->pdgId())) {
503 throw std::runtime_error(problem);
506 }
else if (cascadeWants(
c)) {