REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
TRestMySQLToAnalysisProcess.cxx
1 /*************************************************************************
2  * This file is part of the REST software framework. *
3  * *
4  * Copyright (C) 2016 GIFNA/TREX (University of Zaragoza) *
5  * For more information see http://gifna.unizar.es/trex *
6  * *
7  * REST is free software: you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * REST is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have a copy of the GNU General Public License along with *
18  * REST in $REST_PATH/LICENSE. *
19  * If not, see http://www.gnu.org/licenses/. *
20  * For the list of contributors see $REST_PATH/CREDITS. *
21  *************************************************************************/
22 
79 #include "TRestMySQLToAnalysisProcess.h"
80 using namespace std;
81 
82 #if defined USE_SQL
83 #include <mysql/mysql.h>
84 #endif
85 
87 
92 
108  Initialize();
109  LoadConfig(configFilename);
110 }
111 
116 
121  SetName(this->ClassName());
122  SetTitle("Default config");
123 }
124 
137 void TRestMySQLToAnalysisProcess::LoadConfig(const string& configFilename, const string& name) {
138  if (LoadConfigFromFile(configFilename, name)) LoadDefaultConfig();
139 }
140 
146  fStartTimestamp = fRunInfo->GetStartTimestamp();
147  fEndTimestamp = fRunInfo->GetEndTimestamp();
148 
149  if (fSQLVariables.size() > 0)
150  FillDBArrays();
151  else {
152  RESTWarning
153  << "TRestMySQLToAnalysisProcess::InitProcess. No data base field entries have been specified!"
154  << RESTendl;
155  RESTWarning << "This process will do nothing!" << RESTendl;
156  }
157 }
158 
164  SetSectionName(this->ClassName());
165 
166 #ifndef USE_SQL
167  RESTWarning << "TRestMySQLToAnalysisProcess. REST was compiled without mySQL support" << RESTendl;
168  RESTWarning << "This process will not be funcional" << RESTendl;
169 #endif
170 }
171 
176  fEvent = inputEvent;
177 
178 #if defined USE_SQL
179  RESTDebug << "TRestMySQLToAnalysisProcess. Ev ID : " << fEvent->GetID() << RESTendl;
180  RESTDebug << "TRestMySQLToAnalysisProcess. Get timestamp : " << fEvent->GetTime() << RESTendl;
181  for (int n = 0; n < fAnaTreeVariables.size(); n++)
182  RESTDebug << "TRestMySQLToAnalysisProcess. Variable : " << fAnaTreeVariables[n]
183  << " value : " << GetDBValueAtTimestamp(n, fEvent->GetTime()) << RESTendl;
184 
186 
187  for (int n = 0; n < fAnaTreeVariables.size(); n++)
188  SetObservableValue((string)fAnaTreeVariables[n], GetDBValueAtTimestamp(n, fEvent->GetTime()));
189 #else
190  if (fCheckSQL) {
191  RESTWarning << "REST was not linked to SQL libraries. Run cmake using -DREST_SQL=ON" << RESTendl;
192  RESTWarning << "Clearing process metadata info." << RESTendl;
193  RESTWarning << "Please, remove this process from the data chain or enable support for MySQL."
194  << RESTendl;
195 
196  fAnaTreeVariables.clear();
197  fSQLVariables.clear();
198  fDBServerName = "";
199  fDBName = "";
200  fDBUserName = "";
201  fDBUserPass = "";
202  fDBTable = "";
203 
204  fCheckSQL = false;
205  }
206 #endif
207 
208  return fEvent;
209 }
210 
216  size_t pos = 0;
217 
218  fDBServerName = GetParameter("server", "");
219  if (fDBServerName == "")
220  RESTError << "TRestMySQLToAnalysisProcess. Database server name not found!" << RESTendl;
221 
222  fDBName = GetParameter("database", "");
223  if (fDBName == "") RESTError << "TRestMySQLToAnalysisProcess. Database not found!" << RESTendl;
224 
225  fDBUserName = GetParameter("user", "");
226  if (fDBUserName == "")
227  RESTError << "TRestMySQLToAnalysisProcess. Database user name not found!" << RESTendl;
228 
229  fDBUserPass = GetParameter("password", "");
230  if (fDBUserPass == "")
231  RESTError << "TRestMySQLToAnalysisProcess. Database user password not found!" << RESTendl;
232 
233  fDBTable = GetParameter("table", "");
234  if (fDBTable == "")
235  RESTError << "TRestMySQLToAnalysisProcess. Database table name not found!" << RESTendl;
236 
237  string definition;
238  while ((definition = GetKEYDefinition("dbEntry", pos)) != "") {
239  TString sqlName = GetFieldValue("sqlName", definition);
240  fSQLVariables.push_back((string)sqlName);
241 
242  TString anaName = GetFieldValue("anaName", definition);
243  fAnaTreeVariables.push_back((string)anaName);
244  }
245 }
246 
253  BeginPrintProcess();
254 
255  RESTMetadata << "SQL data extracted from:" << RESTendl;
256  RESTMetadata << "- database : " << fDBName << RESTendl;
257  RESTMetadata << "- table : " << fDBTable << RESTendl;
258  RESTMetadata << " " << RESTendl;
259 
260  RESTMetadata << "List of variables added to the analysis tree" << RESTendl;
261  RESTMetadata << " ------------------------------------------ " << RESTendl;
262  for (unsigned int n = 0; n < fAnaTreeVariables.size(); n++) {
263  RESTMetadata << " + SQL field : " << fSQLVariables[n] << RESTendl;
264  RESTMetadata << " - Tree name : " << fAnaTreeVariables[n] << RESTendl;
265  RESTMetadata << " - Min value : " << fMinValues[n] << RESTendl;
266  RESTMetadata << " - Max value : " << fMaxValues[n] << RESTendl;
267  RESTMetadata << " " << RESTendl;
268  }
269  EndPrintProcess();
270 }
271 
282 #if defined USE_SQL
283  MYSQL* conn = mysql_init(nullptr);
284  if (conn == nullptr) {
285  RESTError << "TRestMySQLToAnalysisProcess::InitProcess. mysql_init() failed" << RESTendl;
286  exit(1);
287  }
288 
289  if (!mysql_real_connect(conn, fDBServerName.c_str(), fDBUserName.c_str(), fDBUserPass.c_str(),
290  fDBName.c_str(), 0, nullptr, 0)) {
291  RESTError << "TRestMySQLToAnalysisProcess::InitProcess. Connection to DB failed!" << RESTendl;
292  RESTError << mysql_error(conn) << RESTendl;
293  exit(1);
294  }
295 
296  string sqlQuery = BuildQueryString();
297  RESTDebug << sqlQuery << RESTendl;
298  if (mysql_query(conn, sqlQuery.c_str())) {
299  RESTError << "Error making query to SQL database" << RESTendl;
300  RESTError << mysql_error(conn) << RESTendl;
301  RESTError << "Query string : " << sqlQuery << RESTendl;
302  exit(1);
303  }
304 
305  MYSQL_RES* result = mysql_store_result(conn);
306 
307  if (result == nullptr) {
308  RESTError << "Error getting result from SQL query" << RESTendl;
309  RESTError << mysql_error(conn) << RESTendl;
310  RESTError << "Query string : " << sqlQuery << RESTendl;
311  exit(1);
312  }
313 
314  int num_fields = mysql_num_fields(result);
315  int num_rows = mysql_num_rows(result);
316 
317  // We double the average sampling of data in the given range
318  fSampling = (fEndTimestamp - fStartTimestamp) / num_rows / 2;
319 
320  if (num_rows < 3) {
321  this->SetError("No DB entries found for the run period!");
322  fDataBaseExists = false;
323  return;
324  }
325 
326  // We register all the data inside a std::vector.
327  MYSQL_ROW row;
328  std::vector<std::vector<Double_t>> data;
329 
330  while ((row = mysql_fetch_row(result))) {
331  std::vector<Double_t> dataRow;
332  for (int i = 0; i < num_fields; i++) {
333  string value;
334  if (row[i])
335  value = row[i];
336  else
337  value = "NULL";
338 
339  dataRow.push_back(StringToDouble(value));
340  }
341  data.push_back(dataRow);
342  }
343 
344  fMinValues.clear();
345  fMaxValues.clear();
346  for (int j = 0; j < data.size(); j++) {
347  if (j == 0)
348  for (int n = 1; n < data.front().size(); n++) {
349  fMinValues.push_back(data.front()[n]);
350  fMaxValues.push_back(data.front()[n]);
351  }
352 
353  for (int n = 1; n < data[j].size(); n++) {
354  if (fMinValues[n - 1] > data[j][n]) fMinValues[n - 1] = data[j][n];
355  if (fMaxValues[n - 1] < data[j][n]) fMaxValues[n - 1] = data[j][n];
356  }
357  }
358 
359  RESTDebug << "Raw data size " << data.size() << RESTendl;
360 
361  fDBdata.clear();
362  cout.precision(10);
363  // We finally fill the array with a fixed time bin (given by fSampling)
364  Double_t timeNow = fStartTimestamp;
365  Int_t dbEntry = 0;
366  while (timeNow < fEndTimestamp) {
367  while (timeNow > data[dbEntry][0] && dbEntry + 1 < data.size()) dbEntry++;
368 
369  std::vector<Double_t> dataBuff;
370  if (timeNow < data.front()[0]) {
371  for (int n = 1; n < data.front().size(); n++) dataBuff.push_back(data.front()[n]);
372  } else if (timeNow > data.back()[0]) {
373  for (int n = 1; n < data.back().size(); n++) dataBuff.push_back(data.back()[n]);
374  } else {
375  for (int n = 1; n < data[dbEntry].size(); n++) {
376  double y2 = data[dbEntry][n];
377  double y1 = data[dbEntry - 1][n];
378 
379  // Normalized field
380  double x2 = data[dbEntry][0];
381  double x1 = data[dbEntry - 1][0];
382 
383  double m = (y2 - y1) / (x2 - x1);
384  double l = y1 - m * x1;
385 
386  dataBuff.push_back(m * timeNow + l);
387  }
388  }
389 
390  timeNow += fSampling;
391  fDBdata.push_back(dataBuff);
392  }
393 
394  RESTDebug << "Added entries : " << fDBdata.size() << RESTendl;
395  if (GetVerboseLevel() >= TRestStringOutput::REST_Verbose_Level::REST_Debug)
396  TRestTools::PrintTable(fDBdata, 0, 5);
397 
398  mysql_close(conn);
399 #else
400  RESTWarning << "REST was not linked to SQL libraries. Run cmake using -DREST_SQL=ON" << RESTendl;
401 #endif
402 }
403 
408  string sqlQuery = "SELECT timestamp";
409  for (unsigned int n = 0; n < fSQLVariables.size(); n++) {
410  sqlQuery += ",";
411  sqlQuery += fSQLVariables[n];
412  }
413  sqlQuery += " FROM " + fDBTable + " where timestamp between ";
414 
415  string startStr = Form("%10.0lf", fStartTimestamp);
416  string endStr = Form("%10.0lf", fEndTimestamp);
417 
418  sqlQuery += startStr + " and " + endStr;
419 
420  return sqlQuery;
421 }
422 
428 Double_t TRestMySQLToAnalysisProcess::GetDBValueAtTimestamp(Int_t index, Double_t timestamp) {
429  if (!fDataBaseExists) return -1;
430  Int_t bin = (Int_t)((timestamp - fStartTimestamp) / fSampling);
431 
432  if (bin < 0) return fDBdata.front()[index];
433  if ((unsigned int)(bin + 1) >= fDBdata.size()) return fDBdata.back()[index];
434 
435  double y2 = fDBdata[bin + 1][index];
436  double y1 = fDBdata[bin][index];
437 
438  double m = (y2 - y1) / fSampling;
439  double l = y1 - m * (fStartTimestamp + bin * fSampling);
440 
441  return m * timestamp + l;
442 }
A base class for any REST event.
Definition: TRestEvent.h:38
This process connects to a SQL database and adds new observables inside the analysis tree.
void LoadDefaultConfig()
Function to load the default config in absence of RML input.
void InitFromConfigFile() override
Function reading input parameters from the RML TRestMySQLToAnalysisProcess section.
Double_t GetDBValueAtTimestamp(Int_t index, Double_t timestamp)
This method will retrieve the given data field component, specified by the argument index at the give...
std::string BuildQueryString()
Dedicated method to help building the SQL query string.
void InitProcess() override
Function to use in initialization of process members before starting to process the event.
void FillDBArrays()
This method is the one accessing the SQL database and filling the internal arrays with data that will...
void PrintMetadata() override
It prints out basic information of the SQL database used to generate the analysis tree observables....
void Initialize() override
Function to initialize input/output event members and define the section name and library version.
TRestMySQLToAnalysisProcess()
Default constructor.
TRestEvent * ProcessEvent(TRestEvent *inputEvent) override
The main processing event function.
void LoadConfig(const std::string &configFilename, const std::string &name="")
Function to load the configuration from an external configuration file.
@ REST_Debug
+show the defined debug messages
static int PrintTable(std::vector< std::vector< T >> data, Int_t start=0, Int_t end=0)
Prints the contents of the vector table given as argument in screen. Allowed types are Int_t,...
Definition: TRestTools.cxx:163
Int_t GetChar(std::string hint="Press a KEY to continue ...")
Helps to pause the program, printing a message before pausing.
Double_t StringToDouble(std::string in)
Gets a double from a string.