28 using parent_mask_t =
unsigned long long;
30 parent_mask_t matchMask(
const std::vector<MatchedParent>& matches) {
31 parent_mask_t
mask = 0x0;
32 for (
const auto&
match: matches) {
33 constexpr
size_t max_idx = std::numeric_limits<decltype(
mask)>::digits;
34 if (
match.parent_index > max_idx) {
35 throw std::runtime_error(
36 "parent index overflowed the match mask "
46 std::string
join(
const std::vector<std::string>&
v,
const std::string&
sep =
", ") {
48 for (
unsigned int pos = 0;
pos <
v.size();
pos++) {
55 std::vector<std::string>
stringify(
const T& container) {
56 std::vector<std::string>
out;
63 std::vector<std::string>
output;
64 for (
unsigned int child_n = 0; child_n <
p->nChildren(); child_n++) {
67 if (
output.empty())
return "none";
76 unsigned int n_cascade_candidates = 0;
77 for (
auto& cascade: cascades_raw) {
78 n_cascade_candidates += cascade->size();
81 "n_targets: " << targets->size() <<
", "
82 "n_parents: " << truth->size() <<
", "
83 "n_cascade_candidates: " << n_cascade_candidates <<
100 std::map<int, std::set<int>> findAllDescendants(
int parent,
const Barcodex& barcodex, std::set<int> history = {})
102 using return_t = std::map<int,std::set<int>>;
103 auto itr = barcodex.find(
parent);
104 if (itr == barcodex.end()) {
106 throw std::runtime_error(
110 const std::set<int>&
children = itr->second;
112 if (!history.insert(
parent).second) {
116 return_t all_children;
121 for (
auto& [dec,
dh]: findAllDescendants(child, barcodex, history)) {
122 all_children[dec].merge(
dh);
132 if (barkids.size() > 1) {
133 std::set<int> pdg_ids;
134 TLorentzVector sum_p4;
137 sum_p4 += dupkid->
p4();
138 pdg_ids.insert(dupkid->pdgId());
139 if (dupkid->nChildren() > child->
nChildren()) child = dupkid;
141 if (pdg_ids.size() != 1) {
142 throw std::runtime_error(
"same barcode, different pdgid: [" +
join(
stringify(pdg_ids)) +
"]");
144 if (
float dr = child->
p4().DeltaR(sum_p4);
dr > 0.001) {
154 for (
unsigned int parent_n = 0; parent_n <
p->nParents(); parent_n++) {
156 if (!
parent)
throw std::runtime_error(
"broken truth record");
157 if (
parent->pdgId() ==
p->pdgId())
return false;
166 if (
int n_parents =
p->nParents(); n_parents != 1) {
167 throw std::logic_error(
"can't get parent [n_parents: " +
std::to_string(n_parents) +
"]");
173 return (
parent->hasCharm() ||
parent->hasBottom()) &&
p->isChLepton();
177 return parent->hasBottom() &&
p->hasCharm();
193 unsigned char n_match = 0;
196 if (
parent.cascade_pids.contains(
pid)) n_match++;
268 return StatusCode::SUCCESS;
280 using uc_t =
unsigned char;
291 if (targets->empty())
return StatusCode::SUCCESS;
296 std::vector<const xAOD::TruthParticle*> psort;
298 if (!parentids.contains(
p->pdgId()))
continue;
299 if (!isOriginal(
p))
continue;
303 std::sort(psort.begin(), psort.end(),[](
const auto*
p1,
const auto*
p2) {return p1->m() > p2->m();});
305 constexpr
size_t max_idx = std::numeric_limits<parent_mask_t>::digits;
306 if (psort.size() > max_idx) {
308 "Found too many parent particles to store in parent match mask "
309 "truncating the parent collection [max: " << max_idx <<
", "
310 "n: " << psort.size() <<
"]");
311 psort.resize(max_idx);
315 std::vector<SG::ReadHandle<TPC>> cascades_raw;
317 cascades_raw.emplace_back(
key, cxt);
319 logInputs(msgStream(), targets, phandle, cascades_raw);
327 for (
auto& cascade: cascades_raw) {
330 logIPMap(
msg(), ipmap);
332 ATH_MSG_DEBUG(
"merged cascade contains " << barcodex.size() <<
" particles");
337 std::unordered_map<const J*, std::vector<MatchedParent>> labeled_targets;
338 unsigned int n_parents = 0;
339 for (
const auto*
p: psort) {
340 unsigned int parent_index = n_parents++;
342 for (
auto& [cbar, histbars]: findAllDescendants(
HepMC::barcode(
p), barcodex)) {
343 IPMap::mapped_type& barkids = ipmap.at(cbar);
345 std::vector<std::pair<float, const J*>> drs;
347 const J* drsMinMatch = 0;
348 for (
const auto* j: *targets) {
349 if(j->p4().DeltaR(child->
p4()) < drsMinDR) {
350 drsMinDR=j->
p4().DeltaR(child->
p4());
358 match.deltaR = drsMinDR;
359 match.parent_index = parent_index;
361 for (
auto& histbar: histbars) {
362 match.cascade_pids.insert(selectChild(ipmap.at(histbar))->pdgId());
365 labeled_targets[drsMinMatch].push_back(
match);
375 for (
const J* j: *targets) {
376 if (labeled_targets.contains(j)) {
377 const std::vector<MatchedParent>& matches = labeled_targets.at(j);
379 return p1.deltaR <
p2.deltaR;
382 matches.begin(), matches.end(),
min_dr);
384 pdgid(*j) =
p->pdgId();
386 auto* container =
dynamic_cast<const TPC*
>(
p->container());
387 link(*j) =
JL(*container,
p->index());
389 nMatched(*j) = matches.size();
390 mask(*j) = matchMask(matches);
392 matchPdgId(*j) = child->
pdgId();
393 matchChildCount(*j) = child->
nChildren();
394 auto* matchedContainer =
dynamic_cast<const TPC*
>(child->
container());
395 matchLink(*j) =
JL(*matchedContainer, child->
index());
397 cascadeCount.decorate(*j, matches);
407 matchChildCount(*j) = 0;
408 matchLink(*j) =
JL();
410 cascadeCount.decorateDefault(*j);
420 dec.lock(targets.get());
423 return StatusCode::SUCCESS;
444 return StatusCode::SUCCESS;
454 auto cascadeWants = [
461 if (
int n_parents =
p->nParents(); n_parents == 1) {
462 if (vsl && isSoftLepton(
p))
return false;
463 if (vsc && isSoftCharm(
p))
return false;
465 if (targid.contains(
p->pdgId()))
return true;
466 if (
b &&
p->hasBottom())
return true;
467 if (
c &&
p->hasCharm())
return true;
478 if (cascadeWants(
p)) {
479 auto& child_set = insert(
p);
480 for (
unsigned int child_n = 0; child_n <
p->nChildren(); child_n++) {
491 if(ok_missing.contains(
p->pdgId())) {
495 "null truth child [barcode={},pdg_id={},child={}of{}]",
498 if (warn_missing.contains(
p->pdgId())) {
502 throw std::runtime_error(problem);
505 }
else if (cascadeWants(
c)) {