ATLAS Offline Software
Loading...
Searching...
No Matches
Event/FourMomUtils/src/Thrust.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
7
8// AthAnalysisBase/ManaCore doesn't currently include the Trigger Service
9#ifndef XAOD_ANALYSIS
10
11#include <cmath>
12
13namespace FourMomUtils {
14
15using std::abs;
16using std::exp;
17
18CLHEP::Hep3Vector
19thrust( const I4MomIter_t& iBeg, const I4MomIter_t& iEnd,
20 double& thrust_major, double& thrust_minor, bool useThreeD)
21{
22 /*
23 Finding the thrust axis in an event is not trivial.
24
25 Here, we follow the procedure described in the PYTHIA manual JHEP 05 (2006) 026,
26 also hep-ph/0603175. The approach is to use an iterative method, which usually
27 converges quickly. As the minimization can find just a local minimum, different
28 starting points for the thrust axis are tried. By default, first the direction
29 of the four most energetic particles are tried, if their result disagrees, all
30 16 permutations of the sum of all 4 particles are tried (with coefficients +- 1)
31
32 Note, that the thrust is calculated for _ALL_ particles. If you want only a subset
33 of particles, you have to apply a cut beforehand.
34 See e.g. Reconstruction/EventShapes/EventShapeTools for examples.
35 */
36
37 CLHEP::Hep3Vector thrust(0,0,0);
38
39 int agree=0;
40 int disagree=0;
41
42 CLHEP::Hep3Vector n_0[20];
43 short add0[20] = { 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1,-1,-1,-1 };
44 short add1[20] = { 0, 1, 0, 0, 1, 1, 1, 1,-1,-1,-1,-1, 1, 1, 1, 1,-1,-1,-1,-1 };
45 short add2[20] = { 0, 0, 1, 0, 1, 1,-1,-1, 1, 1,-1,-1, 1, 1,-1,-1, 1, 1,-1,-1 };
46 short add3[20] = { 0, 0, 0, 1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1 };
47
48 std::vector<const INavigable4Momentum*> v_copy(4);
49
50 // partial_sort_copy sorts a copy of the collection according to energy and
51 // returns only the first four elements (minimum of input collection size and
52 // pre-allocated output vector v_copy
53 partial_sort_copy( iBeg, iEnd,
54 v_copy.begin(), v_copy.end(),
56
57 int n_tests=0;
58 int max_tests=std::min<int>(20, std::distance(iBeg, iEnd));
59 do{
60 n_0[n_tests]=CLHEP::Hep3Vector(0,0,0);
61
62 // assign direction of four most energetic particles
63 n_0[n_tests] +=
64 add0[n_tests] * CLHEP::Hep3Vector(v_copy.at(0)->px(), v_copy.at(0)->py(), v_copy.at(0)->pz()) +
65 add1[n_tests] * CLHEP::Hep3Vector(v_copy.at(1)->px(), v_copy.at(1)->py(), v_copy.at(1)->pz()) +
66 add2[n_tests] * CLHEP::Hep3Vector(v_copy.at(2)->px(), v_copy.at(2)->py(), v_copy.at(2)->pz()) +
67 add3[n_tests] * CLHEP::Hep3Vector(v_copy.at(3)->px(), v_copy.at(3)->py(), v_copy.at(3)->pz());
68
69 if(!useThreeD)
70 n_0[n_tests].setZ(0);
71
72 /* // my convention : x is always positive (thrust axis has two fold ambiguity)
73 if(n_0[n_tests].x()<0)
74 n_0[n_tests] = - n_0[n_tests]; */
75
76 // protect against small number of input particles (smaller than 4!)
77 if(n_0[n_tests].mag()>0)
78 n_0[n_tests] /= n_0[n_tests].mag();
79
80 int loop=0;
81 bool run=false;
82 do{
83 CLHEP::Hep3Vector n_1(0,0,0);
84 for ( I4MomIter_t itr = iBeg; itr != iEnd; ++itr )
85 {
86 // if(((*itr)->hlv()).vect().dot(n_0[n_tests])>0)
87 if((*itr)->px() * n_0[n_tests].x() +
88 (*itr)->py() * n_0[n_tests].y() +
89 (*itr)->pz() * n_0[n_tests].z() > 0 )
90 n_1 += CLHEP::Hep3Vector((*itr)->px(), (*itr)->py(), (*itr)->pz() );
91 else
92 n_1 -= CLHEP::Hep3Vector((*itr)->px(), (*itr)->py(), (*itr)->pz() );
93 }
94
95 if(!useThreeD)
96 n_1.setZ(0);
97
98 // protect against few number of input particles (smaller than 4!)
99 if(n_1.mag()>0)
100 n_1 /= n_1.mag();
101
102 // has axis changed ? if so, try at most ten times (thrust axis has two fold ambiguity)
103 run = ( n_0[n_tests]!=n_1 ) && ( -n_0[n_tests]!=n_1 ) && loop++<10;
104 n_0[n_tests] = n_1;
105 }while( run );
106
107 // agrees or disagrees with first result ?
108 // thrust has a sign ambiguity
109 if( n_tests>0 && ( n_0[0] == n_0[n_tests] || n_0[0] == -n_0[n_tests] ) ) agree++;
110 if( n_tests>0 && n_0[0] != n_0[n_tests] && n_0[0] != -n_0[n_tests] ) disagree++;
111
112 // stop if four first tries give same result (no test for first try! )
113 // if not, try at most max_tests combinations
114 }while( ( disagree>0 || agree<4 ) && ++n_tests < max_tests);
115
116 // now that we have the thrust axis, we determine the thrust value
117 // if the various calculations of the thrust axes disagree, try all
118 // and take the maximum, calculate minor and mayor axis
119 n_tests=0;
120 do{
121 double denominator = 0;
122 double numerator_t = 0;
123 double numerator_m = 0;
124 for ( I4MomIter_t itr = iBeg; itr != iEnd; ++itr )
125 {
126 CLHEP::Hep3Vector c((*itr)->hlv().vect());
127 c.setZ(0);
128 numerator_t += abs(c.dot(n_0[n_tests]));
129 numerator_m += (c.cross(n_0[n_tests])).mag();
130 denominator += c.mag();
131 }
132 const double inv_denominator = denominator!= 0 ? (1. / denominator) : 1;
133 if( numerator_t * inv_denominator > thrust_major )
134 {
135 thrust_major = numerator_t * inv_denominator;
136 thrust_minor = numerator_m * inv_denominator;
137 thrust=n_0[n_tests];
138 }
139 }while(disagree>0 && ++n_tests < max_tests);
140
141 /* std::cout << "Calculation of Thrust gave: ( "
142 << thrust.x() << " | "
143 << thrust.y() << " | "
144 << thrust.z() << " )\n"; */
145
146 // return StatusCode::SUCCESS;
147 return thrust;
148}
149
150} //> end namespace FourMomUtils
151
152#endif
Scalar mag() const
mag method
CLHEP::Hep3Vector thrust(const I4MomIter_t &iBeg, const I4MomIter_t &iEnd, double &thrust_major, double &thrust_minor, bool useThreeD=false)
INavigable4MomentumCollection::const_iterator I4MomIter_t
Definition ForwardTerm.h:16
Definition run.py:1