ATLAS Offline Software
Loading...
Searching...
No Matches
BunchCrossingToolBase.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5
6
7// Local include(s):
9#include "SetPrint.h"
11
12// STL include(s):
13#include <algorithm>
14#include <functional>
15#include <cmath>
16
17namespace Trig {
18
24 : asg::AsgMetadataTool( name ),
27
29 declareProperty( "MaxBunchSpacing", m_maxBunchSpacing = 150 );
30 declareProperty( "FrontLength", m_frontLength = 300 );
31 declareProperty( "TailLength", m_tailLength = 300 );
32 }
33
35
36 // Check if this is a filled bunch crossing:
37 if( m_filledBunches.find( bcid ) != m_filledBunches.end() ) {
38 return true;
39 } else {
40 return false;
41 }
42 }
43
45
46 // Look for this BCID in the list of bunch trains:
47 std::set< BunchTrain >::const_iterator itr = m_bunchTrains.begin();
48 std::set< BunchTrain >::const_iterator end = m_bunchTrains.end();
49 for( ; itr != end; ++itr ) {
50 if( itr->find( bcid ) != itr->end() ) {
51 return true;
52 }
53 }
54
55 return false;
56 }
57
59
60 // Check if this is an unpaired bunch crossing:
61 if( m_unpairedBunches.find( bcid ) != m_unpairedBunches.end() ) {
62 return true;
63 } else {
64 return false;
65 }
66 }
67
69
70 // Check if this is a filled bunch:
71 std::set< BunchCrossing >::const_iterator itr_fill =
72 m_filledBunches.find( bcid );
73 if( itr_fill != m_filledBunches.end() ) {
74 return true;
75 }
76
77 // Check if this is an unpaired bunch with the bunch in beam 1:
78 std::set< BunchCrossing >::const_iterator itr_unp =
79 m_unpairedBunches.find( bcid );
80 if( ( itr_unp != m_unpairedBunches.end() ) &&
81 ( itr_unp->intensityBeam1() > 0.001 ) ) {
82 return true;
83 } else {
84 return false;
85 }
86 }
87
89
90 // Check if this is a filled bunch:
91 std::set< BunchCrossing >::const_iterator itr_fill =
92 m_filledBunches.find( bcid );
93 if( itr_fill != m_filledBunches.end() ) {
94 return true;
95 }
96
97 // Check if this is an unpaired bunch with the bunch in beam 1:
98 std::set< BunchCrossing >::const_iterator itr_unp =
99 m_unpairedBunches.find( bcid );
100 if( ( itr_unp != m_unpairedBunches.end() ) &&
101 ( itr_unp->intensityBeam2() > 0.001 ) ) {
102 return true;
103 } else {
104 return false;
105 }
106 }
107
109 BeamType type ) const {
110
111 // Check if this is a colliding bunch:
112 std::set< BunchCrossing >::const_iterator itr;
113 if( ( itr = m_filledBunches.find( bcid ) ) != m_filledBunches.end() ) {
114 switch( type ) {
115 case Crossing:
116 if( itr->intensityBeam2() > 0.001 ) {
117 ATH_MSG_WARNING( "Crossing intensity not available, ask for "
118 << "separate beam intensities instead" );
119 return 0.0;
120 } else {
121 return itr->intensityBeam1();
122 }
123 case Beam1:
124 if( std::abs( itr->intensityBeam2() ) < 0.001 ) {
125 ATH_MSG_WARNING( "Separate beam intensities not available, ask "
126 << "for the crossing intensity instead" );
127 return 0.0;
128 } else {
129 return itr->intensityBeam1();
130 }
131 break;
132 case Beam2:
133 return itr->intensityBeam2();
134 break;
135 default:
136 ATH_MSG_ERROR( "Unknown intensity type requested (" << type
137 << ")" );
138 return -1.0;
139 }
140 }
141
142 // Check if this is an unpaired bunch:
143 if( ( itr = m_unpairedBunches.find( bcid ) ) !=
144 m_unpairedBunches.end() ) {
145 switch( type ) {
146 case Beam1:
147 return itr->intensityBeam1();
148 break;
149 case Beam2:
150 return itr->intensityBeam2();
151 break;
152 case Crossing:
153 ATH_MSG_WARNING( "Crossing intensity requested for unpaired bunch ("
154 << "bcid=" << bcid << ")" );
155 return 0.0;
156 default:
157 ATH_MSG_ERROR( "Unknown intensity type requested (" << type
158 << ")" );
159 return -1.0;
160 }
161 }
162
163 // If neither, then its intensity is 0.0 by definition:
164 return 0.0;
165 }
166
169
170 // First the obvious check:
171 if( ! isFilled( bcid ) ) {
172 // Check if it's an unpaired bunch:
173 if( isUnpaired( bcid ) ) {
174 return Unpaired;
175 }
176 // If the previous bunch crossing is the tail of a bunch train:
177 if( ! distanceFromTail( bcid - 1, BunchCrossings ) ) {
178 return FirstEmpty;
179 }
180 // Check if it's in the middle of a bunch train:
181 std::set< BunchTrain >::const_iterator itr = m_bunchTrains.begin();
182 std::set< BunchTrain >::const_iterator end = m_bunchTrains.end();
183 for( ; itr != end; ++itr ) {
184 if( itr->isInside( bcid ) ) {
185 return MiddleEmpty;
186 }
187 }
188 // If none of the above are true, it has to be a "simple" empty bunch:
189 return Empty;
190 }
191
192 // Now we know that the bunch has to be a filled one...
193
194 // If it's not in a train, it has to be a single filled bunch:
195 if( ! isInTrain( bcid ) ) return Single;
196
197 // Let's check if it is close to the front of a bunch train:
198 int distance = distanceFromFront( bcid, NanoSec );
199 if( ( distance >= 0 ) && ( distance <= m_frontLength ) ) {
200 return Front;
201 }
202 // Now let's check if it's close to the tail of a bunch train:
204 if( ( distance >= 0 ) && ( distance <= m_tailLength ) ) {
205 return Tail;
206 }
207
208 // If none of the above are true, it has to be in the middle of a train:
209 return Middle;
210 }
211
240 int
242 BunchDistanceType type ) const {
243
244 // Look for this BCID in the list of bunch trains:
245 std::set< BunchTrain >::const_iterator itr = m_bunchTrains.begin();
246 std::set< BunchTrain >::const_iterator end = m_bunchTrains.end();
247 for( ; itr != end; ++itr ) {
248 BunchTrain::const_iterator element;
249 if( ( element = itr->find( bcid ) ) != itr->end() ) {
250 switch( type ) {
251
252 case NanoSec:
254 *( itr->train_front() ) );
255 break;
256 case BunchCrossings:
257 return ( BunchCrossing( bcid ) - *( itr->train_front() ) );
258 break;
259 case FilledBunches:
260 if( *( itr->train_front() ) > *( itr->train_back() ) ) {
261 if( BunchCrossing( bcid ) <= *( itr->train_back() ) ) {
262 return ( std::count_if( itr->begin(), element,
263 std::bind( std::not_equal_to< BunchCrossing >(),
264 *element, std::placeholders::_1 ) ) +
265 std::count_if( itr->train_front(), itr->end(),
266 std::bind( std::not_equal_to< BunchCrossing >(),
267 *element, std::placeholders::_1 ) ) );
268 } else {
269 return std::count_if( itr->train_front(), element,
270 std::bind( std::not_equal_to< BunchCrossing >(),
271 *element, std::placeholders::_1 ) );
272 }
273 } else {
274 return std::count_if( itr->begin(), element,
275 std::bind( std::not_equal_to< BunchCrossing >(),
276 *element, std::placeholders::_1 ) );
277 }
278 break;
279 default:
280 ATH_MSG_ERROR( "BunchDistanceType not understood!" );
281 return -1;
282 }
283 }
284 }
285
286 // If the bunch crossing is not part of a train:
287 return -1;
288 }
289
319 BunchDistanceType type ) const {
320
321 // Look for this BCID in the list of bunch trains:
322 std::set< BunchTrain >::const_iterator itr = m_bunchTrains.begin();
323 std::set< BunchTrain >::const_iterator end = m_bunchTrains.end();
324 for( ; itr != end; ++itr ) {
325 BunchTrain::const_iterator element;
326 if( ( element = itr->find( bcid ) ) != itr->end() ) {
327 switch( type ) {
328
329 case NanoSec:
330 return BunchCrossing::BUNCH_SPACING * ( *( itr->train_back() ) -
331 BunchCrossing( bcid ) );
332 break;
333 case BunchCrossings:
334 return ( *( itr->train_back() ) - BunchCrossing( bcid ) );
335 break;
336 case FilledBunches:
337 if( *( itr->train_front() ) > *( itr->train_back() ) ) {
338 if( BunchCrossing( bcid ) > *( itr->train_back() ) ) {
339 return ( std::count_if( element, itr->end(),
340 std::bind( std::not_equal_to< BunchCrossing >(),
341 *element, std::placeholders::_1 ) ) +
342 std::count_if( itr->begin(), ++( itr->train_back() ),
343 std::bind( std::not_equal_to< BunchCrossing >(),
344 *element, std::placeholders::_1 ) ) );
345 } else {
346 return std::count_if( element, ++( itr->train_back() ),
347 std::bind( std::not_equal_to< BunchCrossing >(),
348 *element, std::placeholders::_1 ) );
349 }
350 } else {
351 return std::count_if( element, itr->end(),
352 std::bind( std::not_equal_to< BunchCrossing >(),
353 *element, std::placeholders::_1 ) );
354 }
355 break;
356 default:
357 ATH_MSG_ERROR( "BunchDistanceType not understood!" );
358 return -1;
359 }
360 }
361 }
362
363 // If the bunch crossing is not part of a train:
364 return -1;
365 }
366
377 const auto train = std::ranges::find_if(m_bunchTrains,
378 [bcid](const BunchTrain& bunchTrain) {
379 return bunchTrain.contains(bcid);
380 });
381 // If we didn't find this BCID in a train, let's return right away:
382 if( train == m_bunchTrains.end() ) {
383 return -1;
384 }
385 // Search for the first filled bunch before the front of this train:
386 BunchCrossing trainFront = *train->train_front();
387 BunchCrossing prevFilled = trainFront;
388 while (!isFilled(--prevFilled));
389 auto dist = train->train_front()->distance( prevFilled );
390 // Now return the results:
391 switch( type ) {
392 case NanoSec:
393 return BunchCrossing::BUNCH_SPACING * dist;
394 break;
395 case BunchCrossings:
396 return dist;
397 break;
398 default:
399 ATH_MSG_ERROR( "You can only use NanoSec or BunchCrossings for type "
400 "for gapBeforeTrain" );
401 return -1;
402 }
403 }
404
415 const auto train = std::ranges::find_if(m_bunchTrains,
416 [bcid](const BunchTrain& bunchTrain) {
417 return bunchTrain.contains(bcid);
418 });
419 // If we didn't find this BCID in a train, let's return right away:
420 if( train == m_bunchTrains.end() ) {
421 return -1;
422 }
423 // Search for the first filled bunch after the back of this train:
424 BunchCrossing train_front = *( train->train_back() );
425 do {++train_front; } while (!isFilled(train_front));
426 const auto dist = train_front.distance(*train->train_back());
427 // Now return the results:
428 switch( type ) {
429 case NanoSec:
430 return BunchCrossing::BUNCH_SPACING * dist;
431 break;
432 case BunchCrossings:
433 return dist;
434 break;
435 default:
436 ATH_MSG_ERROR( "You can only use NanoSec or BunchCrossings for type "
437 "for gapAfterTrain" );
438 return -1;
439 }
440 }
441
455 BunchDistanceType dtype,
456 BunchFillType ftype ) const {
457
458 // Construct this "smart" BCID:
459 const BunchCrossing bunch( bcid );
460
461 // Search for the first previous bunch that fulfills the requirement:
462 BunchCrossing prev_bunch( bunch );
463 --prev_bunch;
464 int loop_counter = 0;
465 switch( ftype ) {
466
467 case CollidingBunch:
468 // There should always be filled bunches in the configuration, but
469 // let's make sure that we don't get into an endless loop:
470 while( ( ! isFilled( prev_bunch ) ) &&
471 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
472 --prev_bunch;
473 ++loop_counter;
474 }
475 if( loop_counter == BunchCrossing::MAX_BCID ) {
476 ATH_MSG_ERROR( "Failed to calculate gap before BCID "
477 << bcid << " to a filled bunch! This shouldn't have "
478 << "happened!" );
479 return -1;
480 }
481 break;
482 case UnpairedBunch:
483 // There are no unpaired bunches in every configuration, so make sure
484 // we don't get into an endless loop:
485 while( ( ! isUnpaired( prev_bunch ) ) &&
486 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
487 --prev_bunch;
488 ++loop_counter;
489 }
490 // Return "-1" if there are no unpaired bunches in the configuration:
491 if( loop_counter == BunchCrossing::MAX_BCID ) {
492 return -1;
493 }
494 break;
495 case UnpairedBeam1:
496 // There are no unpaired bunches from beam 1 in every configuration, so
497 // make sure we don't get into an endless loop:
498 while( ( ! ( isUnpaired( prev_bunch ) && isBeam1( prev_bunch ) ) ) &&
499 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
500 --prev_bunch;
501 ++loop_counter;
502 }
503 // Return "-1" if there are no unpaired bunches from beam 1 in the
504 // configuration:
505 if( loop_counter == BunchCrossing::MAX_BCID ) {
506 return -1;
507 }
508 break;
509 case UnpairedBeam2:
510 // There are no unpaired bunches from beam 2 in every configuration, so
511 // make sure we don't get into an endless loop:
512 while( ( ! ( isUnpaired( prev_bunch ) && isBeam2( prev_bunch ) ) ) &&
513 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
514 --prev_bunch;
515 ++loop_counter;
516 }
517 // Return "-1" if there are no unpaired bunches from beam 2 in the
518 // configuration:
519 if( loop_counter == BunchCrossing::MAX_BCID ) {
520 return -1;
521 }
522 break;
523 case EmptyBunch:
524 // There should always be empty bunches in the configuration, but let's
525 // make sure that we don't get into an endless loop:
526 while( ( isFilled( prev_bunch ) || isUnpaired( prev_bunch ) ) &&
527 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
528 --prev_bunch;
529 ++loop_counter;
530 }
531 if( loop_counter == BunchCrossing::MAX_BCID ) {
532 ATH_MSG_ERROR( "Failed to calculate gap before BCID "
533 << bcid << " to an empty bunch! This shouldn't have "
534 << "happened!" );
535 return -1;
536 }
537 break;
538 default:
539 ATH_MSG_ERROR( "Unknown bunch fill type specified: "
540 << ftype );
541 return -1;
542 }
543
544 // Now return the results:
545 switch( dtype ) {
546
547 case NanoSec:
548 return BunchCrossing::BUNCH_SPACING * bunch.gapFrom( prev_bunch );
549 break;
550 case BunchCrossings:
551 return bunch.gapFrom( prev_bunch );
552 break;
553 default:
554 ATH_MSG_ERROR( "You can only use NanoSec or BunchCrossings for type "
555 "for gapBeforeBunch" );
556 return -1;
557 }
558
559 // This should actually never be reached:
560 return -1;
561 }
562
576 BunchDistanceType dtype,
577 BunchFillType ftype ) const {
578
579 // Construct this "smart" BCID:
580 const BunchCrossing bunch( bcid );
581
582 // Search for the first next bunch that fulfills the requirement:
583 BunchCrossing next_bunch( bunch );
584 ++next_bunch;
585 int loop_counter = 0;
586 switch( ftype ) {
587
588 case CollidingBunch:
589 // There should always be filled bunches in the configuration, but
590 // let's make sure that we don't get into an endless loop:
591 while( ( ! isFilled( next_bunch ) ) &&
592 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
593 ++next_bunch;
594 ++loop_counter;
595 }
596 if( loop_counter == BunchCrossing::MAX_BCID ) {
597 ATH_MSG_ERROR( "Failed to calculate gap after BCID "
598 << bcid << " to a filled bunch! This shouldn't have "
599 << "happened!" );
600 return -1;
601 }
602 break;
603 case UnpairedBunch:
604 // There are no unpaired bunches in every configuration, so make sure
605 // we don't get into an endless loop:
606 while( ( ! isUnpaired( next_bunch ) ) &&
607 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
608 ++next_bunch;
609 ++loop_counter;
610 }
611 // Return "-1" if there are no unpaired bunches in the configuration:
612 if( loop_counter == BunchCrossing::MAX_BCID ) {
613 return -1;
614 }
615 break;
616 case UnpairedBeam1:
617 // There are no unpaired bunches from beam 1 in every configuration, so
618 // make sure we don't get into an endless loop:
619 while( ( ! ( isUnpaired( next_bunch ) && isBeam1( next_bunch ) ) ) &&
620 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
621 ++next_bunch;
622 ++loop_counter;
623 }
624 // Return "-1" if there are no unpaired bunches from beam 1 in the
625 // configuration:
626 if( loop_counter == BunchCrossing::MAX_BCID ) {
627 return -1;
628 }
629 break;
630 case UnpairedBeam2:
631 // There are no unpaired bunches from beam 2 in every configuration, so
632 // make sure we don't get into an endless loop:
633 while( ( ! ( isUnpaired( next_bunch ) && isBeam2( next_bunch ) ) ) &&
634 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
635 ++next_bunch;
636 ++loop_counter;
637 }
638 // Return "-1" if there are no unpaired bunches from beam 2 in the
639 // configuration:
640 if( loop_counter == BunchCrossing::MAX_BCID ) {
641 return -1;
642 }
643 break;
644 case EmptyBunch:
645 // There should always be empty bunches in the configuration, but let's
646 // make sure that we don't get into an endless loop:
647 while( ( isFilled( next_bunch ) || isUnpaired( next_bunch ) ) &&
648 ( loop_counter < BunchCrossing::MAX_BCID ) ) {
649 ++next_bunch;
650 ++loop_counter;
651 }
652 if( loop_counter == BunchCrossing::MAX_BCID ) {
653 ATH_MSG_ERROR( "Failed to calculate gap after BCID "
654 << bcid << " to an empty bunch! This shouldn't have "
655 << "happened!" );
656 return -1;
657 }
658 break;
659 default:
660 ATH_MSG_ERROR( "Unknown bunch fill type specified: "
661 << ftype );
662 return -1;
663 }
664
665 // Now return the results:
666 switch( dtype ) {
667
668 case NanoSec:
669 return BunchCrossing::BUNCH_SPACING * bunch.gapTo( next_bunch );
670 break;
671 case BunchCrossings:
672 return bunch.gapTo( next_bunch );
673 break;
674 default:
675 ATH_MSG_ERROR( "You can only use NanoSec or BunchCrossings for type "
676 "for gapBeforeBunch" );
677 return -1;
678 }
679
680 // This should actually never be reached:
681 return -1;
682 }
683
684 std::vector< bool >
686 int bunches ) const {
687
688 // The only thing we have to be careful about is the bunches near the
689 // "turnover" region of the BCIDs. That's why I use the BunchCrossing
690 // class here:
691 std::vector< bool > result;
692 for( int i = 0; i < bunches; ++i ) {
693 result.push_back( isFilled( BunchCrossing( bcid ) -
694 BunchCrossing( i ) ) );
695 }
696
697 return result;
698 }
699
700 std::vector< bool >
702 int bunches ) const {
703
704 // The only thing we have to be careful about is the bunches near the
705 // "turnover" region of the BCIDs. That's why I use the BunchCrossing
706 // class here:
707 std::vector< bool > result;
708 for( int i = 0; i < bunches; ++i ) {
709 result.push_back( isFilled( BunchCrossing( bcid ) +
710 BunchCrossing( i ) ) );
711 }
712
713 return result;
714 }
715
716 std::vector< float >
718 int bunches,
719 BeamType type ) const {
720
721 std::vector< float > result;
722 for( int i = 0; i < bunches; ++i ) {
723 std::set< BunchCrossing >::const_iterator itr =
724 m_filledBunches.find( BunchCrossing( bcid ) - BunchCrossing( i ) );
725 if( itr != m_filledBunches.end() ) {
726 switch( type ) {
727 case Beam1:
728 case Crossing:
729 result.push_back( itr->intensityBeam1() );
730 break;
731 case Beam2:
732 result.push_back( itr->intensityBeam2() );
733 break;
734 default:
735 ATH_MSG_ERROR( "Unknown intensity type requested ("
736 << type << ")" );
737 return result;
738 }
739 } else {
740 result.push_back( 0.0 );
741 }
742 }
743
744 return result;
745 }
746
747 std::vector< float >
749 int bunches,
750 BeamType type ) const {
751
752 std::vector< float > result;
753 for( int i = 0; i < bunches; ++i ) {
754 std::set< BunchCrossing >::const_iterator itr =
755 m_filledBunches.find( BunchCrossing( bcid ) + BunchCrossing( i ) );
756 if( itr != m_filledBunches.end() ) {
757 switch( type ) {
758 case Beam1:
759 case Crossing:
760 result.push_back( itr->intensityBeam1() );
761 break;
762 case Beam2:
763 result.push_back( itr->intensityBeam2() );
764 break;
765 default:
766 ATH_MSG_ERROR( "Unknown intensity type requested ("
767 << type << ")" );
768 return result;
769 }
770 } else {
771 result.push_back( 0.0 );
772 }
773 }
774
775 return result;
776 }
777
779
780 return m_filledBunches.size();
781 }
782
784
785 return m_unpairedBunches.size();
786 }
787
789
790 return m_bunchTrains.size();
791 }
792
793 int
795
796 // Check if there are bunch trains in the current configurations:
797 if( m_bunchTrains.size() ) {
798 switch( type ) {
799 case NanoSec:
800 return m_bunchTrains.begin()->spacing();
801 break;
802 case BunchCrossings:
803 return ( m_bunchTrains.begin()->spacing() /
805 break;
806 case FilledBunches:
807 ATH_MSG_ERROR( "Function should not be called with argument: "
808 "FilledBunches" );
809 return -1;
810 break;
811 default:
812 ATH_MSG_ERROR( "Function called with unknown argument: " << type );
813 return -1;
814 }
815 } else {
816 // Return -1 if there are no bunch trains in the configuration:
817 return -1;
818 }
819
820 ATH_MSG_FATAL( "The code should never reach this line. Check the code!" );
821 return -1;
822 }
823
838 loadSingleBunches( const std::vector< int >& bunches,
839 const std::vector< float >& bunch_int1,
840 const std::vector< float >& bunch_int2 ) {
841
842 // Do a small sanity check:
843 if( ( ( bunches.size() != bunch_int1.size() ) && bunch_int1.size() ) ||
844 ( ( bunches.size() != bunch_int2.size() ) && bunch_int2.size() ) ) {
845 ATH_MSG_ERROR( "Received vectors of different sizes for the bunch "
846 "IDs and bunch intensities\n"
847 "Function can not work like this..." );
848 return StatusCode::FAILURE;
849 }
850 if( ! bunch_int1.size() ) {
851 ATH_MSG_DEBUG( "Not using bunch intensity for the calculation" );
852 }
853 if( ( ! bunch_int2.size() ) && bunch_int1.size() ) {
854 ATH_MSG_DEBUG( "Using 'bunch crossing intensity' for the "
855 "calculation" );
856 }
857
858 //
859 // Calculate the allowed maximum BCID separation between single bunches:
860 //
861 const int maxBCSpacing = bunchSpacing( bunches );
862
863 // Reset the cache:
864 m_filledBunches.clear();
865 m_singleBunches.clear();
866
867 //
868 // Loop over the paired bunch crossings:
869 //
870 std::vector< int >::const_iterator b_itr = bunches.begin();
871 std::vector< int >::const_iterator b_end = bunches.end();
872 std::vector< float >::const_iterator i1_itr = bunch_int1.begin();
873 std::vector< float >::const_iterator i2_itr = bunch_int2.begin();
874 for( ; b_itr != b_end; ++b_itr ) {
875
876 // Evaluate the intensity of this paired bunch:
877 const float intensity1 = bunch_int1.size() ? *i1_itr : 1.0;
878 const float intensity2 = bunch_int2.size() ? *i2_itr : 0.0;
879
880 // It's definitely a filled bunch, so let's remember it as such:
881 m_filledBunches.insert( BunchCrossing( *b_itr, intensity1,
882 intensity2 ) );
883
884 ATH_MSG_VERBOSE( "Evaluating bunch crossing: " << *b_itr );
885
886 //
887 // This expression counts how many of the paired bunches fulfill:
888 //
889 // distance( ref_bcid, bcid ) <= maxBCSpacing
890 //
891 // Since the calculation takes the reference bcid into account as well,
892 // the count is always >= 1. I have to use the specialised
893 // distance(...) function, because a regular
894 //
895 // bcid - maxBCSpacing <= ref_bcid <= bcid + maxBCSpacing
896 //
897 // expression wouldn't give the correct answer at the "turnover" of the
898 // bcid numbering. (When evaluating bcid 1 and
899 // BunchCrossing::MAX_BCID.)
900 //
901 const int neighbours =
902 std::count_if( bunches.begin(), bunches.end(),
903 [ maxBCSpacing, &b_itr ]( int bunch ) {
904 return ( Trig::distance( bunch, *b_itr ) <=
905 maxBCSpacing );
906 } );
907
908 //
909 // Now decide if we want to consider this bunch crossing as a single
910 // bunch or not:
911 //
912 ATH_MSG_VERBOSE( " Bunch neighbours: " << neighbours );
913 if( neighbours == 1 ) {
914 ATH_MSG_VERBOSE( " Bunch crossing " << *b_itr
915 << " seems to be a single bunch" );
916 m_singleBunches.insert( BunchCrossing( *b_itr, intensity1,
917 intensity2 ) );
918 }
919
920 // Only step through the intensity vector(s) if it has some elements:
921 if( bunch_int1.size() ) ++i1_itr;
922 if( bunch_int2.size() ) ++i2_itr;
923 }
924
925 //
926 // Finally some debugging message for the end:
927 //
928 ATH_MSG_DEBUG( "Single bunches found: " << m_singleBunches );
929
930 return StatusCode::SUCCESS;
931 }
932
954 loadBunchTrains( const std::vector< int >& bunches,
955 const std::vector< float >& bunch_int1,
956 const std::vector< float >& bunch_int2 ) {
957
958 // Do a small sanity check:
959 if( ( ( bunches.size() != bunch_int1.size() ) && bunch_int1.size() ) ||
960 ( ( bunches.size() != bunch_int2.size() ) && bunch_int2.size() ) ) {
961 ATH_MSG_ERROR( "Received vectors of different sizes for the bunch "
962 "IDs and bunch intensities\n"
963 "Function can not work like this..." );
964 return StatusCode::FAILURE;
965 }
966 if( ! bunch_int1.size() ) {
967 ATH_MSG_DEBUG( "Not using bunch intensity for the calculation" );
968 }
969 if( ( ! bunch_int2.size() ) && bunch_int1.size() ) {
970 ATH_MSG_DEBUG( "Using 'bunch crossing intensity' for the "
971 "calculation" );
972 }
973
974 //
975 // Calculate the allowed maximum BCID separation between single bunches:
976 //
977 const int maxBCSpacing = bunchSpacing( bunches );
978
979 // Reset the cache:
980 m_bunchTrains.clear();
981
982 //
983 // Create a cache of the bunches which have not been identified as a
984 // single bunch:
985 //
986 std::set< BunchCrossing > cache;
987 std::vector< int >::const_iterator b_itr = bunches.begin();
988 std::vector< int >::const_iterator b_end = bunches.end();
989 std::vector< float >::const_iterator i1_itr = bunch_int1.begin();
990 std::vector< float >::const_iterator i2_itr = bunch_int2.begin();
991 for( ; b_itr != b_end; ++b_itr ) {
992 if( std::find( m_singleBunches.begin(), m_singleBunches.end(),
993 BunchCrossing( *b_itr ) ) == m_singleBunches.end() ) {
994 cache.insert( BunchCrossing( *b_itr,
995 ( float )( bunch_int1.size() ? *i1_itr :
996 1.0 ),
997 ( float )( bunch_int2.size() ? *i2_itr :
998 0.0 ) ) );
999 }
1000 if( bunch_int1.size() ) ++i1_itr;
1001 if( bunch_int2.size() ) ++i2_itr;
1002 }
1003
1004 ATH_MSG_VERBOSE( "Bunches considered for trains: " << cache );
1005
1006 //
1007 // Continue the loop until we have unassigned bunches:
1008 //
1009 while( cache.size() ) {
1010
1011 // Create a new bunch train object:
1012 BunchTrain bt;
1013 bt.insert( *cache.begin() );
1014
1015 // Try finding attachable bunches until no other attachable bunch can
1016 // be found:
1017 size_t prev_size = 0;
1018 while( prev_size != cache.size() ) {
1019
1020 // Let's remember the size of the cache:
1021 prev_size = cache.size();
1022
1023 // Find all the bunches that should be a part of this train:
1024 std::set< BunchCrossing >::const_iterator c_itr = cache.begin();
1025 std::set< BunchCrossing >::const_iterator c_end = cache.end();
1026 for( ; c_itr != c_end; ++c_itr ) {
1027 if( bt.distance( *c_itr ) <= maxBCSpacing ) {
1028 ATH_MSG_VERBOSE( "Adding BunchCrossing " << *c_itr
1029 << " to Bunch Train " << bt );
1030 bt.insert( *c_itr );
1031 }
1032 }
1033
1034 // Now remove the selected bunches from the cache:
1035 BunchTrain::const_iterator itr = bt.begin();
1036 BunchTrain::const_iterator end = bt.end();
1037 for( ; itr != end; ++itr ) {
1038 cache.erase( *itr );
1039 }
1040 }
1041
1042 // Finally, remember this train:
1043 if( ! bt.validate() ) {
1044 ATH_MSG_ERROR( "Found a strange bunch train: " << bt );
1045 ATH_MSG_ERROR( "Keeping in it the list of trains!" );
1046 }
1047 m_bunchTrains.insert( bt );
1048 }
1049
1050 //
1051 // Check if the spacing in the bunch trains is the same. (It should be for
1052 // all real configurations.)
1053 //
1054 std::set< BunchTrain >::const_iterator train_itr = m_bunchTrains.begin();
1055 std::set< BunchTrain >::const_iterator train_end = m_bunchTrains.end();
1056 int spacing = -1;
1057 for( ; train_itr != train_end; ++train_itr ) {
1058 if( spacing < 0 ) {
1059 spacing = train_itr->spacing();
1060 continue;
1061 }
1062 if( train_itr->spacing() != spacing ) {
1063 ATH_MSG_WARNING( "The spacing seems to be different between the "
1064 "trains" );
1065 ATH_MSG_WARNING( "This should probably not happen" );
1066 }
1067 }
1068
1069 ATH_MSG_DEBUG( "Bunch trains found: " << m_bunchTrains );
1070
1071 return StatusCode::SUCCESS;
1072 }
1073
1085 loadUnpairedBunches( const std::vector< int >& beam1,
1086 const std::vector< int >& beam2,
1087 const std::vector< float >& bunch_int1,
1088 const std::vector< float >& bunch_int2 ) {
1089
1090 // Do a small sanity check:
1091 if( ( ( beam1.size() != bunch_int1.size() ) && bunch_int1.size() ) ||
1092 ( ( beam2.size() != bunch_int2.size() ) && bunch_int2.size() ) ) {
1093 ATH_MSG_ERROR( "Received vectors of different sizes for the bunch "
1094 "IDs and bunch intensities\n"
1095 "Function can not work like this..." );
1096 return StatusCode::FAILURE;
1097 }
1098 if( ( ! bunch_int1.size() ) && ( ! bunch_int2.size() ) ) {
1099 ATH_MSG_DEBUG( "Not using bunch intensity for the calculation" );
1100 }
1101
1102 // Reset the cache:
1103 m_unpairedBunches.clear();
1104
1105 //
1106 // Add the unpaired bunches from beam 1:
1107 //
1108 std::vector< int >::const_iterator b_itr = beam1.begin();
1109 std::vector< int >::const_iterator b_end = beam1.end();
1110 std::vector< float >::const_iterator i_itr = bunch_int1.begin();
1111 for( ; b_itr != b_end; ++b_itr ) {
1112
1113 // Evaluate the intensity of this unpaired bunch:
1114 const float intensity = bunch_int1.size() ? *i_itr : 1.0;
1115
1116 // Nothing fancy to do, just put it in the cache:
1117 m_unpairedBunches.insert( BunchCrossing( *b_itr, intensity, 0.0 ) );
1118
1119 // Only step through the intensity vector if it has some elements:
1120 if( bunch_int1.size() ) ++i_itr;
1121 }
1122
1123 //
1124 // Add the unpaired bunches from beam 2:
1125 //
1126 b_itr = beam2.begin();
1127 b_end = beam2.end();
1128 i_itr = bunch_int2.begin();
1129 for( ; b_itr != b_end; ++b_itr ) {
1130
1131 // Evaluate the intensity of this unpaired bunch:
1132 const float intensity = bunch_int2.size() ? *i_itr : 1.0;
1133
1134 // Check if this BCID is already known as an unpaired BCID:
1135 std::set< BunchCrossing >::iterator itr =
1136 m_unpairedBunches.find( *b_itr );
1137 if( itr != m_unpairedBunches.end() ) {
1138 // Modify the BCID not to correspond to a particular beam. Most
1139 // implementations don't treat beam 1 and beam 2 separately.
1140 BunchCrossing bc( *itr );
1141 bc.setIntensityBeam2( intensity );
1142 m_unpairedBunches.erase( itr );
1143 m_unpairedBunches.insert( bc );
1144 } else {
1145 // Nothing fancy to do, just put it in the cache:
1146 m_unpairedBunches.insert( BunchCrossing( *b_itr, 0.0, intensity ) );
1147 }
1148
1149 // Only step through the intensity vector if it has some elements:
1150 if( bunch_int2.size() ) ++i_itr;
1151 }
1152
1153 //
1154 // Finally some debugging message for the end:
1155 //
1156 ATH_MSG_DEBUG( "Unpaired bunches found: " << m_unpairedBunches );
1157
1158 return StatusCode::SUCCESS;
1159 }
1160
1167
1168 ATH_MSG_INFO( "No. of coll. bunches : " << m_filledBunches.size() );
1169 ATH_MSG_INFO( "No. of unpaired bunches: " << m_unpairedBunches.size() );
1170 ATH_MSG_INFO( "No. of bunch trains : " << m_bunchTrains.size() );
1171 if( m_bunchTrains.size() ) {
1172 ATH_MSG_INFO( "Bunch spacing in trains: "
1173 << m_bunchTrains.begin()->spacing()
1174 << " ns" );
1175 }
1176
1177 return;
1178 }
1179
1193 bunchSpacing( const std::vector< int >& bunches ) const {
1194
1195 // The maximum BC spacing to start from.
1196 const int maxSpacing = m_maxBunchSpacing / BunchCrossing::BUNCH_SPACING;
1197
1198 // Iterate downwards from the maximum spacing, searching for the minimum
1199 // spacing with which bunches exist.
1200 int result = maxSpacing;
1201 for( ; result > 0; --result ) {
1202
1203 // Test how many bunches have neighbors inside of the current window.
1204 const int nbunches =
1205 std::count_if( bunches.begin(), bunches.end(),
1206 count_bunch_neighbors( bunches, result ) );
1207 ATH_MSG_VERBOSE( "Number of bunches with " << result
1208 << " BC neighbors: " << nbunches );
1209
1210 // If none of them do, then we're finished.
1211 if( ! nbunches ) {
1212 // If we're not at the max spacing anymore, then it means that in
1213 // the previous step there were still bunches with neighbors in this
1214 // window. That's the spacing we need then.
1215 //
1216 // But if we're still at the maximum spacing, then let's just keep
1217 // that as the final answer.
1218 if( result != maxSpacing ) {
1219 ++result;
1220 }
1221 break;
1222 }
1223 }
1224 // If we went down to 0, then the right answer is 1. This is just how this
1225 // algorithm works...
1226 if( result == 0 ) {
1227 result = 1;
1228 }
1229 ATH_MSG_DEBUG( "Bunch spacing: " << result << " BCs" );
1230
1231 // Return the smallest spacing found:
1232 return result;
1233 }
1234
1235} // namespace Trig
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
virtual BunchCrossingType bcType(bcid_type bcid) const
Get the type of the specific bunch crossing.
virtual bool isBeam1(bcid_type bcid) const
Function deciding if there was a bunch from "beam 1" in this bunch crossing.
std::set< Trig::BunchCrossing > m_singleBunches
Internal list of single bunches.
StatusCode loadBunchTrains(const std::vector< int > &bunches, const std::vector< float > &bunch_int1=std::vector< float >(), const std::vector< float > &bunch_int2=std::vector< float >())
Interpret the configuration for bunch trains.
virtual int gapBeforeBunch(bcid_type bcid, BunchDistanceType dtype=NanoSec, BunchFillType ftype=CollidingBunch) const
Gap before a particular bunch.
virtual std::vector< float > bunchIntInFront(bcid_type bcid, int bunches=10, BeamType type=Crossing) const
Function returning the intensities of the bunch crossings before the reference.
int bunchSpacing(const std::vector< int > &bunches) const
Get the apparent bunch spacing in the current configuration.
virtual unsigned int numberOfUnpairedBunches() const
Get the number of unpaired bunches in the current configuration.
virtual int gapBeforeTrain(bcid_type bcid, BunchDistanceType type=NanoSec) const
Gap before the train this BCID is in.
virtual bool isFilled(bcid_type bcid) const
The simplest query: Is the bunch crossing filled or not?
virtual std::vector< float > bunchIntAfter(bcid_type bcid, int bunches=10, BeamType type=Crossing) const
Function returning the intensities of the bunch crossings after the reference.
virtual int gapAfterBunch(bcid_type bcid, BunchDistanceType dtype=NanoSec, BunchFillType ftype=CollidingBunch) const
Gap after a particular bunch.
virtual int distanceFromFront(bcid_type bcid, BunchDistanceType type=NanoSec) const
The distance of the specific bunch crossing from the front of the train.
virtual bool isUnpaired(bcid_type bcid) const
Function deciding if a given bunch crossing has an unpaired bunch.
BunchCrossingToolBase(const std::string &name="BunchCrossingToolBase")
Default constructor.
virtual unsigned int numberOfFilledBunches() const
Get the number of filled bunches in the current configuration.
std::set< Trig::BunchCrossing > m_unpairedBunches
Internal list of unpaired bunches.
virtual std::vector< bool > bunchesInFront(bcid_type bcid, int bunches=10) const
Function returning whether the previous bunches were filled, and how.
virtual int distanceFromTail(bcid_type bcid, BunchDistanceType type=NanoSec) const
The distance of the specific bunch crossing from the tail of the train.
virtual float bcIntensity(bcid_type bcid, BeamType type=Crossing) const
Function returning the "intensity" of a given bunch crossing.
virtual bool isBeam2(bcid_type bcid) const
Function deciding if there was a bunch from "beam 2" in this bunch crossing.
virtual unsigned int numberOfBunchTrains() const
Get the number of the bunch trains in the current configuration.
virtual int gapAfterTrain(bcid_type bcid, BunchDistanceType type=NanoSec) const
Gap after the train this BCID is in.
StatusCode loadSingleBunches(const std::vector< int > &bunches, const std::vector< float > &bunch_int1=std::vector< float >(), const std::vector< float > &bunch_int2=std::vector< float >())
Interpret the configuration for single bunches.
void printConfig() const
Function printing the configuration of the tool.
int m_maxBunchSpacing
The maximum bunch spacing that the tool should consider.
virtual int bunchTrainSpacing(BunchDistanceType type=NanoSec) const
Get the bunch spacing in the trains.
std::set< Trig::BunchCrossing > m_filledBunches
List of colliding bunches.
int m_frontLength
Length of the "front" of a bunch train.
StatusCode loadUnpairedBunches(const std::vector< int > &beam1, const std::vector< int > &beam2, const std::vector< float > &bunch_int1=std::vector< float >(), const std::vector< float > &bunch_int2=std::vector< float >())
Interpret the configuration for unpaired bunches.
virtual std::vector< bool > bunchesAfter(bcid_type bcid=0, int bunches=10) const
Function returning whether the following bunches were filled, and how.
std::set< Trig::BunchTrain > m_bunchTrains
Internal list of bunch trains.
virtual bool isInTrain(bcid_type bcid) const
Function deciding if a given bunch crossing is in a filled train.
int m_tailLength
Length of the "tail" of a bunch train.
A smart integer class representing bunch crossings.
int gapTo(const BunchCrossing &bc) const
Distance to a following bunch crossing.
int distance(const BunchCrossing &bc) const
The distance from another bunch crossing.
int gapFrom(const BunchCrossing &bc) const
Distance from a previous bunch crossing.
static const int MAX_BCID
The maximum number of bunches that can be in the LHC.
static const int BUNCH_SPACING
Minimum spacing between the bunches, in nanoseconds.
void setIntensityBeam2(float intensity)
Set the "intensity" of beam 2 in this bunch crossing.
A smart set of BunchCrossing objects.
Definition BunchTrain.h:35
bool validate()
Check the spacing of the bunches in the train.
int distance(const BunchCrossing &bc) const
"Distance" of a bunch crossing from this bunch train
BunchFillType
Enumeration specifying what kind of bunch to use in the gap functions.
@ CollidingBunch
The gap should be calculated wrt. the closest colling bunch.
@ UnpairedBunch
The gap should be calculated wrt. the closest unpaired bunch.
@ EmptyBunch
The gap should be calculated wrt. the closest empty bunch.
@ UnpairedBeam1
The gap should be calculated wrt.
@ UnpairedBeam2
The gap should be calculated wrt.
unsigned int bcid_type
Declare the interface that this class provides.
BunchDistanceType
Enumeration specifying the units in which to expect the bunch distance type.
@ BunchCrossings
Distance in units of 25 nanoseconds.
@ NanoSec
Distance in nanoseconds.
@ FilledBunches
Distance in units of filled bunches (depends on filling scheme).
BunchCrossingType
Simplified type for a given bunch crossing.
@ Unpaired
This is an unpaired bunch (either beam1 or beam2).
@ FirstEmpty
The first empty bunch after a train.
@ Tail
The BCID belongs to the last few bunces in a train.
@ Empty
An empty bunch far away from filled bunches.
@ Front
The BCID belongs to the first few bunches in a train.
@ Middle
The BCID belongs to the middle bunches in a train.
@ Single
This is a filled, single bunch (not in a train).
@ MiddleEmpty
An empty BCID in the middle of a train.
BeamType
Types of the return values of the bcIntensity function.
@ Beam1
The returned intensity should be for "beam 1".
@ Beam2
The returned intensity should be for "beam 2".
@ Crossing
The returned intensity should describe the BC.
Functor counting how many neighbors a given bunch crossing has.
AsgMetadataTool(const std::string &name)
Normal ASG tool constructor with a name.
The common trigger namespace for trigger analysis tools.
int distance(const BunchCrossing bc1, const BunchCrossing bc2)
I need this function only for technical reasons.