12#ifndef XAOD_STANDALONE
30using namespace asg::msgUserCode;
34 constexpr float INV_GEV = 1.f / 1000.f;
36 static const SG::AuxElement::Accessor<ElementLink<xAOD::IParticleContainer>> ACC_partA(
"FE_ParticleA");
37 static const SG::AuxElement::Accessor<ElementLink<xAOD::IParticleContainer>> ACC_partB(
"FE_ParticleB");
38 static const SG::AuxElement::Accessor<int> ACC_typeA(
"FE_ParticleA_Type");
39 static const SG::AuxElement::Accessor<int> ACC_typeB(
"FE_ParticleB_Type");
40 static const SG::AuxElement::Accessor<float> ACC_sharedEc(
"FE_SharedEc");
41 static const SG::AuxElement::Accessor<float> ACC_sharedEn(
"FE_SharedEn");
42 static const SG::AuxElement::Accessor<float> ACC_fracAc(
"FE_FracAc");
43 static const SG::AuxElement::Accessor<float> ACC_fracAn(
"FE_FracAn");
44 static const SG::AuxElement::Accessor<float> ACC_fracBc(
"FE_FracBc");
45 static const SG::AuxElement::Accessor<float> ACC_fracBn(
"FE_FracBn");
47#ifndef XAOD_STANDALONE
48 using FELinks_t = std::vector<ElementLink<xAOD::FlowElementContainer>>;
51 static const SG::AuxElement::ConstAccessor<std::vector<ElementLink<xAOD::FlowElementContainer>>>
52 ACC_cFEs(
"chargedGlobalFELinks");
53 static const SG::AuxElement::ConstAccessor<std::vector<ElementLink<xAOD::FlowElementContainer>>>
54 ACC_nFEs(
"neutralGlobalFELinks");
55 static const SG::AuxElement::ConstAccessor<ElementLink<xAOD::IParticleContainer>>
56 ACC_origObj(
"originalObjectLink");
59 inline void warnLimited(std::atomic<unsigned>& ctr,
const std::function<
void()>& fn)
61 if (
ctr.fetch_add(1, std::memory_order_relaxed) < 10)
fn();
73 std::less<const xAOD::IParticleContainer*>{}(
a, b) || (
a == b && ia <= ib);
80 return c1 == o.c1 &&
i1 == o.i1 &&
c2 == o.c2 &&
i2 == o.i2;
85 std::size_t h1 = std::hash<const void*>{}(k.c1) ^ (std::hash<std::size_t>{}(k.i1) << 1);
86 std::size_t h2 = std::hash<const void*>{}(k.c2) ^ (std::hash<std::size_t>{}(k.i2) << 1);
87 return h1 ^ (h2 << 1);
96#ifndef XAOD_STANDALONE
132 return StatusCode::SUCCESS;
135#ifndef XAOD_STANDALONE
143 std::vector<ObjView> objects;
144#ifndef XAOD_STANDALONE
152#ifndef XAOD_STANDALONE
158 return StatusCode::SUCCESS;
161#ifndef XAOD_STANDALONE
163 std::vector<ObjView>& objects)
const
171 for (std::size_t idx = 0; idx <
base->size(); ++idx)
174#ifndef XAOD_STANDALONE
179 objects.emplace_back(std::move(view));
183#ifndef XAOD_STANDALONE
187 collect_one(ObjView::Type::Electron,
194 collect_one(ObjView::Type::Muon,
201 collect_one(ObjView::Type::Photon,
208 collect_one(ObjView::Type::Tau,
215 collect_one(ObjView::Type::SmallRJet,
222 collect_one(ObjView::Type::LargeRJet,
230 collect_one(ObjView::Type::Electron,
237 collect_one(ObjView::Type::Muon,
244 collect_one(ObjView::Type::Photon,
251 collect_one(ObjView::Type::Tau,
258 collect_one(ObjView::Type::SmallRJet,
265 collect_one(ObjView::Type::LargeRJet,
271 return StatusCode::SUCCESS;
274#ifndef XAOD_STANDALONE
292 static std::atomic<unsigned> s_warn{0};
296 warnLimited(s_warn, [&]{
ANA_MSG_WARNING(
"collectFEsFromIndex called with null container"); });
299 if (idx >= cont->size())
301 warnLimited(s_warn, [&]{
303 <<
" size=" << cont->size());
311 warnLimited(s_warn, [&]{
ANA_MSG_WARNING(
"Null IParticle at idx=" << idx); });
316 [&](
const std::vector<ElementLink<xAOD::FlowElementContainer>>& links,
bool charged)
318 for (
const auto& el : links)
320 if (!el.isValid())
continue;
326 view.cSet.insert(fe);
327 view.EcTot += fe->
e() * INV_GEV;
329 view.nSet.insert(fe);
330 view.EnTot += fe->
e() * INV_GEV;
335 bool usedGlobal =
false;
337#ifndef XAOD_STANDALONE
340 case ObjView::Type::Electron:
344 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
345 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
348 case ObjView::Type::Muon:
352 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
353 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
356 case ObjView::Type::Photon:
360 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
361 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
364 case ObjView::Type::Tau:
368 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
369 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
372 case ObjView::Type::SmallRJet:
377 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
381 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
385 case ObjView::Type::LargeRJet:
390 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
394 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
400 if (ACC_cFEs.isAvailable(*p)) {
402 loop_links(ACC_cFEs(*p),
true);
404 if (ACC_nFEs.isAvailable(*p)) {
406 loop_links(ACC_nFEs(*p),
false);
414 for (
const auto& cl :
jet->constituentLinks())
416 if (!cl.isValid())
continue;
419 if (!cpart)
continue;
424#ifndef XAOD_STANDALONE
429 const auto& feLink = origObj(*constit);
431 if (ACC_origObj.isAvailable(*constit))
433 const auto& feLink = ACC_origObj(*constit);
435 if (!feLink.isValid())
continue;
438 if (!opart)
continue;
443 if (fe->isCharged()) {
444 view.cSet.insert(fe);
445 view.EcTot += fe->e() * INV_GEV;
447 view.nSet.insert(fe);
448 view.EnTot += fe->e() * INV_GEV;
453 const auto* fe = constit;
455 if (fe->isCharged()) {
456 view.cSet.insert(fe);
457 view.EcTot += fe->e() * INV_GEV;
459 view.nSet.insert(fe);
460 view.EnTot += fe->e() * INV_GEV;
467#ifndef XAOD_STANDALONE
469 const std::vector<ObjView>& objects)
const
474 std::unordered_map<PairKey, SharedAcc, PairKeyHash> shared;
475 shared.reserve(objects.size() * 2);
477 for (std::size_t i = 0; i < objects.size(); ++i)
479 const auto&
A = objects[i];
481 for (std::size_t j = i + 1; j < objects.size(); ++j)
483 const auto& B = objects[j];
488 if (!
A.cSet.empty() && !B.cSet.empty())
490 const auto& small = (
A.cSet.size() < B.cSet.size()) ?
A.cSet : B.cSet;
491 const auto& large = (
A.cSet.size() < B.cSet.size()) ? B.cSet :
A.cSet;
492 for (
const auto* fe : small) {
493 if (large.count(fe)) Ec += fe->e() * INV_GEV;
497 if (!
A.nSet.empty() && !B.nSet.empty())
499 const auto& small = (
A.nSet.size() < B.nSet.size()) ?
A.nSet : B.nSet;
500 const auto& large = (
A.nSet.size() < B.nSet.size()) ? B.nSet :
A.nSet;
501 for (
const auto* fe : small) {
502 if (large.count(fe)) En += fe->e() * INV_GEV;
506 if (Ec <= 0.f && En <= 0.f)
continue;
509 auto& s = shared[key];
519 s.typeA =
static_cast<int>(
A.type);
520 s.typeB =
static_cast<int>(B.type);
524 auto assocMap = std::make_unique<xAOD::MissingETAssociationMap>();
525 auto assocAux = std::make_unique<xAOD::AuxContainerBase>();
526 assocMap->setStore(assocAux.get());
528 for (
const auto& [key,
sh] : shared)
531 assocMap->push_back(assoc);
538 assocMap->pop_back();
543 ACC_partA(*assoc) = linkA;
544 ACC_partB(*assoc) = linkB;
545 ACC_typeA(*assoc) =
sh.typeA;
546 ACC_typeB(*assoc) =
sh.typeB;
548 ACC_sharedEc(*assoc) =
sh.Ec;
549 ACC_sharedEn(*assoc) =
sh.En;
551 ACC_fracAc(*assoc) = (
sh.AcTot > 0.f ?
sh.Ec /
sh.AcTot : 0.f);
552 ACC_fracAn(*assoc) = (
sh.AnTot > 0.f ?
sh.En /
sh.AnTot : 0.f);
553 ACC_fracBc(*assoc) = (
sh.BcTot > 0.f ?
sh.Ec /
sh.BcTot : 0.f);
554 ACC_fracBn(*assoc) = (
sh.BnTot > 0.f ?
sh.En /
sh.BnTot : 0.f);
557#ifndef XAOD_STANDALONE
565 return StatusCode::SUCCESS;
#define ATH_CHECK
Evaluate an expression and check for errors.
Base class for elements of a container that can have aux data.
Handle class for reading a decoration on an object.
ServiceHandle< StoreGateSvc > & evtStore()
ElementLink implementation for ROOT usage.
bool isValid() const
Check if the element can be found.
Handle class for reading a decoration on an object.
bool isAvailable()
Test to see if this variable exists in the store, for the referenced object.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
virtual double e() const override
The total energy of the particle.
Class providing the definition of the 4-vector interface.
virtual Type::ObjectType type() const =0
The type of the object as a simple enumeration.
@ Jet
The object is a jet.
@ FlowElement
The object is a track-calo-cluster.
Jet_v1 Jet
Definition of the current "jet version".
MissingETAssociation_v1 MissingETAssociation
Version control by type definition.
FlowElement_v1 FlowElement
Definition of the current "pfo version".
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.
hold the test vectors and ease the comparison