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 Eigen::VectorXd& mu, const Eigen::MatrixXd& covMat) : m_mu(mu),
73 m_covMat(covMat)
74{
75 Eigen::SelfAdjointEigenSolver<MatrixXd> sol(m_covMat);
76 VectorXd vals = sol.eigenvalues();
77 MatrixXd vecs = sol.eigenvectors();
78
79 std::vector<VectorXd> vBase;
80 //keep only vectors with positive eigenvalue
81 for (int i = 0; i < vals.rows(); ++i)
82 if (vals[i] > 0) {
83 vBase.push_back(sqrt(vals[i]) * vecs.col(i));
84 }
85
86 if (vBase.size() == 0) // matrix is zero, no smearing
87 return;
88
89 m_vBaseMat = toMatrix(vBase);
90
91 // get the longitudinal space
92 VectorXd v0 = m_vBaseMat.row(0);
93
94 // get the orthogonal space
95 m_cOrt = getOrthogonalSpace(v0);
96
97 m_v0norm = v0.dot(v0) > 0 ? v0 / v0.dot(v0) : v0; //normalize, or keep it zero
98}
99
100VectorXd ConditionalGaussGenerator::generate(double x0) const
101{
102 double dx0 = x0 - m_mu[0];
103
104 // in case of zero cov matrix
105 if (m_vBaseMat.cols() == 0)
106 return m_mu;
107
108 VectorXd x = m_v0norm * dx0;
109
110 for (const VectorXd& co : m_cOrt) {
111 double rr = gRandom->Gaus();
112 x += rr * co;
113 }
114
115 VectorXd vec = m_vBaseMat * x;
116
117 return (m_mu + vec);
118}
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
Eigen::MatrixXd m_covMat
covariance matrix of the distribution
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.