ATLAS Offline Software
Event/FourMomUtils/src/Thrust.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
3 */
4 
5 #include "FourMomUtils/Thrust.h"
7 
8 // AthAnalysisBase/ManaCore doesn't currently include the Trigger Service
9 #ifndef XAOD_ANALYSIS
10 
11 #include <cmath>
12 
13 namespace FourMomUtils {
14 
15 using std::abs;
16 using std::exp;
17 
18 CLHEP::Hep3Vector
19 thrust( 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 = 1. / denominator;
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
P4Sorters.h
DataModel_detail::const_iterator
Const iterator class for DataVector/DataList.
Definition: DVLIterator.h:82
P4Sorters::Descending::Ene
Definition: P4DescendingSorters.h:105
Thrust.h
drawFromPickle.exp
exp
Definition: drawFromPickle.py:36
FourMomUtils::thrust
CLHEP::Hep3Vector thrust(const I4MomIter_t &iBeg, const I4MomIter_t &iEnd, double &thrust_major, double &thrust_minor, bool useThreeD=false)
Definition: Event/FourMomUtils/src/Thrust.cxx:19
run
Definition: run.py:1
ReadTripsProbsFromCool.denominator
denominator
Definition: ReadTripsProbsFromCool.py:96
python.pydraw.loop
def loop(arg)
Definition: pydraw.py:1242
Amg::distance
float distance(const Amg::Vector3D &p1, const Amg::Vector3D &p2)
calculates the distance between two point in 3D space
Definition: GeoPrimitivesHelpers.h:54
python.compressB64.c
def c
Definition: compressB64.py:93
mag
Scalar mag() const
mag method
Definition: AmgMatrixBasePlugin.h:25
FourMomUtils
Definition: ForwardTerm.h:14