SQLamarr
The stand-alone ultra-fast simulation option for the LHCb experiment
MCParticleSelector.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 
11 #include "SQLamarr/MCParticleSelector.h"
12 #include "SQLamarr/SQLiteError.h"
13 #include <iostream>
14 #include <algorithm>
15 
16 namespace SQLamarr
17 {
18  //============================================================================
19  // Constructor
20  //============================================================================
22  SQLite3DB& db,
23  const std::vector<uint64_t> retained_status_values,
24  const std::vector<uint64_t> retained_abspid_values
25  )
26  : BaseSqlInterface(db)
27  , m_retained_status_values(retained_status_values)
28  , m_retained_abspid_values(retained_abspid_values)
29  {}
30 
31  //============================================================================
32  // execute
33  //============================================================================
35  {
36  sqlite3_stmt* get_root = get_statement("get_root", R"(
37  SELECT p.genparticle_id, mcv.mcvertex_id, p.genevent_id, v.genvertex_id
38  FROM GenParticles AS p
39  INNER JOIN GenVertices AS v ON v.genvertex_id = p.production_vertex
40  INNER JOIN MCVertices AS mcv ON p.genevent_id = mcv.genevent_id
41  WHERE v.is_primary == TRUE AND mcv.is_primary == TRUE
42  )");
43 
45  bool traversal_status = true;
46 
47  while (traversal_status && exec_stmt(get_root))
48  traversal_status &= process_particle (
49  sqlite3_column_int(get_root, 0),
50  sqlite3_column_int(get_root, 1)
51  );
52 
54 
55  if (!traversal_status)
56  throw SQLiteError("Graph traversal failed.");
57  }
58 
59  //============================================================================
60  // process_particle
61  //============================================================================
62  bool MCParticleSelector::process_particle(int genparticle_id, int prod_vtx)
63  {
64  sqlite3_stmt* get_particle = get_statement("get_particle", R"(
65  SELECT
66  status,
67  pid,
68  production_vertex IS NOT NULL,
69  end_vertex IS NOT NULL
70  FROM GenParticles
71  WHERE genparticle_id = ?
72  )");
73  sqlite3_bind_int(get_particle, 1, genparticle_id);
74 
75 
76  sqlite3_stmt* get_daughters = get_statement("get_daughters", R"(
77  SELECT daughter.genparticle_id
78  FROM GenParticles AS mother
79  INNER JOIN GenParticles AS daughter
80  ON mother.end_vertex = daughter.production_vertex
81  WHERE mother.genparticle_id = ?
82  )");
83  sqlite3_bind_int(get_daughters, 1, genparticle_id);
84 
85 
86  if (!exec_stmt(get_particle))
87  {
88  std::cerr << "Stop iteration at particle " << genparticle_id << std::endl;
89  return false;
90  }
91 
92  const int status = sqlite3_column_int(get_particle, 0);
93  const int pid = sqlite3_column_int(get_particle, 1);
94  const int abspid = abs(pid);
95  const int valid_prod = sqlite3_column_int(get_particle, 2);
96  const int valid_end = sqlite3_column_int(get_particle, 3);
97 
98  bool kept = keep(status, abspid);
99  const int end_vtx = (kept && valid_end) ?
100  get_or_create_end_vertex(genparticle_id) : prod_vtx;
101 
102  std::vector<uint64_t> daughter_ids;
103  while (valid_end && sqlite3_step(get_daughters) == SQLITE_ROW)
104  daughter_ids.push_back (sqlite3_column_int(get_daughters, 0));
105 
106  bool traversal_status = true;
107  for (uint64_t daughter_id: daughter_ids)
108  traversal_status &= process_particle (daughter_id, end_vtx);
109 
110  if (valid_prod && kept) // && prod_vtx != end_vtx)
111  {
112  sqlite3_stmt* insert_mc_particle = get_statement("insert_mc_particle", R"(
113  INSERT OR IGNORE INTO MCParticles (
114  genparticle_id,
115  genevent_id,
116  pid, pe, px, py, pz, m,
117  is_signal
118  )
119  SELECT
120  genparticle_id,
121  genevent_id,
122  pid, pe, px, py, pz, m,
123  status == 889
124  FROM GenParticles
125  WHERE genparticle_id = ?;
126  )");
127  sqlite3_bind_int(insert_mc_particle, 1, genparticle_id);
128  exec_stmt(insert_mc_particle);
129 
130  const int mcparticle_id = last_insert_row();
131 
132  sqlite3_stmt* set_mc_vertices = get_statement("set_mc_vertices", R"(
133  UPDATE MCParticles
134  SET
135  production_vertex = ?,
136  end_vertex = ?
137  WHERE
138  mcparticle_id = ?;
139  )");
140  sqlite3_bind_int(set_mc_vertices, 1, prod_vtx);
141  if (valid_end)
142  sqlite3_bind_int(set_mc_vertices, 2, end_vtx);
143  else
144  sqlite3_bind_null(set_mc_vertices, 2);
145 
146  sqlite3_bind_int(set_mc_vertices, 3, mcparticle_id);
147 
148  exec_stmt(set_mc_vertices);
149  }
150 
151  return traversal_status;
152  }
153 
154  //============================================================================
155  // keep
156  //============================================================================
157  bool MCParticleSelector::keep(int status, int abspid) const
158  {
159  const auto& s_ok = m_retained_status_values;
160  if (std::find(s_ok.begin(), s_ok.end(), status) != s_ok.end())
161  return true;
162 
163  const auto& id_ok = m_retained_abspid_values;
164  if (std::find(id_ok.begin(), id_ok.end(), status) != id_ok.end())
165  return true;
166 
167  if (abspid <= 8) // quarks
168  return false;
169 
170  if (abspid >= 11 && abspid <= 18) // leptons
171  return true;
172 
173  return false;
174  }
175 
176  //============================================================================
177  // get_or_create_end_vertex
178  //============================================================================
179  uint64_t MCParticleSelector::get_or_create_end_vertex (int genparticle_id)
180  {
182  sqlite3_stmt* insert_end_vertex = get_statement("insert_end_vertex", R"(
183  INSERT OR IGNORE INTO
184  MCVertices (genvertex_id, genevent_id, status, is_primary, t, x, y, z)
185  SELECT
186  gv.genvertex_id, gv.genevent_id,
187  gv.status, gv.is_primary, gv.t, gv.x, gv.y, gv.z
188  FROM GenParticles AS gp
189  INNER JOIN GenVertices AS gv
190  ON gp.end_vertex == gv.genvertex_id
191  WHERE gp.genparticle_id = ? AND is_primary == FALSE;
192  )");
193  sqlite3_bind_int (insert_end_vertex, 1, genparticle_id);
194 
195  sqlite3_stmt* get_end_vertex = get_statement("get_end_vertex", R"(
196  SELECT mcv.mcvertex_id
197  FROM GenParticles AS gp
198  INNER JOIN GenVertices AS gv
199  ON gp.end_vertex == gv.genvertex_id
200  INNER JOIN MCVertices AS mcv
201  ON gv.genvertex_id == mcv.genvertex_id
202  WHERE gp.genparticle_id = ?
203  )");
204  sqlite3_bind_int (get_end_vertex, 1, genparticle_id);
205 
206  exec_stmt(insert_end_vertex);
207  if (!exec_stmt(get_end_vertex))
208  throw SQLiteError("MCParticleSelector failed to insert an end-vertex");
209 
210  return sqlite3_column_int (get_end_vertex, 0);
211  }
212 }
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.
void begin_transaction()
Begin an SQL transaction stopping update to disk util end_transaction() is issued
void end_transaction()
End an SQL transaction re-enabling disk updates.
int last_insert_row()
Return the index of the last rows inserted in any table.
bool exec_stmt(sqlite3_stmt *)
Execute a statement, possibly throwing an exception on failure.
bool process_particle(int genparticle_id, int prod_vtx)
Recursive function processing a particles and its daughters (if any).
void execute() override
Execute the algorithm on the database (a batch of data)
uint64_t get_or_create_end_vertex(int genparticle_id)
Returns the UID of the end vertex of a particle, creating it if missing.
MCParticleSelector(SQLite3DB &db, const std::vector< uint64_t > retained_status_values={ LAMARR_LHCB_STABLE_IN_PRODGEN, LAMARR_LHCB_DECAYED_BY_DECAYGEN, LAMARR_LHCB_DECAYED_BY_DECAYGEN_AND_PRODUCED_BY_PRODGEN, LAMARR_LHCB_SIGNAL_IN_LAB_FRAME, LAMARR_LHCB_STABLE_IN_DECAYGEN }, const std::vector< uint64_t > retained_abspid_values={ 6, 22, 23, 24, 25, 32, 33, 34, 35, 36, 37, 102, 130, 310, 311, 321, 411, 421, 413, 423, 415, 425, 431, 435, 511, 521, 513, 523, 515, 525, 531, 535, 541, 545, 441, 10441, 100441, 443, 10443, 20443, 100443, 30443, 9000443, 9010443, 9020443, 445, 10445, 551, 10551, 100551, 110551, 200551, 210551, 553, 10553, 20553, 30553, 100553, 110553, 120553, 130553, 200553, 210553, 220553, 300553, 9000553, 9010553, 555, 10555, 20555, 100555, 110555, 120555, 200555, 557, 100557, 2212, 2212, 3122, 3222, 3212, 3224, 3214, 3114, 3322, 3312, 3324, 3314, 3334, 4122, 4222, 4212, 4112, 4224, 4214, 4114, 4232, 4132, 4322, 4312, 4324, 4314, 4332, 4334, 4412, 4422, 4414, 4424, 4432, 4434, 4444, 5122, 5112, 5212, 5222, 5114, 5214, 5224, 5132, 5232, 5312, 5322, 5314, 5324, 5332, 5334, 5142, 5242, 5412, 5422, 5414, 5424, 5342, 5432, 5442, 5444, 5512, 5522, 5514, 5524, 5532, 5534, 5542, 5544, 5554 })
Initializes and configures the algorithm.
bool keep(int status, int abspid) const
Definition of the criterion to promote a GenParticle to MCParticle.
A database connection handler easying sharing the DB between C++ and Python.
Definition: db_functions.py:24