Belle II Software development
ConditionalGaussGenerator.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <framework/utilities/ConditionalGaussGenerator.h>
10#include <TRandom.h>
11
12
13using namespace Belle2;
14using Eigen::MatrixXd;
15using Eigen::VectorXd;
16
17
19static std::vector<VectorXd> toVectors(const MatrixXd& mat)
20{
21 std::vector<VectorXd> vList;
22 for (int j = 0; j < mat.cols(); ++j)
23 vList.push_back(mat.col(j));
24
25 return vList;
26}
27
29static MatrixXd toMatrix(const std::vector<VectorXd>& vList)
30{
31 if (vList.size() == 0)
32 return MatrixXd();
33
34 MatrixXd mat(vList[0].rows(), vList.size());
35 for (unsigned j = 0; j < vList.size(); ++j)
36 mat.col(j) = vList[j];
37
38 return mat;
39}
40
42static std::vector<VectorXd> getOrthogonalSpace(VectorXd v0)
43{
44 if (v0.dot(v0) == 0)
45 return toVectors(MatrixXd::Identity(v0.rows(), v0.rows()));
46
47 VectorXd v0Norm = v0.normalized();
48
49 std::vector<VectorXd> vList;
50 vList.push_back(v0Norm);
51
52 while (int(vList.size()) < v0.rows()) {
53
54 // Let's first create an empty vector and then fill it with gRandom
55 // We can NOT use VectorXd::Random for any reasons
56 VectorXd v(v0.rows());
57 for (int i = 0; i < v.rows(); ++i)
58 v(i) = gRandom->Uniform(-1, 1);
59
60 for (const VectorXd& vi : vList)
61 v -= vi.dot(v) * vi / vi.dot(vi);
62
63 if (v.dot(v) > 0) {
64 vList.push_back(v.normalized());
65 }
66 }
67
68 vList.erase(vList.begin()); // note len(vList) >= 1
69 return vList;
70}
71
72ConditionalGaussGenerator::ConditionalGaussGenerator(const VectorXd& mu, const MatrixXd& covMat) : m_mu(mu), m_covMat(covMat)
73{
74 Eigen::SelfAdjointEigenSolver<MatrixXd> sol(m_covMat);
75 VectorXd vals = sol.eigenvalues();
76 MatrixXd vecs = sol.eigenvectors();
77
78 std::vector<VectorXd> vBase;
79 //keep only vectors with positive eigenvalue
80 for (int i = 0; i < vals.rows(); ++i)
81 if (vals[i] > 0) {
82 vBase.push_back(sqrt(vals[i]) * vecs.col(i));
83 }
84
85 if (vBase.size() == 0) // matrix is zero, no smearing
86 return;
87
88 m_vBaseMat = toMatrix(vBase);
89
90 // get the longitudinal space
91 VectorXd v0 = m_vBaseMat.row(0);
92
93 // get the orthogonal space
94 m_cOrt = getOrthogonalSpace(v0);
95
96 m_v0norm = v0.dot(v0) > 0 ? v0 / v0.dot(v0) : v0; //normalize, or keep it zero
97}
98
99VectorXd ConditionalGaussGenerator::generate(double x0) const
100{
101 double dx0 = x0 - m_mu[0];
102
103 // in case of zero cov matrix
104 if (m_vBaseMat.cols() == 0)
105 return m_mu;
106
107 VectorXd x = m_v0norm * dx0;
108
109 for (const VectorXd& co : m_cOrt) {
110 double rr = gRandom->Gaus();
111 x += rr * co;
112 }
113
114 VectorXd vec = m_vBaseMat * x;
115
116 return (m_mu + vec);
117}
Eigen::VectorXd generate(double x0) const
generate random vector based on the provided first component x0
Eigen::VectorXd m_mu
central values of the distribution
Eigen::MatrixXd m_vBaseMat
transformation matrix between eigen-system of m_covMat and nominal system
std::vector< Eigen::VectorXd > m_cOrt
array of vectors describing free degrees of freedom of random generator
Eigen::VectorXd m_v0norm
vector which scales with dx0
ConditionalGaussGenerator()
dummy constructor without arguments
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.