ATLAS Offline Software
HepMcParticleLink.icc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration.
3  */
4 /**
5  * @file GeneratorObjects/HepMcParticleLink.icc
6  * @author scott snyder <snyder@bnl.gov>
7  * @date Feb, 2019
8  * @brief a link optimized in size for a GenParticle in a McEventCollection
9  */
10 
11 
12 //**************************************************************************
13 // ExtendedBarCode
14 //
15 
16 inline
17 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode()
18 {
19 }
20 
21 
22 /**
23  * @brief Constructor.
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.
31  */
32 inline
33 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode
34  (barcode_type uid,
35  index_type eventIndex,
36  PositionFlag isIndexEventPosition /*=IS_EVENTNUM*/,
37  UniqueIDFlag isUniqueIDBarcode /*= IS_ID*/)
38 {
39  setIndex (eventIndex, isIndexEventPosition);
40  setUniqueID (uid, isUniqueIDBarcode);
41 }
42 
43 
44 /**
45  * @brief Copy constructor. (Can't be defaulted due to the atomic member.)
46  */
47 inline
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)
52 {
53 }
54 
55 
56 /**
57  * @brief Move constructor. (Can't be defaulted due to the atomic member.)
58  */
59 inline
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))
64 {
65 }
66 
67 /**
68  * @brief Assignment. (Can't be defaulted due to the atomic member.)
69  */
70 inline
71 HepMcParticleLink::ExtendedBarCode&
72 HepMcParticleLink::ExtendedBarCode::operator= (const ExtendedBarCode& rhs)
73 {
74  if (this != &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;
78  }
79  return *this;
80 }
81 
82 /**
83  * @brief Assignment. (Can't be defaulted due to the atomic member.)
84  */
85 inline
86 HepMcParticleLink::ExtendedBarCode&
87 HepMcParticleLink::ExtendedBarCode::operator= (ExtendedBarCode&& rhs) noexcept
88 {
89  if (this != &rhs) {
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);
93  }
94  return *this;
95 }
96 
97 
98 /**
99  * @brief Unique ID of target variable (0 for a null link).
100  */
101 inline
102 HepMcParticleLink::barcode_type
103 HepMcParticleLink::ExtendedBarCode::uid() const
104 {
105  return m_BC;
106 }
107 
108 
109 /**
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.
113  *
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.
118  */
119 inline
120 void HepMcParticleLink::ExtendedBarCode::eventIndex (index_type& index,
121  index_type& position) const
122 {
123  index_type idx = m_evtIndex;
124  if (idx & POSITION_MASK) {
125  index = UNDEFINED;
126  position = idx & ~POSITION_MASK;
127  }
128  else {
129  index = idx;
130  position = UNDEFINED;
131  }
132 }
133 
134 
135 /**
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.
139  *
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.
144  */
145 inline
146 void HepMcParticleLink::ExtendedBarCode::uniqueID (barcode_type& id,
147  barcode_type& barcode) const
148 {
149  barcode_type uid = m_BC;
150  if (uid == 0) // special case for delta-rays
151  {
152  id = uid;
153  barcode = uid;
154  }
155  else if (uid & BARCODE_MASK) {
156  id = UNDEFINEDBC;
157  barcode = uid & ~BARCODE_MASK;
158  }
159  else {
160  id = uid;
161  barcode = UNDEFINEDBC;
162  }
163 }
164 
165 
166 /**
167  * @brief Return which collection we're targeting, as a char ('a'..'b').
168  */
169 inline
170 char HepMcParticleLink::ExtendedBarCode::getTruthSuppressionTypeAsChar() const
171 {
172  return truthSuppressionTypeAsChar (m_truthSupp);
173 }
174 
175 
176 /**
177  * @brief Equality test.
178  *
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=.
183  */
184 inline
185 bool
186 HepMcParticleLink::ExtendedBarCode::operator==(const ExtendedBarCode& rhs) const
187 {
188  return (this->m_BC == rhs.m_BC &&
189  this->m_truthSupp == rhs.m_truthSupp &&
190  this->m_evtIndex == rhs.m_evtIndex);
191 }
192 
193 
194 /**
195  * @brief Inequality test.
196  *
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=.
201  */
202 inline
203 bool
204 HepMcParticleLink::ExtendedBarCode::operator!= (const ExtendedBarCode& rhs) const
205 {
206  return !(operator==(rhs));
207 }
208 
209 
210 /**
211  * @brief Ordering test.
212  *
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=.
216  */
217 inline
218 bool
219 HepMcParticleLink::ExtendedBarCode::operator< (const ExtendedBarCode& rhs) const
220 {
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) ) ;
224 }
225 
226 
227 /**
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.
232  *
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.
237  */
238 inline
239 int
240 HepMcParticleLink::ExtendedBarCode::compareIndex (const HepMcParticleLink& lhs,
241  const HepMcParticleLink& rhs)
242 {
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;
248 
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) {
252  lhs.cptr();
253  idx1 = lhs.m_extBarcode.m_evtIndex;
254  }
255  if (idx2 & POSITION_MASK) {
256  rhs.cptr();
257  idx2 = rhs.m_extBarcode.m_evtIndex;
258  }
259 
260  // Compare.
261  if (idx1 == idx2) {
262  return 0;
263  }
264  else if (idx1 < idx2) {
265  return -1;
266  }
267  else {
268  return 1;
269  }
270 }
271 
272 
273 
274 /**
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.
279  *
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.
284  */
285 inline
286 int
287 HepMcParticleLink::ExtendedBarCode::compareUniqueID (const HepMcParticleLink& lhs,
288  const HepMcParticleLink& rhs)
289 {
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;
295 
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) {
299  lhs.cptr();
300  uid1 = lhs.m_extBarcode.m_BC;
301  }
302  if (uid2 & BARCODE_MASK) {
303  rhs.cptr();
304  uid2 = rhs.m_extBarcode.m_BC;
305  }
306  // Compare.
307  if (uid1 == uid2) {
308  return 0;
309  }
310  else if (uid1 < uid2) {
311  return -1;
312  }
313  else {
314  return 1;
315  }
316 }
317 
318 
319 /**
320  * @brief Change m_BC from barcode to ID.
321  * @param ID GenParticle::id value to set.
322  * @param barcode existing barcode value.
323  *
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.
327  *
328  * This may be called concurrently, as long as all such concurrent
329  * calls have the same arguments.
330  */
331 inline
332 void HepMcParticleLink::ExtendedBarCode::makeID (barcode_type ID,
333  barcode_type barcode) const
334 {
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);
339 }
340 
341 
342 /**
343  * @brief Change index from position to number.
344  * @param index Event number to set.
345  * @param position Existing event position.
346  *
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.
350  *
351  * This may be called concurrently, as long as all such concurrent
352  * calls have the same arguments.
353  */
354 inline
355 void HepMcParticleLink::ExtendedBarCode::makeIndex (index_type index,
356  index_type position) const
357 {
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));
362 }
363 
364 
365 /**
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().
370  */
371 inline
372 void
373 HepMcParticleLink::ExtendedBarCode::setUniqueID (barcode_type uid,
374  UniqueIDFlag barcodeFlag)
375 {
376  assert ((uid & BARCODE_MASK) == 0);
377  // For delta-rays barcode=id=0
378  if (uid != 0 && barcodeFlag == IS_BARCODE) {
379  uid |= BARCODE_MASK;
380  }
381  m_BC = uid;
382 }
383 
384 
385 /**
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.
390  */
391 inline
392 void
393 HepMcParticleLink::ExtendedBarCode::setIndex (index_type idx,
394  PositionFlag positionFlag)
395 {
396  assert ((idx & POSITION_MASK) == 0);
397  if (positionFlag == IS_POSITION) {
398  idx |= POSITION_MASK;
399  }
400  m_evtIndex = idx;
401 }
402 
403 inline bool HepMcParticleLink::ExtendedBarCode::linkIsNull() const
404 {
405  barcode_type particle_id, particle_barcode;
406  uniqueID (particle_id, particle_barcode);
407  return (
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)
411  );
412 }
413 
414 
415 //**************************************************************************
416 // HepMcParticleLink
417 //
418 
419 
420 /**
421  * @brief Default constructor. Makes a null link.
422  * @param sg Optional specification of a specific store to reference.
423  */
424 inline
425 HepMcParticleLink::HepMcParticleLink (IProxyDict* sg /*= nullptr*/)
426  : m_store (sg)
427 {
428 }
429 
430 
431 /**
432  * @brief Default constructor. Makes a null link.
433  * @param ctx Context of the store to reference.
434  */
435 inline
436 HepMcParticleLink::HepMcParticleLink (const EventContext& ctx)
437  : HepMcParticleLink (Atlas::getExtendedEventContext(ctx).proxy())
438 {
439 }
440 
441 /**
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.
451  */
452 inline
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()*/)
458  : m_store (sg),
459  m_extBarcode (uid, eventIndex, positionFlag, uniqueIDFlag)
460 {
461 }
462 
463 
464 /**
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.
474  */
475 inline
476 HepMcParticleLink::HepMcParticleLink (barcode_type uid,
477  uint32_t eventIndex,
478  PositionFlag positionFlag,
479  UniqueIDFlag uniqueIDFlag,
480  const EventContext& ctx)
481  : HepMcParticleLink (uid, eventIndex, positionFlag, uniqueIDFlag,
482  Atlas::getExtendedEventContext(ctx).proxy())
483 {
484 }
485 
486 
487 /**
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.
497  */
498 inline
499 HepMcParticleLink::HepMcParticleLink (const HepMC::ConstGenParticlePtr& part,
500  uint32_t eventIndex,
501  PositionFlag positionFlag,
502  const EventContext& ctx)
503  : HepMcParticleLink (part, eventIndex, positionFlag,
504  Atlas::getExtendedEventContext(ctx).proxy())
505 {
506 }
507 
508 /**
509  * @brief Dereference.
510  */
511 inline
512 const HepMC::GenParticle& HepMcParticleLink::operator* () const
513 {
514  return *cptr();
515 }
516 
517 
518 /**
519  * @brief Dereference.
520  */
521 inline
522 HepMC::ConstGenParticlePtr HepMcParticleLink::operator->() const
523 {
524  return cptr();
525 }
526 
527 
528 /**
529  * @brief Dereference.
530  */
531 inline
532 HepMcParticleLink::operator HepMC::ConstGenParticlePtr() const
533 {
534  return cptr();
535 }
536 
537 
538 /**
539  * @brief Validity check. Dereference and check for null.
540  */
541 inline
542 bool HepMcParticleLink::isValid() const
543 {
544  return (nullptr != cptr());
545 }
546 
547 
548 /**
549  * @brief Validity check. Dereference and check for null.
550  */
551 inline
552 bool HepMcParticleLink::operator!() const
553 {
554  return !isValid();
555 }
556 
557 
558 /**
559  * @brief Validity check. Dereference and check for null.
560  */
561 inline
562 HepMcParticleLink::operator bool() const
563 {
564  return isValid();
565 }
566 
567 
568 /**
569  * @brief Equality comparison.
570  */
571 inline
572 bool HepMcParticleLink::operator== (const HepMcParticleLink& rhs) const
573 {
574  return (m_extBarcode.getTruthSuppressionType()==rhs.m_extBarcode.getTruthSuppressionType() &&
575  ExtendedBarCode::compareUniqueID(*this, rhs) == 0 &&
576  ExtendedBarCode::compareIndex (*this, rhs) == 0);
577 }
578 
579 
580 /**
581  * @brief Inequality comparison.
582  */
583 inline
584 bool HepMcParticleLink::operator!= (const HepMcParticleLink& rhs) const
585 {
586  return !(operator==(rhs));
587 }
588 
589 
590 /**
591  * @brief Ordering comparison.
592  */
593 inline
594 bool HepMcParticleLink::operator< (const HepMcParticleLink& rhs) const
595 {
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;
600  if (cmpIndex == 0) {
601  if (ExtendedBarCode::compareUniqueID(*this, rhs) < 0) return true;
602  }
603  }
604  return false;
605 }
606 
607 
608 /**
609  * @brief Return whether the truth particle has been suppressed, as an enum.
610  */
611 inline
612 EBC_SUPPRESSED_TRUTH HepMcParticleLink::getTruthSuppressionType() const
613 {
614  return m_extBarcode.getTruthSuppressionType();
615 }
616 
617 
618 /**
619  * @brief Return whether the truth particle has been suppressed.
620  */
621 inline void HepMcParticleLink::setTruthSuppressionType(EBC_SUPPRESSED_TRUTH truthSupp)
622 {
623  m_extBarcode.setTruthSuppressionType(truthSupp);
624 }
625 
626 
627 /**
628  * @brief Return whether the truth particle has been suppressed, as a char ('a'..'b').
629  */
630 inline
631 char HepMcParticleLink::getTruthSuppressionTypeAsChar() const
632 {
633  return m_extBarcode.getTruthSuppressionTypeAsChar();
634 }
635 
636 
637 /**
638  * @brief Hash the 32-bit barcode and 16-bit eventindex into a 32bit int.
639  */
640 inline
641 HepMcParticleLink::barcode_type HepMcParticleLink::compress() const
642 {
643  return ( ((m_extBarcode.uid()&0xFFFF) << 16) |
644  eventIndex() );
645 }
646 
647 
648 /**
649  * @brief Comparison with ConstGenParticlePtr.
650  * Needed with c++20 to break an ambiguity.
651  */
652 inline
653 bool operator== (HepMC::ConstGenParticlePtr a,
654  const HepMcParticleLink& b)
655 {
656  return a == b.cptr();
657 }