2 * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
5 * @file GeneratorObjects/HepMcParticleLink.icc
6 * @author scott snyder <snyder@bnl.gov>
8 * @brief a link optimized in size for a GenParticle in a McEventCollection
12 //**************************************************************************
17 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode()
24 * @param uid Unique ID of target particle.
25 * @param eventIndex Identifies the target GenEvent in a McEventCollection,
26 * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
27 * or the position in the container
28 * if isIndexEventPosition is IS_POSITION.
29 * 0 always means the first event in the collection.
30 * @param isIndexEventPosition: See @c eventIndex.
33 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode
35 index_type eventIndex,
36 PositionFlag isIndexEventPosition /*=IS_EVENTNUM*/,
37 UniqueIDFlag isUniqueIDBarcode /*= IS_ID*/)
39 setIndex (eventIndex, isIndexEventPosition);
40 setUniqueID (uid, isUniqueIDBarcode);
45 * @brief Copy constructor. (Can't be defaulted due to the atomic member.)
48 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode (const ExtendedBarCode& rhs)
49 : m_BC (static_cast<barcode_type> (rhs.m_BC)),
50 m_evtIndex (static_cast<index_type> (rhs.m_evtIndex)),
51 m_truthSupp (rhs.m_truthSupp)
57 * @brief Move constructor. (Can't be defaulted due to the atomic member.)
60 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode (ExtendedBarCode&& rhs) noexcept
61 : m_BC (rhs.m_BC.load()), // no move constructor for atomics
62 m_evtIndex (rhs.m_evtIndex.load()), // no move constructor for atomics
63 m_truthSupp (std::exchange(rhs.m_truthSupp,EBC_UNSUPPRESSED))
68 * @brief Assignment. (Can't be defaulted due to the atomic member.)
71 HepMcParticleLink::ExtendedBarCode&
72 HepMcParticleLink::ExtendedBarCode::operator= (const ExtendedBarCode& rhs)
75 m_BC = static_cast<barcode_type> (rhs.m_BC);
76 m_evtIndex = static_cast<index_type> (rhs.m_evtIndex);
77 m_truthSupp=rhs.m_truthSupp;
83 * @brief Assignment. (Can't be defaulted due to the atomic member.)
86 HepMcParticleLink::ExtendedBarCode&
87 HepMcParticleLink::ExtendedBarCode::operator= (ExtendedBarCode&& rhs) noexcept
90 m_BC = static_cast<barcode_type> (rhs.m_BC.load());
91 m_evtIndex = static_cast<index_type>(rhs.m_evtIndex.load());
92 m_truthSupp = std::exchange(rhs.m_truthSupp, EBC_UNSUPPRESSED);
99 * @brief Unique ID of target variable (0 for a null link).
102 HepMcParticleLink::barcode_type
103 HepMcParticleLink::ExtendedBarCode::uid() const
110 * @brief Return the event index/position.
111 * @param index[out] Event index (number), or @c UNDEFINED.
112 * @param position[out] Event position, or @c UNDEFINED.
114 * The GenEvent within the McEventCollection is identified either by
115 * the GenEvent number or by the position within the collection.
116 * This method will return this by setting either @c index or @c position;
117 * the other one is set to @c UNDEFINED.
120 void HepMcParticleLink::ExtendedBarCode::eventIndex (index_type& index,
121 index_type& position) const
123 index_type idx = m_evtIndex;
124 if (idx & POSITION_MASK) {
126 position = idx & ~POSITION_MASK;
130 position = UNDEFINED;
136 * @brief Return the GenParticle id/barcode.
137 * @param id[out] GenParticle::id, or @c UNDEFINEDBC.
138 * @param barcode[out] barcode (deprecated), or @c UNDEFINEDBC.
140 * The GenParticle within the GenEvent is identified either by
141 * the GenParticle::id or the barcode.
142 * This method will return this by setting either @c id or @c barcode;
143 * the other one is set to @c UNDEFINEDBC.
146 void HepMcParticleLink::ExtendedBarCode::uniqueID (barcode_type& id,
147 barcode_type& barcode) const
149 barcode_type uid = m_BC;
150 if (uid == 0) // special case for delta-rays
155 else if (uid & BARCODE_MASK) {
157 barcode = uid & ~BARCODE_MASK;
161 barcode = UNDEFINEDBC;
167 * @brief Return which collection we're targeting, as a char ('a'..'b').
170 char HepMcParticleLink::ExtendedBarCode::getTruthSuppressionTypeAsChar() const
172 return truthSuppressionTypeAsChar (m_truthSupp);
177 * @brief Equality test.
179 * Be aware: if one EBC holds the target GenEvent by number and the
180 * other by position, then this will always return false, even if they
181 * reference the same GenEvent.
182 * To avoid this, use HepMcParticleLink::operator=.
186 HepMcParticleLink::ExtendedBarCode::operator==(const ExtendedBarCode& rhs) const
188 return (this->m_BC == rhs.m_BC &&
189 this->m_truthSupp == rhs.m_truthSupp &&
190 this->m_evtIndex == rhs.m_evtIndex);
195 * @brief Inequality test.
197 * Be aware: if one EBC holds the target GenEvent by number and the
198 * other by position, then this will always return true, even if they
199 * reference the same GenEvent.
200 * To avoid this, use HepMcParticleLink::operator=.
204 HepMcParticleLink::ExtendedBarCode::operator!= (const ExtendedBarCode& rhs) const
206 return !(operator==(rhs));
211 * @brief Ordering test.
213 * Be aware: if one EBC holds the target GenEvent by number and the
214 * other by position, then this will not work as expected.
215 * To avoid this, use HepMcParticleLink::operator=.
219 HepMcParticleLink::ExtendedBarCode::operator< (const ExtendedBarCode& rhs) const
221 return (m_truthSupp < rhs.m_truthSupp ||
222 (m_truthSupp == rhs.m_truthSupp && m_evtIndex < rhs.m_evtIndex) ||
223 (m_truthSupp == rhs.m_truthSupp && m_evtIndex == rhs.m_evtIndex && m_BC < rhs.m_BC) ) ;
228 * @brief Compare the event index part of two links.
229 * @param lhs First link to compare.
230 * @param rhs Second link to compare.
231 * @returns -1, 0, or 1, depending on the result of the comparison.
233 * The event index part of the link can be represented as either
234 * an event number or the position within the container.
235 * If necessary, the links will be normalized so that they
236 * both refer to an event number.
240 HepMcParticleLink::ExtendedBarCode::compareIndex (const HepMcParticleLink& lhs,
241 const HepMcParticleLink& rhs)
243 // Get the stored indices. The high bit will be set of they
244 // represent a position. Do a quick test for equality.
245 index_type idx1 = lhs.m_extBarcode.m_evtIndex;
246 index_type idx2 = rhs.m_extBarcode.m_evtIndex;
247 if (idx1 == idx2) return 0;
249 // Normalize the values so that they both refer to event number;
250 // this happens as a side-effect of calling cptr().
251 if (idx1 & POSITION_MASK) {
253 idx1 = lhs.m_extBarcode.m_evtIndex;
255 if (idx2 & POSITION_MASK) {
257 idx2 = rhs.m_extBarcode.m_evtIndex;
264 else if (idx1 < idx2) {
275 * @brief Compare the unique ID part of two links.
276 * @param lhs First link to compare.
277 * @param rhs Second link to compare.
278 * @returns -1, 0, or 1, depending on the result of the comparison.
280 * The unique ID part of the link can be represented as either
281 * a barcode or the id.
282 * If necessary, the links will be normalized so that they
283 * both refer to an id.
287 HepMcParticleLink::ExtendedBarCode::compareUniqueID (const HepMcParticleLink& lhs,
288 const HepMcParticleLink& rhs)
290 // Get the stored indices. The high bit will be set of they
291 // represent a position. Do a quick test for equality.
292 barcode_type uid1 = lhs.m_extBarcode.m_BC;
293 barcode_type uid2 = rhs.m_extBarcode.m_BC;
294 if (uid1 == uid2) return 0;
296 // Normalize the values so that they both refer to the id;
297 // this happens as a side-effect of calling cptr().
298 if (uid1 & BARCODE_MASK) {
300 uid1 = lhs.m_extBarcode.m_BC;
302 if (uid2 & BARCODE_MASK) {
304 uid2 = rhs.m_extBarcode.m_BC;
310 else if (uid1 < uid2) {
320 * @brief Change m_BC from barcode to ID.
321 * @param ID GenParticle::id value to set.
322 * @param barcode existing barcode value.
324 * If the link is currently referencing a GenParticle with @c barcode,
325 * update it so that it instead references the GenParticle
326 * with id value @c ID.
328 * This may be called concurrently, as long as all such concurrent
329 * calls have the same arguments.
332 void HepMcParticleLink::ExtendedBarCode::makeID (barcode_type ID,
333 barcode_type barcode) const
335 assert ((ID & BARCODE_MASK) == 0);
336 barcode_type old = barcode | BARCODE_MASK;
337 m_BC.compare_exchange_strong (old, ID);
338 assert (old == (barcode|BARCODE_MASK) || old == ID);
343 * @brief Change index from position to number.
344 * @param index Event number to set.
345 * @param position Existing event position.
347 * If the link is currently referencing the GenEvent at @c position,
348 * update it so that it instead references the GenEvent
349 * with number @c index.
351 * This may be called concurrently, as long as all such concurrent
352 * calls have the same arguments.
355 void HepMcParticleLink::ExtendedBarCode::makeIndex (index_type index,
356 index_type position) const
358 assert ((index & POSITION_MASK) == 0);
359 index_type old = position | POSITION_MASK;
360 m_evtIndex.compare_exchange_strong (old, index);
361 assert (old == (position|POSITION_MASK) || old == index || (position==UNDEFINED && old==0));
366 * @brief Initialize the unique identifier part of the link.
367 * @param uid The id or barcode.
368 * @param barcodeFlag If IS_BARCODE, @c uid represents a GenParticle barcode (deprecated);
369 * otherwise, it represents a GenParticle::id().
373 HepMcParticleLink::ExtendedBarCode::setUniqueID (barcode_type uid,
374 UniqueIDFlag barcodeFlag)
376 assert ((uid & BARCODE_MASK) == 0);
377 // For delta-rays barcode=id=0
378 if (uid != 0 && barcodeFlag == IS_BARCODE) {
386 * @brief Initialize the event index part of the link.
387 * @param idx The index or position.
388 * @param positionFlag If IS_POSITION, @c idx represents a position
389 * in the collection; otherwise, it represents an event number.
393 HepMcParticleLink::ExtendedBarCode::setIndex (index_type idx,
394 PositionFlag positionFlag)
396 assert ((idx & POSITION_MASK) == 0);
397 if (positionFlag == IS_POSITION) {
398 idx |= POSITION_MASK;
403 inline bool HepMcParticleLink::ExtendedBarCode::linkIsNull() const
405 barcode_type particle_id, particle_barcode;
406 uniqueID (particle_id, particle_barcode);
408 (particle_id == 0 && particle_barcode == 0) || // delta rays
409 (particle_id == 0 && particle_barcode == ExtendedBarCode::UNDEFINEDBC) ||
410 (particle_id == ExtendedBarCode::UNDEFINEDBC && particle_barcode == 0)
415 //**************************************************************************
421 * @brief Default constructor. Makes a null link.
422 * @param sg Optional specification of a specific store to reference.
425 HepMcParticleLink::HepMcParticleLink (IProxyDict* sg /*= nullptr*/)
432 * @brief Default constructor. Makes a null link.
433 * @param ctx Context of the store to reference.
436 HepMcParticleLink::HepMcParticleLink (const EventContext& ctx)
437 : HepMcParticleLink (Atlas::getExtendedEventContext(ctx).proxy())
442 * @brief Constructor.
443 * @param uid Unique ID of the target particle. 0 means a null link.
444 * @param eventIndex Identifies the target GenEvent in a McEventCollection,
445 * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
446 * or the position in the container
447 * if isIndexEventPosition is IS_POSITION.
448 * 0 always means the first event in the collection.
449 * @param positionFlag: See @c eventIndex.
450 * @param sg Optional specification of a specific store to reference.
453 HepMcParticleLink::HepMcParticleLink (barcode_type uid,
454 uint32_t eventIndex /*= 0*/,
455 PositionFlag positionFlag /*= IS_EVENTNUM*/,
456 UniqueIDFlag uniqueIDFlag /*= IS_ID*/,
457 IProxyDict* sg /*= SG::CurrentEventStore::store()*/)
459 m_extBarcode (uid, eventIndex, positionFlag, uniqueIDFlag)
465 * @brief Constructor.
466 * @param uid Unique ID of the target particle. 0 means a null link.
467 * @param eventIndex Identifies the target GenEvent in a McEventCollection,
468 * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
469 * or the position in the container
470 * if isIndexEventPosition is IS_POSITION.
471 * 0 always means the first event in the collection.
472 * @param positionFlag: See @c eventIndex.
473 * @param ctx Context of the store to reference.
476 HepMcParticleLink::HepMcParticleLink (barcode_type uid,
478 PositionFlag positionFlag,
479 UniqueIDFlag uniqueIDFlag,
480 const EventContext& ctx)
481 : HepMcParticleLink (uid, eventIndex, positionFlag, uniqueIDFlag,
482 Atlas::getExtendedEventContext(ctx).proxy())
488 * @brief Constructor.
489 * @param p Particle to reference.
490 * @param eventIndex Identifies the target GenEvent in a McEventCollection,
491 * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
492 * or the position in the container
493 * if isIndexEventPosition is IS_POSITION.
494 * 0 always means the first event in the collection.
495 * @param positionFlag: See @c eventIndex.
496 * @param ctx Context of the store to reference.
499 HepMcParticleLink::HepMcParticleLink (const HepMC::ConstGenParticlePtr& part,
501 PositionFlag positionFlag,
502 const EventContext& ctx)
503 : HepMcParticleLink (part, eventIndex, positionFlag,
504 Atlas::getExtendedEventContext(ctx).proxy())
509 * @brief Dereference.
512 const HepMC::GenParticle& HepMcParticleLink::operator* () const
519 * @brief Dereference.
522 HepMC::ConstGenParticlePtr HepMcParticleLink::operator->() const
529 * @brief Dereference.
532 HepMcParticleLink::operator HepMC::ConstGenParticlePtr() const
539 * @brief Validity check. Dereference and check for null.
542 bool HepMcParticleLink::isValid() const
544 return (nullptr != cptr());
549 * @brief Validity check. Dereference and check for null.
552 bool HepMcParticleLink::operator!() const
559 * @brief Validity check. Dereference and check for null.
562 HepMcParticleLink::operator bool() const
569 * @brief Equality comparison.
572 bool HepMcParticleLink::operator== (const HepMcParticleLink& rhs) const
574 return (m_extBarcode.getTruthSuppressionType()==rhs.m_extBarcode.getTruthSuppressionType() &&
575 ExtendedBarCode::compareUniqueID(*this, rhs) == 0 &&
576 ExtendedBarCode::compareIndex (*this, rhs) == 0);
581 * @brief Inequality comparison.
584 bool HepMcParticleLink::operator!= (const HepMcParticleLink& rhs) const
586 return !(operator==(rhs));
591 * @brief Ordering comparison.
594 bool HepMcParticleLink::operator< (const HepMcParticleLink& rhs) const
596 if (m_extBarcode.getTruthSuppressionType() < rhs.m_extBarcode.getTruthSuppressionType()) return true;
597 if (m_extBarcode.getTruthSuppressionType() == rhs.m_extBarcode.getTruthSuppressionType()) {
598 int cmpIndex = ExtendedBarCode::compareIndex (*this, rhs);
599 if (cmpIndex < 0) return true;
601 if (ExtendedBarCode::compareUniqueID(*this, rhs) < 0) return true;
609 * @brief Return whether the truth particle has been suppressed, as an enum.
612 EBC_SUPPRESSED_TRUTH HepMcParticleLink::getTruthSuppressionType() const
614 return m_extBarcode.getTruthSuppressionType();
619 * @brief Return whether the truth particle has been suppressed.
621 inline void HepMcParticleLink::setTruthSuppressionType(EBC_SUPPRESSED_TRUTH truthSupp)
623 m_extBarcode.setTruthSuppressionType(truthSupp);
628 * @brief Return whether the truth particle has been suppressed, as a char ('a'..'b').
631 char HepMcParticleLink::getTruthSuppressionTypeAsChar() const
633 return m_extBarcode.getTruthSuppressionTypeAsChar();
638 * @brief Hash the 32-bit barcode and 16-bit eventindex into a 32bit int.
641 HepMcParticleLink::barcode_type HepMcParticleLink::compress() const
643 return ( ((m_extBarcode.uid()&0xFFFF) << 16) |
649 * @brief Comparison with ConstGenParticlePtr.
650 * Needed with c++20 to break an ambiguity.
653 bool operator== (HepMC::ConstGenParticlePtr a,
654 const HepMcParticleLink& b)
656 return a == b.cptr();