ATLAS Offline Software
Reconstruction/Jet/JetSubStructureUtils/Root/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 
6 #include "TLorentzVector.h"
8 
9 using namespace std;
10 using namespace JetSubStructureUtils;
11 
12 map<string, double> Thrust::result(const fastjet::PseudoJet &jet) const
13 {
14  map<string, double> Variables;
15  Variables["ThrustMin"] = -999. * 1000.;
16  Variables["ThrustMaj"] = -999. * 1000.;
17 
18  vector<fastjet::PseudoJet> clusters = boostToCenterOfMass(jet, jet.constituents());
19  if(clusters.size() < 2) return Variables;
20 
21  bool useThreeD = true;
22 
23  /*
24  This code is recopied from Atlas Code (Rolf Seuster)
25 
26  Finding the thrust axis in an event is not trivial.
27 
28  Here, we follow the procedure described in the PYTHIA manual JHEP 05 (2006) 026,
29  also hep-ph/0603175. The approach is to use an iterative method, which usually
30  converges quickly. As the minimization can find just a local minimum, different
31  starting points for the thrust axis are tried. By default, first the direction
32  of the four most energetic particles are tried, if their result disagrees, all
33  16 permutations of the sum of all 4 particles are tried (with coefficients +- 1)
34 
35  Note, that the thrust is calculated for _ALL_ particles. If you want only a subset
36  of particles, you have to apply a cut beforehand.
37  See e.g. Reconstruction/EventShapes/EventShapeTools for examples.
38  */
39 
40  double thrust_major = -1;
41  double thrust_minor = -1;
42 
43  if(clusters.size() < 4) return Variables;
44 
45  std::vector<fastjet::PseudoJet>::const_iterator iBeg = clusters.begin();
46  std::vector<fastjet::PseudoJet>::const_iterator iEnd = clusters.end();
47 
48  TVector3 thrust(0,0,0);
49 
50  int agree = 0;
51  int disagree = 0;
52 
53  TVector3 n_0[20];
54  short add0[20] = { 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1,-1,-1,-1 };
55  short add1[20] = { 0, 1, 0, 0, 1, 1, 1, 1,-1,-1,-1,-1, 1, 1, 1, 1,-1,-1,-1,-1 };
56  short add2[20] = { 0, 0, 1, 0, 1, 1,-1,-1, 1, 1,-1,-1, 1, 1,-1,-1, 1, 1,-1,-1 };
57  short add3[20] = { 0, 0, 0, 1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1, 1,-1 };
58 
59  std::vector<fastjet::PseudoJet> clusters_Esorted = fastjet::sorted_by_E(clusters);
60  std::vector<fastjet::PseudoJet> v_copy(4);
61  for(int i=0; i<4; i++) {
62  v_copy[i] = clusters_Esorted[i];
63  }
64 
65  int n_tests = 0;
66  int max_tests = min<int>(20, distance(iBeg, iEnd));
67  do {
68  n_0[n_tests]=TVector3(0,0,0);
69 
70  // assign direction of four most energetic particles
71  n_0[n_tests] +=
72  add0[n_tests] * TVector3(v_copy.at(0).px(), v_copy.at(0).py(), v_copy.at(0).pz()) +
73  add1[n_tests] * TVector3(v_copy.at(1).px(), v_copy.at(1).py(), v_copy.at(1).pz()) +
74  add2[n_tests] * TVector3(v_copy.at(2).px(), v_copy.at(2).py(), v_copy.at(2).pz()) +
75  add3[n_tests] * TVector3(v_copy.at(3).px(), v_copy.at(3).py(), v_copy.at(3).pz());
76 
77  if (!useThreeD)
78  n_0[n_tests].SetZ(0);
79 
80  // protect against small number of input particles (smaller than 4!)
81  if (n_0[n_tests].Mag() > 0)
82  n_0[n_tests] *= 1/n_0[n_tests].Mag();
83 
84  int loop = 0;
85  bool run = false;
86  do {
87  TVector3 n_1(0,0,0);
88  for (std::vector<fastjet::PseudoJet>::const_iterator i = iBeg; i != iEnd; ++i) {
89  const fastjet::PseudoJet &itr = *i;
90  if ((itr).px() * n_0[n_tests].x() +
91  (itr).py() * n_0[n_tests].y() +
92  (itr).pz() * n_0[n_tests].z() > 0)
93  n_1 += TVector3((itr).px(), (itr).py(), (itr).pz());
94  else
95  n_1 -= TVector3((itr).px(), (itr).py(), (itr).pz());
96  }
97 
98  if (!useThreeD)
99  n_1.SetZ(0);
100 
101  // protect against few number of input particles (smaller than 4!)
102  if (n_1.Mag() > 0)
103  n_1 *= 1/n_1.Mag();
104 
105  // has axis changed ? if so, try at most ten times (thrust axis has two fold ambiguity)
106  run = (n_0[n_tests] != n_1) && (-n_0[n_tests] != n_1) && loop++ < 10;
107  n_0[n_tests] = n_1;
108  } while (run);
109 
110  // agrees or disagrees with first result ?
111  // thrust has a sign ambiguity
112  if (n_tests > 0 && (n_0[0] == n_0[n_tests] || n_0[0] == -n_0[n_tests])) agree++;
113  if (n_tests > 0 && n_0[0] != n_0[n_tests] && n_0[0] != -n_0[n_tests]) disagree++;
114 
115  // stop if four first tries give same result (no test for first try! )
116  // if not, try at most max_tests combinations
117  } while ((disagree > 0 || agree < 4) && ++n_tests < max_tests);
118 
119  // now that we have the thrust axis, we determine the thrust value
120  // if the various calculations of the thrust axes disagree, try all
121  // and take the maximum, calculate minor and mayor axis
122  n_tests = 0;
123 
124 
125  do {
126  double denominator = 0;
127  double numerator_t = 0;
128  double numerator_m = 0;
129  for(std::vector<fastjet::PseudoJet>::const_iterator i = iBeg; i != iEnd; ++i) {
130  const fastjet::PseudoJet & itr = *i;
131 
132  TLorentzVector v((itr).px(), (itr).py(), (itr).pz(), (itr).e());
133  TVector3 c(v.Vect());
134  numerator_t += fabs(c.Dot(n_0[n_tests]));
135  numerator_m += (c.Cross(n_0[n_tests])).Mag();
136  denominator += c.Mag();
137  }
138 
139  if(denominator < 1e-20) { //FPE
140  return Variables;
141  }
142 
143  if (numerator_t / denominator > thrust_major) {
144  thrust_major = numerator_t / denominator;
145  thrust_minor = numerator_m / denominator;
146  thrust=n_0[n_tests];
147  }
148  } while (disagree > 0 && ++n_tests < max_tests);
149 
150  Variables["ThrustMin"] = thrust_minor;
151  Variables["ThrustMaj"] = thrust_major;
152 
153  return Variables;
154 }
get_generator_info.result
result
Definition: get_generator_info.py:21
test_pyathena.px
px
Definition: test_pyathena.py:18
JetSubStructureUtils::boostToCenterOfMass
std::vector< fastjet::PseudoJet > boostToCenterOfMass(const fastjet::PseudoJet &jet, std::vector< fastjet::PseudoJet > constituents)
Definition: BoostToCenterOfMass.cxx:9
x
#define x
JetSubStructureUtils
Definition: RCJet.h:49
Thrust.h
jet
Definition: JetCalibTools_PlotJESFactors.cxx:23
lumiFormat.i
int i
Definition: lumiFormat.py:92
z
#define z
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
Amg::pz
@ pz
Definition: GeoPrimitives.h:40
run
Definition: run.py:1
ReadTripsProbsFromCool.denominator
denominator
Definition: ReadTripsProbsFromCool.py:96
python.pydraw.loop
def loop(arg)
Definition: pydraw.py:1242
Amg::py
@ py
Definition: GeoPrimitives.h:39
BoostToCenterOfMass.h
python.PyAthena.v
v
Definition: PyAthena.py:157
DiTauMassTools::MaxHistStrategyV2::e
e
Definition: PhysicsAnalysis/TauID/DiTauMassTools/DiTauMassTools/HelperFunctions.h:26
y
#define y
GlobalVariables.Variables
Variables
Definition: GlobalVariables.py:276
RunTileMonitoring.clusters
clusters
Definition: RunTileMonitoring.py:133
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