Belle II Software  release-08-01-10
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 
13 using namespace Belle2;
14 using Eigen::MatrixXd;
15 using Eigen::VectorXd;
16 
17 
19 static 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 
29 static 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 
42 static 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 
72 ConditionalGaussGenerator::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 
99 VectorXd 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 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.