12#ifndef XAOD_STANDALONE
30using namespace asg::msgUserCode;
34 constexpr float INV_GEV = 1.f / 1000.f;
47#ifndef XAOD_STANDALONE
48 using FELinks_t = std::vector<ElementLink<xAOD::FlowElementContainer>>;
52 ACC_cFEs(
"chargedGlobalFELinks");
54 ACC_nFEs(
"neutralGlobalFELinks");
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);
98#ifndef XAOD_STANDALONE
134 return StatusCode::SUCCESS;
137#ifndef XAOD_STANDALONE
145 std::vector<ObjView> objects;
146#ifndef XAOD_STANDALONE
154#ifndef XAOD_STANDALONE
160 return StatusCode::SUCCESS;
163#ifndef XAOD_STANDALONE
165 std::vector<ObjView>& objects)
const
175 for (std::size_t idx = 0; idx <
base->size(); ++idx)
178#ifndef XAOD_STANDALONE
183 objects.emplace_back(std::move(view));
187#ifndef XAOD_STANDALONE
191 collect_one(ObjView::Type::Electron,
198 collect_one(ObjView::Type::Muon,
205 collect_one(ObjView::Type::Photon,
212 collect_one(ObjView::Type::Tau,
219 collect_one(ObjView::Type::SmallRJet,
226 collect_one(ObjView::Type::LargeRJet,
234 collect_one(ObjView::Type::Electron,
241 collect_one(ObjView::Type::Muon,
248 collect_one(ObjView::Type::Photon,
255 collect_one(ObjView::Type::Tau,
262 collect_one(ObjView::Type::SmallRJet,
269 collect_one(ObjView::Type::LargeRJet,
275 return StatusCode::SUCCESS;
278#ifndef XAOD_STANDALONE
296 static std::atomic<unsigned> s_warn{0};
300 warnLimited(s_warn, [&]{
ANA_MSG_WARNING(
"collectFEsFromIndex called with null container"); });
303 if (idx >= cont->size())
305 warnLimited(s_warn, [&]{
307 <<
" size=" << cont->size());
315 warnLimited(s_warn, [&]{
ANA_MSG_WARNING(
"Null IParticle at idx=" << idx); });
320 [&](
const std::vector<ElementLink<xAOD::FlowElementContainer>>& links,
bool charged)
322 for (
const auto& el : links)
324 if (!el.isValid())
continue;
330 view.cSet.insert(fe);
331 view.EcTot += fe->
e() * INV_GEV;
333 view.nSet.insert(fe);
334 view.EnTot += fe->
e() * INV_GEV;
339 bool usedGlobal =
false;
341#ifndef XAOD_STANDALONE
344 case ObjView::Type::Electron:
348 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
349 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
352 case ObjView::Type::Muon:
356 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
357 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
360 case ObjView::Type::Photon:
364 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
365 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
368 case ObjView::Type::Tau:
372 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
373 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
376 case ObjView::Type::SmallRJet:
381 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
385 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
389 case ObjView::Type::LargeRJet:
394 if (chargedFEs.
isAvailable()) { usedGlobal =
true; loop_links(chargedFEs(*p),
true); }
398 if (neutralFEs.
isAvailable()) { usedGlobal =
true; loop_links(neutralFEs(*p),
false); }
404 if (ACC_cFEs.isAvailable(*p)) {
406 loop_links(ACC_cFEs(*p),
true);
408 if (ACC_nFEs.isAvailable(*p)) {
410 loop_links(ACC_nFEs(*p),
false);
418 for (
const auto& cl :
jet->constituentLinks())
420 if (!cl.isValid())
continue;
423 if (!cpart)
continue;
428#ifndef XAOD_STANDALONE
433 const auto& feLink = origObj(*constit);
435 if (ACC_origObj.isAvailable(*constit))
437 const auto& feLink = ACC_origObj(*constit);
439 if (!feLink.isValid())
continue;
442 if (!opart)
continue;
447 if (fe->isCharged()) {
448 view.cSet.insert(fe);
449 view.EcTot += fe->e() * INV_GEV;
451 view.nSet.insert(fe);
452 view.EnTot += fe->e() * INV_GEV;
457 const auto* fe = constit;
459 if (fe->isCharged()) {
460 view.cSet.insert(fe);
461 view.EcTot += fe->e() * INV_GEV;
463 view.nSet.insert(fe);
464 view.EnTot += fe->e() * INV_GEV;
471#ifndef XAOD_STANDALONE
473 const std::vector<ObjView>& objects)
const
480 std::unordered_map<PairKey, SharedAcc, PairKeyHash> shared;
481 shared.reserve(objects.size() * 2);
483 for (std::size_t i = 0; i < objects.size(); ++i)
485 const auto&
A = objects[i];
487 for (std::size_t j = i + 1; j < objects.size(); ++j)
489 const auto& B = objects[j];
494 if (!
A.cSet.empty() && !B.cSet.empty())
496 const auto& small = (
A.cSet.size() < B.cSet.size()) ?
A.cSet : B.cSet;
497 const auto& large = (
A.cSet.size() < B.cSet.size()) ? B.cSet :
A.cSet;
498 for (
const auto* fe : small) {
499 if (large.count(fe)) Ec += fe->e() * INV_GEV;
503 if (!
A.nSet.empty() && !B.nSet.empty())
505 const auto& small = (
A.nSet.size() < B.nSet.size()) ?
A.nSet : B.nSet;
506 const auto& large = (
A.nSet.size() < B.nSet.size()) ? B.nSet :
A.nSet;
507 for (
const auto* fe : small) {
508 if (large.count(fe)) En += fe->e() * INV_GEV;
512 if (Ec <= 0.f && En <= 0.f)
continue;
515 auto& s = shared[key];
525 s.typeA =
static_cast<int>(
A.type);
526 s.typeB =
static_cast<int>(B.type);
530 auto assocMap = std::make_unique<xAOD::MissingETAssociationMap>();
531 auto assocAux = std::make_unique<xAOD::AuxContainerBase>();
532 assocMap->setStore(assocAux.get());
534 for (
const auto& [key,
sh] : shared)
537 assocMap->push_back(assoc);
544 assocMap->pop_back();
549 ACC_partA(*assoc) = linkA;
550 ACC_partB(*assoc) = linkB;
551 ACC_typeA(*assoc) =
sh.typeA;
552 ACC_typeB(*assoc) =
sh.typeB;
554 ACC_sharedEc(*assoc) =
sh.Ec;
555 ACC_sharedEn(*assoc) =
sh.En;
557 ACC_fracAc(*assoc) = (
sh.AcTot > 0.f ?
sh.Ec /
sh.AcTot : 0.f);
558 ACC_fracAn(*assoc) = (
sh.AnTot > 0.f ?
sh.En /
sh.AnTot : 0.f);
559 ACC_fracBc(*assoc) = (
sh.BcTot > 0.f ?
sh.Ec /
sh.BcTot : 0.f);
560 ACC_fracBn(*assoc) = (
sh.BnTot > 0.f ?
sh.En /
sh.BnTot : 0.f);
563#ifndef XAOD_STANDALONE
571 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
Test to see if the link can be dereferenced.
SG::ConstAccessor< T, ALLOC > ConstAccessor
SG::Accessor< T, ALLOC > Accessor
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