Skip to content

Commit 2835abc

Browse files
Merge pull request #121 from kjvbrt/ana_thrust
Adding determination of event thrust not by minimization
2 parents 624d30c + 5eba397 commit 2835abc

File tree

13 files changed

+280
-46
lines changed

13 files changed

+280
-46
lines changed

.github/workflows/bench.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: benchmark
33
on: [push]
44

55
jobs:
6-
test:
6+
bench:
77
runs-on: ubuntu-latest
88
strategy:
99
fail-fast: false

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ __pycache__/
99

1010
# ROOT files
1111
*.root
12+
13+
# Editors
1214
*~
15+
.vimlocal
1316

1417
# Distribution / packaging
1518
.Python

analyzers/dataframe/Utils.h

Lines changed: 0 additions & 10 deletions
This file was deleted.

analyzers/dataframe/include/FCCAnalyses/Algorithms.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ namespace Algorithms{
7272
};
7373

7474

75-
/// Calculates the thrust axis based on a list of px, py, pz
75+
/// Finds the thrust axis based on a list of px, py, pz
7676
struct minimize_thrust {
7777
minimize_thrust(std::string arg_minname="Minuit2",
7878
std::string arg_algoname="Migrad",
@@ -92,6 +92,22 @@ namespace Algorithms{
9292
double _variable[3]={1.0,1.0,1.0};
9393
};
9494

95+
/// Calculates the thrust axis by looping over all possible combinations
96+
struct calculate_thrust {
97+
calculate_thrust(){}
98+
ROOT::VecOps::RVec<float> operator()(const ROOT::VecOps::RVec<float>& px,
99+
const ROOT::VecOps::RVec<float>& py,
100+
const ROOT::VecOps::RVec<float>& pz);
101+
102+
// Helper functions, to ease manipulation with the elements of internal array
103+
inline void mag2(float (&vec)[4]);
104+
inline float dot(float vec1[4], float vec2[4]);
105+
inline void cross(float (&vec)[4], float vec1[4], float vec2[4]);
106+
inline void unit(float (&vec)[4]);
107+
inline void plus(float (&vec)[4], float vecIn1[4], float vecIn2[4]);
108+
inline void minus(float (&vecOut)[4], float vecIn1[4], float vecIn2[4]);
109+
inline void copy(float (&vecOut)[4], float vecIn[4]);
110+
};
95111

96112
/// Get the weighted charge in a given hemisphere (defined by it's angle wrt to axis). For definition see eq1 https://arxiv.org/pdf/1209.2421.pdf
97113
struct getAxisCharge {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef UTILS_ANALYZERS_H
2+
#define UTILS_ANALYZERS_H
3+
4+
#include <cmath>
5+
6+
namespace FCCAnalyses {
7+
namespace Utils {
8+
9+
template<typename T> inline auto getsize( T& vec){ return vec.size();};
10+
11+
}
12+
}
13+
14+
#endif

analyzers/dataframe/src/Algorithms.cc

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "FCCAnalyses/Algorithms.h"
2+
#include "FCCAnalyses/Utils.h"
23
#include "Math/Minimizer.h"
34
#include "Math/IFunction.h"
45
#include "Math/Factory.h"
@@ -163,6 +164,150 @@ ROOT::VecOps::RVec<float> minimize_thrust::operator()(const ROOT::VecOps::RVec<f
163164
}
164165

165166

167+
ROOT::VecOps::RVec<float> Algorithms::calculate_thrust::operator()(
168+
const ROOT::VecOps::RVec<float>& px,
169+
const ROOT::VecOps::RVec<float>& py,
170+
const ROOT::VecOps::RVec<float>& pz) {
171+
172+
if (px.size() != py.size()) {
173+
throw std::domain_error("calculate_thrust: Input vector sizes are not equal.");
174+
}
175+
if (px.size() != pz.size()) {
176+
throw std::domain_error("calculate_thrust: Input vector sizes are not equal.");
177+
}
178+
179+
ROOT::VecOps::RVec<float> result;
180+
181+
size_t nParticles = px.size();
182+
if (nParticles < 2) {
183+
// std::cout << "calculate_thrust: Number of input particles too small."
184+
// << std::endl;
185+
186+
result.push_back(-1);
187+
result.push_back(-1);
188+
result.push_back(-1);
189+
result.push_back(-1);
190+
191+
return result;
192+
}
193+
194+
// std::cout << "calculate_thrust: Calculating sum of all particles in event"
195+
// << std::endl;
196+
197+
// Array to store x, y, z and magnitude squared of the particles.
198+
// 0 -- magnitude squared, 1 -- x, 2 -- y, 3 -- z
199+
float pArr[nParticles][4];
200+
float pSum = 0.;
201+
for (size_t i = 0; i < nParticles; ++i) {
202+
pArr[i][1] = px[i];
203+
pArr[i][2] = py[i];
204+
pArr[i][3] = pz[i];
205+
mag2(pArr[i]);
206+
pSum += std::sqrt(pArr[i][0]);
207+
}
208+
209+
// Trying all combinations of reference vector orthogonal to two selected
210+
// particles.
211+
// std::cout << "Trying all combinations..." << std::endl;
212+
float pMax[4] = {0., 0., 0., 0.};
213+
for (size_t i = 0; i < nParticles - 1; ++i) {
214+
for (size_t j = i + 1; j < nParticles; ++j) {
215+
float nRef[4];
216+
cross(nRef, pArr[i], pArr[j]);
217+
mag2(nRef);
218+
unit(nRef);
219+
220+
float pPart[4] = {0., 0., 0., 0.};
221+
for (size_t k = 0; k < nParticles; ++k) {
222+
if (k == i || k == j) {
223+
continue;
224+
}
225+
226+
if (dot(nRef, pArr[k]) > 0.) {
227+
plus(pPart, pPart, pArr[k]);
228+
} else {
229+
minus(pPart, pPart, pArr[k]);
230+
}
231+
}
232+
233+
float pFullArr[4][4];
234+
// pPart + pArr[i] + pArr[j]
235+
plus(pFullArr[0], pPart, pArr[i]);
236+
plus(pFullArr[0], pFullArr[0], pArr[j]);
237+
238+
// pPart + pArr[i] - pArr[j]
239+
plus(pFullArr[1], pPart, pArr[i]);
240+
minus(pFullArr[1], pFullArr[1], pArr[j]);
241+
242+
// pPart - pArr[i] + pArr[j]
243+
minus(pFullArr[2], pPart, pArr[i]);
244+
plus(pFullArr[2], pFullArr[2], pArr[j]);
245+
246+
// pPart - pArr[i] - pArr[j]
247+
minus(pFullArr[3], pPart, pArr[i]);
248+
minus(pFullArr[3], pFullArr[3], pArr[j]);
249+
250+
for (size_t k = 0; k < 4; ++k) {
251+
mag2(pFullArr[k]);
252+
if (pFullArr[k][0] > pMax[0]) {
253+
copy(pMax, pFullArr[k]);
254+
}
255+
}
256+
}
257+
}
258+
259+
float pMaxMag = std::sqrt(pMax[0]);
260+
// std::cout << "Thrust value arr: " << pMaxMag / pSum << std::endl;
261+
result.push_back(pMaxMag / pSum);
262+
// Normalizing the thrust vector
263+
result.push_back(pMax[1]/pMaxMag);
264+
result.push_back(pMax[2]/pMaxMag);
265+
result.push_back(pMax[3]/pMaxMag);
266+
267+
return result;
268+
}
269+
270+
inline void Algorithms::calculate_thrust::mag2(float (&vec)[4]) {
271+
vec[0] = vec[1]*vec[1] + vec[2]*vec[2] + vec[3]*vec[3];
272+
}
273+
274+
inline float Algorithms::calculate_thrust::dot(float vec1[4], float vec2[4]) {
275+
return vec1[1]*vec2[1] + vec1[2]*vec2[2] + vec1[3]*vec2[3];
276+
}
277+
278+
inline void Algorithms::calculate_thrust::cross(float (&vec)[4], float vec1[4], float vec2[4]) {
279+
vec[1] = vec1[2]*vec2[3] - vec1[3]*vec2[2];
280+
vec[2] = vec1[3]*vec2[1] - vec1[1]*vec2[3];
281+
vec[3] = vec1[1]*vec2[2] - vec1[2]*vec2[1];
282+
}
283+
284+
inline void Algorithms::calculate_thrust::unit(float (&vec)[4]) {
285+
float mag = std::sqrt(vec[0]);
286+
vec[1] = vec[1]/mag;
287+
vec[2] = vec[2]/mag;
288+
vec[3] = vec[3]/mag;
289+
}
290+
291+
inline void Algorithms::calculate_thrust::plus(float (&vec)[4], float vecIn1[4], float vecIn2[4]) {
292+
vec[1] = vecIn1[1] + vecIn2[1];
293+
vec[2] = vecIn1[2] + vecIn2[2];
294+
vec[3] = vecIn1[3] + vecIn2[3];
295+
}
296+
297+
inline void Algorithms::calculate_thrust::minus(float (&vecOut)[4], float vecIn1[4], float vecIn2[4]) {
298+
vecOut[1] = vecIn1[1] - vecIn2[1];
299+
vecOut[2] = vecIn1[2] - vecIn2[2];
300+
vecOut[3] = vecIn1[3] - vecIn2[3];
301+
}
302+
303+
inline void Algorithms::calculate_thrust::copy(float (&vecOut)[4], float vecIn[4]) {
304+
vecOut[0] = vecIn[0];
305+
vecOut[1] = vecIn[1];
306+
vecOut[2] = vecIn[2];
307+
vecOut[3] = vecIn[3];
308+
}
309+
310+
166311
getAxisCharge::getAxisCharge(bool arg_pos,
167312
float arg_power){
168313
_pos = arg_pos;
@@ -185,7 +330,6 @@ float getAxisCharge::operator() (const ROOT::VecOps::RVec<float> & angle,
185330
}
186331

187332

188-
189333
getAxisMass::getAxisMass(bool arg_pos){
190334
_pos=arg_pos;
191335
}

tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
add_subdirectory(unittest)
33

4+
add_subdirectory(benchmark)
5+
46
function(add_integration_test _testname)
57

68
add_test(NAME ${_testname}

tests/benchmark/CMakeLists.txt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
if(USE_EXTERNAL_CATCH2)
3+
find_package(Catch2 REQUIRED)
4+
else()
5+
message(STATUS "Fetching local copy of Catch2 library for unit-tests...")
6+
# Build Catch2 with the default flags, to avoid generating warnings when we
7+
# build it
8+
set(CXX_FLAGS_CMAKE_USED ${CMAKE_CXX_FLAGS})
9+
set(CMAKE_CXX_FLAGS ${CXX_FLAGS_CMAKE_DEFAULTS})
10+
Include(FetchContent)
11+
FetchContent_Declare(
12+
Catch2
13+
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
14+
GIT_TAG 037ddbc75cc5e58b93cf5a010a94b32333ad824d
15+
)
16+
FetchContent_MakeAvailable(Catch2)
17+
set(CMAKE_MODULE_PATH ${Catch2_SOURCE_DIR}/extras ${CMAKE_MODULE_PATH})
18+
# Disable clang-tidy on external contents
19+
set_target_properties(Catch2 PROPERTIES CXX_CLANG_TIDY "")
20+
21+
# Hack around the fact, that the include directories are not declared as
22+
# SYSTEM for the targets defined this way. Otherwise warnings can still occur
23+
# in Catch2 code when templates are evaluated (which happens quite a bit)
24+
get_target_property(CATCH2_IF_INC_DIRS Catch2 INTERFACE_INCLUDE_DIRECTORIES)
25+
set_target_properties(Catch2 PROPERTIES INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${CATCH2_IF_INC_DIRS}")
26+
27+
# Reset the flags
28+
set(CMAKE_CXX_FLAGS ${CXX_FLAGS_CMAKE_USED})
29+
30+
endif()
31+
32+
33+
# The unittests are a bit better and they are labelled so we can put together a
34+
# list of labels that we want to ignore
35+
set(filter_tests "")
36+
37+
add_executable(bench algorithms.cpp myutils.cpp)
38+
target_link_libraries(bench PUBLIC FCCAnalyses gfortran PRIVATE Catch2::Catch2WithMain)
39+
target_include_directories(bench PUBLIC ${VDT_INCLUDE_DIR})
40+
41+
include(Catch)
42+
catch_discover_tests(bench
43+
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
44+
TEST_PREFIX "B_" # make it possible to filter easily with -R ^UT
45+
TEST_SPEC ${filter_tests} # discover only tests that are known to not fail
46+
)

tests/benchmark/algorithms.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "FCCAnalyses/Algorithms.h"
2+
3+
#include "catch2/catch_test_macros.hpp"
4+
#include <catch2/benchmark/catch_benchmark.hpp>
5+
6+
7+
TEST_CASE("calculate_thrust", "[algorithms]") {
8+
ROOT::VecOps::RVec<float> x {0., 1., 3., 7., 11., 3.};
9+
ROOT::VecOps::RVec<float> y {0., -1., 3., -7., -11., .3};
10+
ROOT::VecOps::RVec<float> z {5., -3., 1., 4., 2., -4};
11+
12+
BENCHMARK("calculate_thrust short vector") {
13+
return FCCAnalyses::Algorithms::calculate_thrust()(x, y, z);
14+
};
15+
}

tests/benchmark/myutils.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#include "FCCAnalyses/myUtils.h"
2+
3+
#include <catch2/catch_test_macros.hpp>
4+
#include <catch2/benchmark/catch_benchmark.hpp>
5+
6+
TEST_CASE("isPV", "[basics]") {
7+
edm4hep::ReconstructedParticleData p;
8+
p.tracks_begin = 0;
9+
ROOT::VecOps::RVec<int> index1 = {3, 0, 7};
10+
ROOT::VecOps::RVec<int> index2 = {3, 1, 7};
11+
12+
BENCHMARK("isPV") {
13+
return FCCAnalyses::myUtils::isPV(p, index1);
14+
};
15+
}

0 commit comments

Comments
 (0)