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 {
52 }
53 
54 
55 /**
56  * @brief Move constructor. (Can't be defaulted due to the atomic member.)
57  */
58 inline
59 HepMcParticleLink::ExtendedBarCode::ExtendedBarCode (ExtendedBarCode&& rhs) noexcept
60  : m_BC (rhs.m_BC.load()), // no move constructor for atomics
61  m_evtIndex (rhs.m_evtIndex.load()) // no move constructor for atomics
62 {
63 }
64 
65 /**
66  * @brief Assignment. (Can't be defaulted due to the atomic member.)
67  */
68 inline
69 HepMcParticleLink::ExtendedBarCode&
70 HepMcParticleLink::ExtendedBarCode::operator= (const ExtendedBarCode& rhs)
71 {
72  if (this != &rhs) {
73  m_BC = static_cast<barcode_type> (rhs.m_BC);
74  m_evtIndex = static_cast<index_type> (rhs.m_evtIndex);
75  }
76  return *this;
77 }
78 
79 /**
80  * @brief Assignment. (Can't be defaulted due to the atomic member.)
81  */
82 inline
83 HepMcParticleLink::ExtendedBarCode&
84 HepMcParticleLink::ExtendedBarCode::operator= (ExtendedBarCode&& rhs) noexcept
85 {
86  if (this != &rhs) {
87  m_BC = static_cast<barcode_type> (rhs.m_BC.load());
88  m_evtIndex = static_cast<index_type>(rhs.m_evtIndex.load());
89  }
90  return *this;
91 }
92 
93 
94 /**
95  * @brief Unique ID of target variable (0 for a null link).
96  */
97 inline
98 HepMcParticleLink::barcode_type
99 HepMcParticleLink::ExtendedBarCode::uid() const
100 {
101  return m_BC;
102 }
103 
104 
105 /**
106  * @brief Return the event index/position.
107  * @param index[out] Event index (number), or @c UNDEFINED.
108  * @param position[out] Event position, or @c UNDEFINED.
109  *
110  * The GenEvent within the McEventCollection is identified either by
111  * the GenEvent number or by the position within the collection.
112  * This method will return this by setting either @c index or @c position;
113  * the other one is set to @c UNDEFINED.
114  */
115 inline
116 void HepMcParticleLink::ExtendedBarCode::eventIndex (index_type& index,
117  index_type& position) const
118 {
119  index_type idx = m_evtIndex;
120  if (idx & POSITION_MASK) {
121  index = UNDEFINED;
122  position = idx & ~POSITION_MASK;
123  }
124  else {
125  index = idx;
126  position = UNDEFINED;
127  }
128 }
129 
130 
131 /**
132  * @brief Return the GenParticle id/barcode.
133  * @param id[out] GenParticle::id, or @c UNDEFINEDBC.
134  * @param barcode[out] barcode (deprecated), or @c UNDEFINEDBC.
135  *
136  * The GenParticle within the GenEvent is identified either by
137  * the GenParticle::id or the barcode.
138  * This method will return this by setting either @c id or @c barcode;
139  * the other one is set to @c UNDEFINEDBC.
140  */
141 inline
142 void HepMcParticleLink::ExtendedBarCode::uniqueID (barcode_type& id,
143  barcode_type& barcode) const
144 {
145  barcode_type uid = m_BC;
146  if (uid == 0) // special case for delta-rays
147  {
148  id = uid;
149  barcode = uid;
150  }
151  else if (uid & BARCODE_MASK) {
152  id = UNDEFINEDBC;
153  barcode = uid & ~BARCODE_MASK;
154  }
155  else {
156  id = uid;
157  barcode = UNDEFINEDBC;
158  }
159 }
160 
161 
162 /**
163  * @brief Equality test.
164  *
165  * Be aware: if one EBC holds the target GenEvent by number and the
166  * other by position, then this will always return false, even if they
167  * reference the same GenEvent.
168  * To avoid this, use HepMcParticleLink::operator=.
169  */
170 inline
171 bool
172 HepMcParticleLink::ExtendedBarCode::operator==(const ExtendedBarCode& rhs) const
173 {
174  return (this->m_BC == rhs.m_BC &&
175  this->m_evtIndex == rhs.m_evtIndex);
176 }
177 
178 
179 /**
180  * @brief Inequality test.
181  *
182  * Be aware: if one EBC holds the target GenEvent by number and the
183  * other by position, then this will always return true, even if they
184  * reference the same GenEvent.
185  * To avoid this, use HepMcParticleLink::operator=.
186  */
187 inline
188 bool
189 HepMcParticleLink::ExtendedBarCode::operator!= (const ExtendedBarCode& rhs) const
190 {
191  return !(operator==(rhs));
192 }
193 
194 
195 /**
196  * @brief Ordering test.
197  *
198  * Be aware: if one EBC holds the target GenEvent by number and the
199  * other by position, then this will not work as expected.
200  * To avoid this, use HepMcParticleLink::operator=.
201  */
202 inline
203 bool
204 HepMcParticleLink::ExtendedBarCode::operator< (const ExtendedBarCode& rhs) const
205 {
206  return (
207  (m_evtIndex < rhs.m_evtIndex) ||
208  (m_evtIndex == rhs.m_evtIndex && m_BC < rhs.m_BC) ) ;
209 }
210 
211 
212 /**
213  * @brief Compare the event index part of two links.
214  * @param lhs First link to compare.
215  * @param rhs Second link to compare.
216  * @returns -1, 0, or 1, depending on the result of the comparison.
217  *
218  * The event index part of the link can be represented as either
219  * an event number or the position within the container.
220  * If necessary, the links will be normalized so that they
221  * both refer to an event number.
222  */
223 inline
224 int
225 HepMcParticleLink::ExtendedBarCode::compareIndex (const HepMcParticleLink& lhs,
226  const HepMcParticleLink& rhs)
227 {
228  // Get the stored indices. The high bit will be set of they
229  // represent a position. Do a quick test for equality.
230  index_type idx1 = lhs.m_extBarcode.m_evtIndex;
231  index_type idx2 = rhs.m_extBarcode.m_evtIndex;
232  if (idx1 == idx2) return 0;
233 
234  // Normalize the values so that they both refer to event number;
235  // this happens as a side-effect of calling cptr().
236  if (idx1 & POSITION_MASK) {
237  lhs.cptr();
238  idx1 = lhs.m_extBarcode.m_evtIndex;
239  }
240  if (idx2 & POSITION_MASK) {
241  rhs.cptr();
242  idx2 = rhs.m_extBarcode.m_evtIndex;
243  }
244 
245  // Compare.
246  if (idx1 == idx2) {
247  return 0;
248  }
249  else if (idx1 < idx2) {
250  return -1;
251  }
252  else {
253  return 1;
254  }
255 }
256 
257 
258 
259 /**
260  * @brief Compare the unique ID part of two links.
261  * @param lhs First link to compare.
262  * @param rhs Second link to compare.
263  * @returns -1, 0, or 1, depending on the result of the comparison.
264  *
265  * The unique ID part of the link can be represented as either
266  * a barcode or the id.
267  * If necessary, the links will be normalized so that they
268  * both refer to an id.
269  */
270 inline
271 int
272 HepMcParticleLink::ExtendedBarCode::compareUniqueID (const HepMcParticleLink& lhs,
273  const HepMcParticleLink& rhs)
274 {
275  // Get the stored indices. The high bit will be set of they
276  // represent a position. Do a quick test for equality.
277  barcode_type uid1 = lhs.m_extBarcode.m_BC;
278  barcode_type uid2 = rhs.m_extBarcode.m_BC;
279  if (uid1 == uid2) return 0;
280 
281  // Normalize the values so that they both refer to the id;
282  // this happens as a side-effect of calling cptr().
283  if (uid1 & BARCODE_MASK) {
284  lhs.cptr();
285  uid1 = lhs.m_extBarcode.m_BC;
286  }
287  if (uid2 & BARCODE_MASK) {
288  rhs.cptr();
289  uid2 = rhs.m_extBarcode.m_BC;
290  }
291  // Compare.
292  if (uid1 == uid2) {
293  return 0;
294  }
295  else if (uid1 < uid2) {
296  return -1;
297  }
298  else {
299  return 1;
300  }
301 }
302 
303 
304 /**
305  * @brief Change m_BC from barcode to ID.
306  * @param ID GenParticle::id value to set.
307  * @param barcode existing barcode value.
308  *
309  * If the link is currently referencing a GenParticle with @c barcode,
310  * update it so that it instead references the GenParticle
311  * with id value @c ID.
312  *
313  * This may be called concurrently, as long as all such concurrent
314  * calls have the same arguments.
315  */
316 inline
317 void HepMcParticleLink::ExtendedBarCode::makeID (barcode_type ID,
318  barcode_type barcode) const
319 {
320  assert ((ID & BARCODE_MASK) == 0);
321  barcode_type old = barcode | BARCODE_MASK;
322  m_BC.compare_exchange_strong (old, ID);
323  assert (old == (barcode|BARCODE_MASK) || old == ID);
324 }
325 
326 
327 /**
328  * @brief Change index from position to number.
329  * @param index Event number to set.
330  * @param position Existing event position.
331  *
332  * If the link is currently referencing the GenEvent at @c position,
333  * update it so that it instead references the GenEvent
334  * with number @c index.
335  *
336  * This may be called concurrently, as long as all such concurrent
337  * calls have the same arguments.
338  */
339 inline
340 void HepMcParticleLink::ExtendedBarCode::makeIndex (index_type index,
341  index_type position) const
342 {
343  assert ((index & POSITION_MASK) == 0);
344  index_type old = position | POSITION_MASK;
345  m_evtIndex.compare_exchange_strong (old, index);
346  assert (old == (position|POSITION_MASK) || old == index || (position==UNDEFINED && old==0));
347 }
348 
349 
350 /**
351  * @brief Initialize the unique identifier part of the link.
352  * @param uid The id or barcode.
353  * @param barcodeFlag If IS_BARCODE, @c uid represents a GenParticle barcode (deprecated);
354  * otherwise, it represents a GenParticle::id().
355  */
356 inline
357 void
358 HepMcParticleLink::ExtendedBarCode::setUniqueID (barcode_type uid,
359  UniqueIDFlag barcodeFlag)
360 {
361  assert ((uid & BARCODE_MASK) == 0);
362  // For delta-rays barcode=id=0
363  if (uid != 0 && barcodeFlag == IS_BARCODE) {
364  uid |= BARCODE_MASK;
365  }
366  m_BC = uid;
367 }
368 
369 
370 /**
371  * @brief Initialize the event index part of the link.
372  * @param idx The index or position.
373  * @param positionFlag If IS_POSITION, @c idx represents a position
374  * in the collection; otherwise, it represents an event number.
375  */
376 inline
377 void
378 HepMcParticleLink::ExtendedBarCode::setIndex (index_type idx,
379  PositionFlag positionFlag)
380 {
381  assert ((idx & POSITION_MASK) == 0);
382  if (positionFlag == IS_POSITION) {
383  idx |= POSITION_MASK;
384  }
385  m_evtIndex = idx;
386 }
387 
388 inline bool HepMcParticleLink::ExtendedBarCode::linkIsNull() const
389 {
390  barcode_type particle_id, particle_barcode;
391  uniqueID (particle_id, particle_barcode);
392  return (
393  (particle_id == 0 && particle_barcode == 0) || // delta rays
394  (particle_id == 0 && particle_barcode == ExtendedBarCode::UNDEFINEDBC) ||
395  (particle_id == ExtendedBarCode::UNDEFINEDBC && particle_barcode == 0)
396  );
397 }
398 
399 
400 //**************************************************************************
401 // HepMcParticleLink
402 //
403 
404 
405 /**
406  * @brief Default constructor. Makes a null link.
407  * @param sg Optional specification of a specific store to reference.
408  */
409 inline
410 HepMcParticleLink::HepMcParticleLink (IProxyDict* sg /*= nullptr*/)
411  : m_store (sg)
412 {
413 }
414 
415 
416 /**
417  * @brief Default constructor. Makes a null link.
418  * @param ctx Context of the store to reference.
419  */
420 inline
421 HepMcParticleLink::HepMcParticleLink (const EventContext& ctx)
422  : HepMcParticleLink (Atlas::getExtendedEventContext(ctx).proxy())
423 {
424 }
425 
426 /**
427  * @brief Constructor.
428  * @param uid Unique ID of the target particle. 0 means a null link.
429  * @param eventIndex Identifies the target GenEvent in a McEventCollection,
430  * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
431  * or the position in the container
432  * if isIndexEventPosition is IS_POSITION.
433  * 0 always means the first event in the collection.
434  * @param positionFlag: See @c eventIndex.
435  * @param sg Optional specification of a specific store to reference.
436  */
437 inline
438 HepMcParticleLink::HepMcParticleLink (barcode_type uid,
439  uint32_t eventIndex /*= 0*/,
440  PositionFlag positionFlag /*= IS_EVENTNUM*/,
441  UniqueIDFlag uniqueIDFlag /*= IS_ID*/,
442  IProxyDict* sg /*= SG::CurrentEventStore::store()*/)
443  : m_store (sg),
444  m_extBarcode (uid, eventIndex, positionFlag, uniqueIDFlag)
445 {
446 }
447 
448 
449 /**
450  * @brief Constructor.
451  * @param uid Unique ID of the target particle. 0 means a null link.
452  * @param eventIndex Identifies the target GenEvent in a McEventCollection,
453  * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
454  * or the position in the container
455  * if isIndexEventPosition is IS_POSITION.
456  * 0 always means the first event in the collection.
457  * @param positionFlag: See @c eventIndex.
458  * @param ctx Context of the store to reference.
459  */
460 inline
461 HepMcParticleLink::HepMcParticleLink (barcode_type uid,
462  uint32_t eventIndex,
463  PositionFlag positionFlag,
464  UniqueIDFlag uniqueIDFlag,
465  const EventContext& ctx)
466  : HepMcParticleLink (uid, eventIndex, positionFlag, uniqueIDFlag,
467  Atlas::getExtendedEventContext(ctx).proxy())
468 {
469 }
470 
471 
472 /**
473  * @brief Constructor.
474  * @param p Particle to reference.
475  * @param eventIndex Identifies the target GenEvent in a McEventCollection,
476  * as either the event number if @c isIndexEventPosition is IS_EVENTNUM,
477  * or the position in the container
478  * if isIndexEventPosition is IS_POSITION.
479  * 0 always means the first event in the collection.
480  * @param positionFlag: See @c eventIndex.
481  * @param ctx Context of the store to reference.
482  */
483 inline
484 HepMcParticleLink::HepMcParticleLink (const HepMC::ConstGenParticlePtr& part,
485  uint32_t eventIndex,
486  PositionFlag positionFlag,
487  const EventContext& ctx)
488  : HepMcParticleLink (part, eventIndex, positionFlag,
489  Atlas::getExtendedEventContext(ctx).proxy())
490 {
491 }
492 
493 /**
494  * @brief Dereference.
495  */
496 inline
497 const HepMC::GenParticle& HepMcParticleLink::operator* () const
498 {
499  return *cptr();
500 }
501 
502 
503 /**
504  * @brief Dereference.
505  */
506 inline
507 HepMC::ConstGenParticlePtr HepMcParticleLink::operator->() const
508 {
509  return cptr();
510 }
511 
512 
513 /**
514  * @brief Dereference.
515  */
516 inline
517 HepMcParticleLink::operator HepMC::ConstGenParticlePtr() const
518 {
519  return cptr();
520 }
521 
522 
523 /**
524  * @brief Validity check. Dereference and check for null.
525  */
526 inline
527 bool HepMcParticleLink::isValid() const
528 {
529  return (nullptr != cptr());
530 }
531 
532 
533 /**
534  * @brief Validity check. Dereference and check for null.
535  */
536 inline
537 bool HepMcParticleLink::operator!() const
538 {
539  return !isValid();
540 }
541 
542 
543 /**
544  * @brief Validity check. Dereference and check for null.
545  */
546 inline
547 HepMcParticleLink::operator bool() const
548 {
549  return isValid();
550 }
551 
552 
553 /**
554  * @brief Equality comparison.
555  */
556 inline
557 bool HepMcParticleLink::operator== (const HepMcParticleLink& rhs) const
558 {
559  return (ExtendedBarCode::compareUniqueID(*this, rhs) == 0 &&
560  ExtendedBarCode::compareIndex (*this, rhs) == 0);
561 }
562 
563 
564 /**
565  * @brief Inequality comparison.
566  */
567 inline
568 bool HepMcParticleLink::operator!= (const HepMcParticleLink& rhs) const
569 {
570  return !(operator==(rhs));
571 }
572 
573 
574 /**
575  * @brief Ordering comparison.
576  */
577 inline
578 bool HepMcParticleLink::operator< (const HepMcParticleLink& rhs) const
579 {
580  int cmpIndex = ExtendedBarCode::compareIndex (*this, rhs);
581  if (cmpIndex < 0) return true;
582  if (cmpIndex == 0) {
583  if (ExtendedBarCode::compareUniqueID(*this, rhs) < 0) return true;
584  }
585  return false;
586 }
587 
588 
589 /**
590  * @brief Hash the 32-bit barcode and 16-bit eventindex into a 32bit int.
591  */
592 inline
593 HepMcParticleLink::barcode_type HepMcParticleLink::compress() const
594 {
595  return ( ((m_extBarcode.uid()&0xFFFF) << 16) |
596  eventIndex() );
597 }
598 
599 
600 /**
601  * @brief Comparison with ConstGenParticlePtr.
602  * Needed with c++20 to break an ambiguity.
603  */
604 inline
605 bool operator== (HepMC::ConstGenParticlePtr a,
606  const HepMcParticleLink& b)
607 {
608  return a == b.cptr();
609 }