SQLamarr
The stand-alone ultra-fast simulation option for the LHCb experiment
PVReconstruction.cpp
1 // (c) Copyright 2022 CERN for the benefit of the LHCb Collaboration.
2 //
3 // This software is distributed under the terms of the GNU General Public
4 // Licence version 3 (GPL Version 3), copied verbatim in the file "LICENCE".
5 //
6 // In applying this licence, CERN does not waive the privileges and immunities
7 // granted to it by virtue of its status as an Intergovernmental Organization
8 // or submit itself to any jurisdiction.
9 
10 // Standard C
11 #include <math.h>
12 
13 // STL
14 #include <iostream>
15 #include <random>
16 
17 // SQLite3
18 #include "sqlite3.h"
19 
20 // Local
21 #include "SQLamarr/preprocessor_symbols.h"
22 #include "SQLamarr/PVReconstruction.h"
23 #include "SQLamarr/GlobalPRNG.h"
24 #include "SQLamarr/SQLiteError.h"
25 
26 namespace SQLamarr
27 {
28  // Internal helper function
30  sqlite3_stmt* stmt,
31  std::string condition,
32  std::string coord
33  )
34  {
35  sqlite3_reset(stmt);
36  sqlite3_bind_text(stmt, 1, condition.c_str(), -1, nullptr);
37  sqlite3_bind_text(stmt, 2, coord.c_str(), -1, nullptr);
38 
39  if (sqlite3_step(stmt) != SQLITE_ROW)
40  {
41  std::cerr
42  << "Failed query for " << condition
43  << " coordinate: " << coord
44  << std::endl;
45  throw SQLiteError("Cannot load parametrization line");
46  }
47 
48  return {
49  static_cast<float>(sqlite3_column_double (stmt, 0)),
50  static_cast<float>(sqlite3_column_double (stmt, 1)),
51  static_cast<float>(sqlite3_column_double (stmt, 2)),
52  static_cast<float>(sqlite3_column_double (stmt, 3)),
53  static_cast<float>(sqlite3_column_double (stmt, 4)),
54  static_cast<float>(sqlite3_column_double (stmt, 5))
55  };
56  }
57 
58 
59  //============================================================================
60  // Constructor
61  //============================================================================
63  SQLite3DB& db,
64  const SmearingParametrization& parametrization
65  )
66  : BaseSqlInterface(db)
67  , m_parametrization (parametrization)
68  {}
69 
70  //============================================================================
71  // SQLite3 extension: rnd_ggg
72  //============================================================================
73  void PVReconstruction::_sql_rnd_ggg (
74  sqlite3_context *context,
75  int argc,
76  sqlite3_value **argv
77  )
78  {
79  if (argc == 6)
80  {
81  const double mu = sqlite3_value_double(argv[0]);
82  const double f1 = sqlite3_value_double(argv[1]);
83  const double f2 = sqlite3_value_double(argv[2]);
84  const double sigma1 = sqlite3_value_double(argv[3]);
85  const double sigma2 = sqlite3_value_double(argv[4]);
86  const double sigma3 = sqlite3_value_double(argv[5]);
87 
88  auto generator = GlobalPRNG::get_or_create(context);
89  std::normal_distribution<double> one_g;
90  std::uniform_real_distribution<double> uniform;
91  const double r = uniform(*generator);
92  const double sigma = (
93  r < f1 ? sigma1 :
94  r < f1 + f2 ? sigma2 :
95  sigma3
96  );
97 
98  const double smear = one_g(*generator)*sigma + mu;
99 
100  sqlite3_result_double(context, smear);
101  return;
102  }
103  sqlite3_result_null(context);
104  }
105 
106 
107 
108  //============================================================================
109  // load_parametrization
110  //============================================================================
111  PVReconstruction::SmearingParametrization
113  const std::string file_path,
114  const std::string table_name,
115  const std::string condition
116  )
117  {
118  sqlite3* db;
119 
120  sqlite3_open_v2(file_path.c_str(), &db, SQLITE_OPEN_READONLY, nullptr);
121 
122  if (!db)
123  throw SQLiteError("Cannot open PVReconstruction DB");
124 
125  char query[1024];
126  sprintf(query, R"(
127  SELECT
128  mu, f1, f2, sigma1, sigma2, sigma3
129  FROM %s
130  WHERE
131  condition = ?
132  AND
133  coord = ?
134  COLLATE NOCASE;
135  )", table_name.c_str());
136 
137  sqlite3_stmt* load_stmt;
138  if (sqlite3_prepare_v2(db, query, -1, &load_stmt, nullptr) != SQLITE_OK)
139  {
140  std::cerr << sqlite3_errmsg(db) << std::endl;
141  throw SQLiteError("Failed preparing a statement");
142  }
143 
144 
146  ret.x() = _get_param_line (load_stmt, condition, "x");
147  ret.y() = _get_param_line (load_stmt, condition, "y");
148  ret.z() = _get_param_line (load_stmt, condition, "z");
149 
150  sqlite3_finalize(load_stmt);
151  sqlite3_close(db);
152 
153 
154  return ret;
155  }
156 
157 
158  //============================================================================
159  // execute
160  //============================================================================
162  {
163  using_sql_function( "rnd_ggg", 6, &_sql_rnd_ggg );
164 
165  sqlite3_stmt* reco_pv = get_statement("reco_pv", R"(
166  INSERT INTO Vertices (
167  mcvertex_id, genevent_id,
168  vertex_type,
169  x, y, z,
170  sigma_x, sigma_y, sigma_z
171  )
172  SELECT
173  mcv.mcvertex_id, mcv.genevent_id,
174  ? AS vertex_type,
175  mcv.x + rnd_ggg(?, ?, ?, ?, ?, ?),
176  mcv.y + rnd_ggg(?, ?, ?, ?, ?, ?),
177  mcv.z + rnd_ggg(?, ?, ?, ?, ?, ?),
178  ? AS sigma_x,
179  ? AS sigma_y,
180  ? AS sigma_z
181  FROM MCVertices AS mcv
182  WHERE mcv.is_primary == TRUE
183  )");
184 
185  int slot_id = 1;
186  sqlite3_bind_int(reco_pv, slot_id++, LAMARR_VERTEX_PRIMARY);
187 
188  for (int iCoord = 0; iCoord < 3; ++iCoord)
189  {
190  sqlite3_bind_double(reco_pv, slot_id++, m_parametrization.data[iCoord].mu);
191  sqlite3_bind_double(reco_pv, slot_id++, m_parametrization.data[iCoord].f1);
192  sqlite3_bind_double(reco_pv, slot_id++, m_parametrization.data[iCoord].f2);
193  sqlite3_bind_double(reco_pv, slot_id++, m_parametrization.data[iCoord].sigma1);
194  sqlite3_bind_double(reco_pv, slot_id++, m_parametrization.data[iCoord].sigma2);
195  sqlite3_bind_double(reco_pv, slot_id++, m_parametrization.data[iCoord].sigma3);
196  }
197 
198  for (int iCoord = 0; iCoord < 3; ++iCoord)
199  {
200  float min_sigma = m_parametrization.data[iCoord].sigma1;
201  if (m_parametrization.data[iCoord].sigma2 < min_sigma)
202  min_sigma = m_parametrization.data[iCoord].sigma2;
203  if (m_parametrization.data[iCoord].sigma3 < min_sigma)
204  min_sigma = m_parametrization.data[iCoord].sigma3;
205 
206  sqlite3_bind_double(reco_pv, slot_id++, min_sigma);
207  }
208 
209  exec_stmt(reco_pv);
210  }
211 }
Abstract interface with helper functions to access an SQLite DB.
sqlite3_stmt * get_statement(const std::string &name, const std::string &query)
Creates or retrieve from cache a statement.
bool exec_stmt(sqlite3_stmt *)
Execute a statement, possibly throwing an exception on failure.
void using_sql_function(const std::string &name, int argc, void(*xFunc)(sqlite3_context *, int, sqlite3_value **))
Register a static function in DB, enabling usage from SQL.
static SmearingParametrization load_parametrization(const std::string file_path, const std::string table_name, const std::string condition)
Instanciate a SmearingParametrization object from an SQLite file.
void execute() override
Execute the algorithm adding primary vertices to Vertices table.
PVReconstruction(SQLite3DB &db, const SmearingParametrization &parametrization)
Constructor.
static PRNG * get_or_create(const sqlite3_context *db, uint64_t seed=no_seed)
Return a pointer to an initialized generator.
Definition: GlobalPRNG.h:99
A database connection handler easying sharing the DB between C++ and Python.
Definition: db_functions.py:24
PVReconstruction::SmearingParametrization_1D _get_param_line(sqlite3_stmt *stmt, std::string condition, std::string coord)
Set of parameters defining a 3-Gaussian resolution function in 1D.
Set of parmeters defining three 3-Gaussian functions for x, y and z.
std::array< SmearingParametrization_1D, 3 > data
Access to raw data in array format.
SmearingParametrization_1D & x()
Read/Write access to coordinate parametrization.
SmearingParametrization_1D & y()
Read/Write access to coordinate parametrization.
SmearingParametrization_1D & z()
Read/Write access to coordinate parametrization.