BmnRoot 26.10.0-18-g4e3414f9
Software framework of the BM@N experiment
Loading...
Searching...
No Matches
TangoData.cxx
Go to the documentation of this file.
1#include "TangoData.h"
2
3#include "TColor.h"
4#include "TROOT.h"
5#include "TRandom.h"
6#include "TangoConnection.h"
7#include "UniRun.h"
8
9#include <TAxis.h>
10#include <TCanvas.h>
11#include <TGraph.h>
12#include <TGraph2D.h>
13#include <TH2D.h>
14#include <TLegend.h>
15#include <TMultiGraph.h>
16#include <TSQLServer.h>
17#include <TSQLStatement.h>
18#include <TStyle.h>
19#include <algorithm>
20#include <cctype>
21#include <cmath>
22#include <fstream>
23#include <iostream>
24using namespace std;
25
26// Tango Database connection based on MySQL before 2020-03-24
27const char* const TANGO_DB_USERNAME_b2020 = "tango";
28const char* const TANGO_DB_PASSWORD_b2020 = "tangompd";
29const char* const TANGO_DB_HOST_b2020 = "10.18.11.66";
30const char* const TANGO_DB_NAME_b2020 = "hdbpp";
31
33
39
40// Copy constructor
49
51
53
54TangoTimeInterval::TangoTimeInterval(TDatime start_time_interval, TDatime end_time_interval)
55{
56 start_time = start_time_interval;
57 end_time = end_time_interval;
58}
59
61
62/**
63 * TangoData CLASS IMPLEMENTATION
64 **/
65
66/** Single Constructor: fill Tango data array according to the given parameters
67 * Tango database connection is defined in the 'tango_db_settings.h' file
68 * Parameters:
69 * start_date - time from which to start reading the parameter, format: "YYYY-MM-DD HH:MM:SS"
70 * (e.g. "2015-03-13 23:00:00")
71 * end_date - end time of reading the parameter, the same format (e.g. "2015-03-13 24:00:00")
72 * system_name - name of the system, i.e. Tango domain (e.g. "magnet", "fhcal" or "gem")
73 * parameter_name - name of hardware parameter stored in Tango, i.e. Tango attribute
74 * (e.g. "vch_2_1" for FHCal or "vmon_0" for GEM)
75 * member_name - name of the Tango member, i.e. device (e.g. "hv_1" for FHCal or "mod_0" for GEM),
76 * it can be given with the Tango family as "family/member" if the member name is not unique
77 * in the domain (e.g. "caen_232/mod_2" for CSC or "plane1_top/adcsc_7_temp" for FSD),
78 * empty string - the member is not used
79 **/
80TangoData::TangoData(const char* start_date,
81 const char* end_date,
82 const char* system_name,
83 const char* parameter_name,
84 const char* member_name,
85 int verbose)
86 : strSystemName(system_name)
87 , strParameterName(parameter_name)
88 , strMemberName(member_name)
89 , strUserName("")
90 , strStartDate(start_date)
91 , strEndDate(end_date)
92 , iVerbose(verbose)
93{
95}
96
97/** Run Range Constructor: fill Tango data array for the time interval from the start time of the first run
98 * to the end time of the last run of the given range (the gaps between runs are included)
99 * The run times are taken from the Unified Condition Database (UniRun)
100 * Parameters:
101 * period_number - period (session) number of the runs (e.g. 8)
102 * start_run - number of the first run of the range (e.g. 6000)
103 * end_run - number of the last run of the range (set equal to start_run to read a single run)
104 * system_name, parameter_name, member_name, verbose - the same as in the time interval constructor
105 * Use GetRunAverageTangoData() to average the parameter only over the time of the runs
106 **/
107TangoData::TangoData(int period_number,
108 int start_run,
109 int end_run,
110 const char* system_name,
111 const char* parameter_name,
112 const char* member_name,
113 int verbose)
114 : strSystemName(system_name)
115 , strParameterName(parameter_name)
116 , strMemberName(member_name)
117 , strUserName("")
118 , iVerbose(verbose)
119 , iPeriodNumber(period_number)
120 , iStartRun(start_run)
121 , iEndRun(end_run)
122{
123 if (SetRunRangeDates(period_number, start_run, end_run) == 0)
125}
126
128{
129 if (arrTangoData != nullptr) {
130 arrTangoData->Delete();
131 delete arrTangoData;
132 }
133}
134
136{
137 TString strFullName = strSystemName + ":" + strParameterName;
138 if (strMemberName != "")
139 strFullName += " (" + strMemberName + ")";
140
141 return strFullName;
142}
143
144// non-user function SetRunRangeDates sets strStartDate and strEndDate to the start time of the first run
145// and the end time of the last run existing in the given run range of the period,
146// and fills vecRunIntervals with the time intervals of the runs (runs without end time are skipped)
147// Returns: 0 - in case of the success, < 0 - if an error occured
148// the last successfully read run range is cached to avoid repeated requests to the Unified Database,
149// e.g. when many Tango parameters are read for the same runs
152static vector<TangoTimeInterval> cached_run_intervals;
153
154int TangoData::SetRunRangeDates(int period_number, int start_run, int end_run)
155{
156 vecRunIntervals.clear();
157 if (start_run > end_run) {
158 cout << "ERROR: start run (" << start_run << ") cannot be greater than end run (" << end_run << ")" << endl;
159 return -1;
160 }
161
162 if ((period_number == cached_period) && (start_run == cached_start_run) && (end_run == cached_end_run)) {
166 if (iVerbose)
167 cout << "Run range " << period_number << ":" << start_run << "-" << end_run
168 << " (from the cache) corresponds"
169 << " to the time " << strStartDate << " - " << strEndDate << endl;
170 return 0;
171 }
172
173 // get runs existing in the database for the given range (run numbers can have gaps)
174 UniqueRunNumber* run_numbers = nullptr;
175 int run_count = UniRun::GetRunNumbers(run_numbers, period_number, start_run, period_number, end_run);
176 if (run_count < 0) {
177 cout << "ERROR: getting run numbers from the Unified Database has been failed" << endl;
178 return -2;
179 }
180 if (run_count == 0) {
181 delete[] run_numbers;
182 cout << "ERROR: there are no runs in the range " << period_number << ":" << start_run << "-" << end_run
183 << " in the Unified Database" << endl;
184 return -3;
185 }
186 int first_run = run_numbers[0].run_number, last_run = run_numbers[run_count - 1].run_number;
187
188 // get start and end times of every run in the range
189 TString start_date, end_date;
190 for (int i = 0; i < run_count; i++) {
191 int run_number = run_numbers[i].run_number;
192 UniRun* pRun = UniRun::GetRun(period_number, run_number);
193 if (pRun == nullptr) {
194 cout << "ERROR: run " << period_number << ":" << run_number << " was not found in the Unified Database"
195 << endl;
196 delete[] run_numbers;
197 vecRunIntervals.clear();
198 return -4;
199 }
200 TDatime run_start = pRun->GetStartDatetime();
201 TDatime* run_end = pRun->GetEndDatetime();
202 delete pRun;
203 if (i == 0)
204 start_date = run_start.AsSQLString();
205
206 if (run_end == nullptr) {
207 // the end time of the last run defines the end of the whole time interval
208 if (i == run_count - 1) {
209 cout << "ERROR: there is no end time for the last run " << period_number << ":" << run_number
210 << " in the Unified Database" << endl;
211 delete[] run_numbers;
212 vecRunIntervals.clear();
213 return -5;
214 }
215 cout << "WARNING: there is no end time for the run " << period_number << ":" << run_number
216 << " in the Unified Database, it is excluded from the run time intervals" << endl;
217 continue;
218 }
219 if (i == run_count - 1)
220 end_date = run_end->AsSQLString();
221
222 vecRunIntervals.push_back(TangoTimeInterval(run_start, *run_end));
223 delete run_end;
224 }
225 delete[] run_numbers;
226
227 strStartDate = start_date;
228 strEndDate = end_date;
229 if (iVerbose)
230 cout << "Run range " << period_number << ":" << first_run << "-" << last_run << " (" << run_count
231 << " runs) corresponds to the time " << strStartDate << " - " << strEndDate << endl;
232
233 cached_period = period_number, cached_start_run = start_run, cached_end_run = end_run;
236
237 return 0;
238}
239
240// non-user function InitTangoData selects the Tango database (MySQL before 2020-03-25, PgSQL after)
241// by the start date and fills the Tango data array
243{
244 if (strcmp(strStartDate.Data(), "2020-03-25") < 0) {
245 IsOldMySQL = true;
246 if (iVerbose)
247 cout << "Old MySQL Database is used to get Tango data" << endl;
248 } else if (iVerbose)
249 cout << "PostgreSQL Database is used to get Tango data" << endl;
250
252}
253
254// non-user function GetTangoParameter gets hardware data from the Tango database and write to the arrTangoData
255// First, name of the target table with required parameter is extracted from the Tango Base Table,
256// then required data are selected from the target table corresponding the given time interval.
257// Returns: 0 - in case of the success, < 0 - if an error occured
259{
260 if (iVerbose)
261 cout << "Input Start Date = " << strStartDate.Data() << endl;
262 if (iVerbose)
263 cout << "Input End Date = " << strEndDate.Data() << endl;
264 if ((strStartDate == "") || (strEndDate == "")) {
265 cout << "ERROR: start datetime and end datetime should not be empty!" << endl;
266 return -1;
267 }
268 if (strStartDate < "2000-01-01") {
269 cout << "ERROR: start date cannot be less than 2000 year" << endl;
270 return -2;
271 }
272
273 // new start and end datetime with time zone if PgSQL
274 TString start_date_new(strStartDate), end_date_new(strEndDate);
275 if (!IsOldMySQL)
276 start_date_new += " Europe/Moscow", end_date_new += " Europe/Moscow";
277
278 // TANGO database connection (MySQL before 2020-03-24 and PgSQL after)
279 TangoConnection* connDb = nullptr;
280 if (IsOldMySQL)
283 else
284 connDb = TangoConnection::Open();
285 if (connDb == nullptr)
286 return -3;
287 TSQLServer* db_server = connDb->GetSQLServer();
288 if (db_server == nullptr)
289 return -4;
290
291 if (db_server->GetTables(db_server->GetDB()) == nullptr)
292 return -5;
293
294 // searching for a table name with corresponding parametter type, where the parameter with given system and
295 // parameter names is stored Statement returns parameter ID and parameter table
296 TString strStatement;
297 if (IsOldMySQL)
298 strStatement = TString::Format(
299 "SELECT att_conf_id, data_type "
300 "FROM att_conf ac join att_conf_data_type acdt on ac.att_conf_data_type_id = acdt.att_conf_data_type_id "
301 "WHERE family='%s' and name='%s' ",
302 strSystemName.Data(), strParameterName.Data());
303 else {
304 strStatement = TString::Format("SELECT att_conf_id, table_name "
305 "FROM att_conf "
306 "WHERE domain='%s' and name='%s' ",
307 strSystemName.Data(), strParameterName.Data());
308 // the member name can be given with the family as "family/member" if the member name is not unique
309 // in the domain (e.g. "caen_232/mod_2" and "caen_240/mod_2" for CSC)
310 TString family_name(""), member_name(strMemberName);
311 Ssiz_t slash_pos = strMemberName.First('/');
312 if (slash_pos != kNPOS) {
313 family_name = strMemberName(0, slash_pos);
314 member_name = strMemberName(slash_pos + 1, strMemberName.Length() - slash_pos - 1);
315 }
316 if (family_name != "")
317 strStatement += TString::Format("and family = '%s' ", family_name.Data());
318 if (member_name != "")
319 strStatement += TString::Format("and member = '%s' ", member_name.Data());
320 strStatement += "ORDER BY att_conf_id";
321 }
322
323 if (iVerbose)
324 cout << "Processing the following SQL request to get info on the Tango parameter:" << endl
325 << strStatement << endl;
326 TSQLStatement* stmt_select = db_server->Statement(strStatement);
327 if (!stmt_select->Process()) {
328 cout << "ERROR: getting info on parameter from Tango has been failed: " << GetFullName() << endl;
329 delete stmt_select;
330 return -6;
331 }
332
333 stmt_select->StoreResult();
334 if (!stmt_select->NextResultRow()) {
335 cout << "ERROR: There is no Tango parameter '" << GetFullName() << endl;
336 delete stmt_select;
337 return -7;
338 }
339 // Tango team duplicated (old MySQL solution) parameters for every Nuclotron session
340 if ((IsOldMySQL) && (stmt_select->GetNumAffectedRows() > 1) && (strcmp(strEndDate.Data(), "2018-01-01") > 0)) {
341 if (!stmt_select->NextResultRow()) {
342 cout << "ERROR: There is no second row for parameter '" << strParameterName << "' for " << strSystemName
343 << " detector" << endl;
344 delete stmt_select;
345 return -8;
346 }
347 }
348
349 int parameter_id = stmt_select->GetInt(0);
350 TString table_name(stmt_select->GetString(1));
351 // several Tango parameters can correspond to the given names, e.g. the same member name in different families
352 if ((!IsOldMySQL) && (stmt_select->NextResultRow()))
353 cout << "WARNING: several Tango parameters correspond to '" << GetFullName()
354 << "', the first one is used. Specify the family in the member name as \"family/member\"" << endl;
355 if (IsOldMySQL)
356 table_name = TString::Format("att_%s", table_name.Data());
357 if (iVerbose)
358 cout << "Found Data Table name = " << table_name << ". Parameter ID = " << parameter_id << endl;
359 delete stmt_select;
360
361 // parse parameter type. current support for att_array_devdouble, att_array_devboolean, att_scalar_devdouble,
362 // att_scalar_devboolean and integer types read as numeric values: att_scalar_devshort, att_scalar_devlong,
363 // att_scalar_devlong64 and att_scalar_devstate
364 Tango_Parameter_Type par_type;
365 if (table_name.Contains("array_devdouble"))
366 par_type = Tango_Double_Array;
367 else if (table_name.Contains("array_devboolean"))
368 par_type = Tango_Bool_Array;
369 else if (table_name.Contains("scalar_devdouble") || table_name.Contains("scalar_devshort")
370 || table_name.Contains("scalar_devlong") || table_name.Contains("scalar_devstate"))
371 par_type = Tango_Double;
372 else if (table_name.Contains("scalar_devboolean"))
373 par_type = Tango_Bool;
374 else {
375 cout << "ERROR: This Tango type is not supported: '" << table_name << "'" << endl;
376 return -9;
377 }
378
379 // getting data from the table found by the attribute type
380 TString query_data;
381 if (IsOldMySQL)
382 query_data = "SELECT date_format(data_time, '%Y-%m-%d %H:%i:%S'), value_r ";
383 else
384 query_data = "SELECT to_char(data_time, 'YYYY-MM-DD HH24:MI:SS.MS'), value_r ";
385
386 if (par_type > 10) // if the parameter is stored as array of values
387 query_data += ", dim_x_r, dim_x_w, idx ";
388
389 // add a new point with the previous value (<=date_start)
390 query_data += TString::Format("FROM %s "
391 "WHERE att_conf_id='%d' and ((data_time > '%s' and data_time <= '%s') "
392 "or (data_time = (SELECT max(data_time) FROM %s WHERE att_conf_id='%d' and data_time "
393 "<= '%s' and value_r is not null))) "
394 "and value_r is not null ",
395 table_name.Data(), parameter_id, start_date_new.Data(), end_date_new.Data(),
396 table_name.Data(), parameter_id, start_date_new.Data());
397
398 if (par_type > 10) // if the parameter is stored as array of values
399 query_data += "ORDER BY data_time,idx";
400 else
401 query_data += "ORDER BY data_time";
402
403 if (iVerbose)
404 cout << "Query data with the following SQL request:" << endl << query_data << endl;
405 stmt_select = db_server->Statement(query_data);
406 if (!stmt_select->Process()) {
407 cout << "ERROR: getting parameter values from Tango has been failed" << endl;
408 delete stmt_select;
409 return -10;
410 }
411
412 stmt_select->StoreResult();
413
414 Int_t cur_num = 0;
415 TangoTimeParameter* par = nullptr;
416 // create Tango data array and write data to it
417 arrTangoData = new TObjArray();
418 arrTangoData->SetName(
419 TString::Format("'%s' parameter for %s detector", strParameterName.Data(), strSystemName.Data()));
420 arrTangoData->SetOwner(kTRUE);
421 while (stmt_select->NextResultRow()) {
422 const char* pc_datetime = stmt_select->GetString(0);
423 TDatime datetime(pc_datetime);
424 // shift the previous time va;ue to the date_start position
425 if ((cur_num == 0) && (strcmp(pc_datetime, strStartDate) < 0))
426 datetime.Set(strStartDate);
427
428 int i_par_len = 1;
429 if (par_type > 10)
430 i_par_len = stmt_select->GetInt(2);
431 if (i_par_len == 0) {
432 cout << "ERROR: Parameter length cannot be equal 0" << endl;
433 delete stmt_select;
435 return -11;
436 }
437
438 int i_real_par_len = 1;
439 if (par_type > 10)
440 i_real_par_len = stmt_select->GetInt(3);
441 if (i_real_par_len == 0) {
442 cout << "ERROR: Real parameter length cannot be equal 0" << endl;
443 delete stmt_select;
445 return -12;
446 }
447
448 par = new TangoTimeParameter(datetime, par_type);
449 // cout<<par.parameter_time.AsString()<<endl;
450 for (int ind = 0; ind < i_par_len; ind++) {
451 if (ind > 0)
452 stmt_select->NextResultRow();
453
454 int i_idx = 0;
455 if (par_type > 10)
456 i_idx = stmt_select->GetInt(4);
457 // cout<<"idx:ind - "<<idx<<":"<<ind<<endl;
458 if (i_idx != ind) {
459 cout << "ERROR: idx should be equal index of the parameter array" << endl;
460 delete stmt_select;
462 return -13;
463 }
464
465 if (ind >= i_real_par_len)
466 continue;
467
468 if ((par_type == Tango_Bool_Array) || (par_type == Tango_Bool)) {
469 // boolean value is returned as a number by MySQL and as "t" or "f" by PgSQL
470 TString str_val = stmt_select->GetString(1);
471 bool b_val = (str_val == "t") || (str_val == "true") || (str_val.Atoi() != 0);
472 par->bool_parameter_value.push_back(b_val);
473 par->double_parameter_value.push_back(b_val);
474 // cout<<par.bool_parameter_value[par.bool_parameter_value.size()-1]<<endl;
475 } else {
476 double d_val = stmt_select->GetDouble(1);
477 par->double_parameter_value.push_back(d_val);
478 // cout<<par.double_parameter_value[par.double_parameter_value.size()-1]<<endl;
479 }
480 }
481 if (iVerbose)
482 cout << "Boolean parameter value size = " << par->bool_parameter_value.size() << endl;
483 if (iVerbose)
484 cout << "Double parameter value size = " << par->double_parameter_value.size() << endl;
485
486 arrTangoData->Add(par);
487 cur_num++;
488 }
489 delete stmt_select;
490
491 // add date_end point (if not exists) equal to the the previous value
492 // (the last archived value is extended even if the archiving was stopped before date_end)
493 if ((par != nullptr) && (strcmp(par->parameter_time.AsSQLString(), strEndDate.Data()) < 0)) {
494 TangoTimeParameter* par_last = new TangoTimeParameter(*par);
495 par_last->parameter_time.Set(strEndDate);
496 arrTangoData->Add(par_last);
497 }
498
499 return 0;
500}
501
502// Function displays hardware data obtained from Tango, e.g. FHCal voltage in time interval, in console
504{
505 if (arrTangoData == nullptr) {
506 cout << "ERROR: Tango parameter has not been obtained" << endl;
507 return;
508 }
509
510 int def_precision = cout.precision();
511 cout.precision(17);
512
513 int par_length = 0;
514 for (int i = 0; i < arrTangoData->GetEntriesFast(); i++) {
516 cout << pParameter->parameter_time.AsSQLString() << endl;
517
518 // cout<<TD->dataArray[i].parameter_length<<endl;
519 par_length = pParameter->double_parameter_value.size();
520 for (int j = 0; j < par_length; j++)
521 cout << pParameter->double_parameter_value[j] << " ";
522 cout << "" << endl << endl;
523 }
524
525 cout.precision(def_precision);
526 return;
527}
528
529// Function displays a set of "simple" parameters obtained from Tango, e.g. GEMs high voltages voltage, in console
530void TangoData::PrintTangoArrayConsole(vector<TangoData*> vecTangoData)
531{
532 for (const auto& tango_data : vecTangoData) {
533 cout << "The current parameter: " << tango_data->GetFullName() << endl;
534 tango_data->PrintTangoDataConsole();
535 }
536}
537
538// non-user function GetSourceName returns "domain_member" of the Tango parameter or "domain" if the member is not set
539static TString GetSourceName(TangoData* pTangoData)
540{
541 TString source_name = pTangoData->GetSystemName();
542 if (pTangoData->GetMemberName() != "")
543 source_name += "_" + pTangoData->GetMemberName();
544 return source_name;
545}
546
547// non-user function GetRangeSuffix returns the range of the Tango parameter:
548// for the Run Range Constructor - the period and run range "_p<period>_r<start>_<end>"
549// (e.g. "_p9_r9696_9730", or "_p9_r9696" for a single run),
550// for the time interval - the start and end dates "_t<YYYYMMDD>_<HHMM>_<YYYYMMDD>_<HHMM>"
551// (e.g. "_t20250301_1000_20250301_1600")
553{
554 if (pTangoData->GetPeriodNumber() >= 0) {
555 TString run_suffix = TString::Format("_p%d_r%d", pTangoData->GetPeriodNumber(), pTangoData->GetStartRun());
556 if (pTangoData->GetEndRun() != pTangoData->GetStartRun())
557 run_suffix += TString::Format("_%d", pTangoData->GetEndRun());
558 return run_suffix;
559 }
560
561 if ((pTangoData->GetStartDate() == "") || (pTangoData->GetEndDate() == ""))
562 return "";
563 TDatime start_date(pTangoData->GetStartDate()), end_date(pTangoData->GetEndDate());
564 return TString::Format("_t%d_%04d_%d_%04d", start_date.GetDate(), start_date.GetTime() / 100, end_date.GetDate(),
565 end_date.GetTime() / 100);
566}
567
568// non-user function GetDataName returns the name of the Tango parameter used in the canvas names:
569// "domain_member_attribute" with the run range or time interval (e.g. "fhcal_hv_1_vch_2_1_p9_r9696_9730")
570static TString GetDataName(TangoData* pTangoData)
571{
572 return GetSourceName(pTangoData) + "_" + pTangoData->GetParameterName() + GetRangeSuffix(pTangoData);
573}
574
575// non-user function GetArrayDataName returns the name of the set of Tango parameters used in the canvas names:
576// the name of the first parameter + "_to_" + the name of the last one; if domain, member and ranges of the parameters
577// are the same, only the attribute of the last one is added, e.g. "fhcal_hv_1_vch_2_1_to_vch_2_10_p9_r9696_9730"
578static TString GetArrayDataName(vector<TangoData*>& vecTangoData)
579{
580 TangoData *pFirst = vecTangoData.front(), *pLast = vecTangoData.back();
581 if (vecTangoData.size() == 1)
582 return GetDataName(pFirst);
583
584 if ((GetSourceName(pFirst) == GetSourceName(pLast)) && (GetRangeSuffix(pFirst) == GetRangeSuffix(pLast)))
585 return GetSourceName(pFirst) + "_" + pFirst->GetParameterName() + "_to_" + pLast->GetParameterName()
586 + GetRangeSuffix(pFirst);
587
588 return GetDataName(pFirst) + "_to_" + GetDataName(pLast);
589}
590
591// non-user function GetArrayTitle returns the title of the set of Tango parameters for the graphs:
592// the full names of the first and last parameters and the number of the parameters,
593// e.g. "fhcal:vch_2_1 - vch_2_10 (hv_1), 10 channels" if the system and member are the same,
594// or "gem:vmon_0 (mod_0) - gem:vmon_11 (mod_2), 24 channels"
595static TString GetArrayTitle(vector<TangoData*>& vecTangoData)
596{
597 TangoData *pFirst = vecTangoData.front(), *pLast = vecTangoData.back();
598 if (vecTangoData.size() == 1)
599 return pFirst->GetFullName();
600
601 TString title;
602 if ((pFirst->GetSystemName() == pLast->GetSystemName()) && (pFirst->GetMemberName() == pLast->GetMemberName())) {
603 title = pFirst->GetSystemName() + ":" + pFirst->GetParameterName() + " - " + pLast->GetParameterName();
604 if (pFirst->GetMemberName() != "")
605 title += " (" + pFirst->GetMemberName() + ")";
606 } else
607 title = pFirst->GetFullName() + " - " + pLast->GetFullName();
608
609 return title + TString::Format(", %zu channels", vecTangoData.size());
610}
611
612// non-user function CreateTangoCanvas creates a canvas named by the displayed data and the kind of visualization,
613// e.g. "fhcal_hv_1_vch_2_1_multigraph3d"; a canvas with the same name (the same data and view) is replaced
614static TCanvas* CreateTangoCanvas(TString data_name, TString view_name)
615{
616 TString canvas_name = data_name + "_" + view_name;
617 // only letters, digits and underscores to use the canvas name in the ROOT interpreter
618 for (Ssiz_t i = 0; i < canvas_name.Length(); i++)
619 if (!isalnum(canvas_name[i]))
620 canvas_name[i] = '_';
621
622 return new TCanvas(canvas_name, canvas_name, 800, 600);
623}
624
625// Function displays hardware vector data obtained from Tango, e.g. FHCal voltage in time interval, graphically as 2D
626// Surface Graph Parameter: y_axis - label of Y axis
627void TangoData::PrintTangoDataSurface(const char* y_axis)
628{
629 if (arrTangoData == nullptr) {
630 cout << "ERROR: Tango parameter has not been obtained" << endl;
631 return;
632 }
633
634 TCanvas* c1 = CreateTangoCanvas(GetDataName(this), "surface");
635 TGraph2D* tango_graph = new TGraph2D();
636 tango_graph->SetTitle(arrTangoData->GetName());
637
638 int par_length = 0;
639 for (int i = 0; i < arrTangoData->GetEntriesFast(); i++) {
641
642 par_length = pParameter->double_parameter_value.size();
643 // cout<<"Parameter length = "<<par_length<<endl;
644 for (int j = 0; j < par_length; j++) {
645 int cur_time = pParameter->parameter_time.Convert();
646 double value = pParameter->double_parameter_value[j];
647 // cout<<x<<" "<<y<<" "<<z<<endl;
648 tango_graph->SetPoint(i * par_length + j, cur_time, j + 1, value);
649 }
650 }
651
652 tango_graph->Draw("SURF1");
653 gPad->Update();
654
655 tango_graph->GetXaxis()->SetTitle("time");
656 tango_graph->GetXaxis()->CenterTitle();
657 tango_graph->GetXaxis()->SetTitleOffset(1.9);
658 tango_graph->GetXaxis()->SetLabelSize(0.025);
659 tango_graph->GetXaxis()->SetLabelOffset(0.009);
660 tango_graph->GetXaxis()->SetNdivisions(-503);
661
662 tango_graph->GetYaxis()->SetTitle(y_axis);
663 tango_graph->GetYaxis()->CenterTitle();
664 tango_graph->GetYaxis()->SetTitleOffset(1.9);
665 tango_graph->GetYaxis()->SetLabelSize(0.025);
666 tango_graph->GetYaxis()->SetLabelOffset(0.001);
667 tango_graph->GetYaxis()->CenterLabels();
668 tango_graph->GetYaxis()->SetNdivisions(par_length + 1, 0, 0);
669
670 tango_graph->GetZaxis()->SetLabelSize(0.025);
671
672 // form X-axis with time ticks
673 tango_graph->GetXaxis()->SetTimeDisplay(1);
674 tango_graph->GetXaxis()->SetTimeFormat("%Y.%m.%d %H:%M");
675 tango_graph->GetXaxis()->SetTimeOffset(0, "local");
676
677 c1->Modified();
678
679 return;
680}
681
682// non-user function AddStepPoint adds a new point to the graph drawn as steps: Tango time points are transitions
683// to new values, so the previous value is held (horizontal line) up to the time point of the new value
684static void AddStepPoint(TGraph& graph, double x, double y)
685{
686 int n = graph.GetN();
687 if ((n > 0) && (graph.GetY()[n - 1] != y)) {
688 double previous_y = graph.GetY()[n - 1];
689 graph.SetPoint(n, x, previous_y);
690 n++;
691 }
692 graph.SetPoint(n, x, y);
693}
694
695// Function PrintTangoDataMulti3D display hardware vector data obtained from Tango, e.g. FHCal voltage in time interval,
696// graphically as a set of Line Graphs Parameter: tango_data - TObjArray with TangoTimeParameter objects obtained from
697// 'GetTangoParameter' function
698int TangoData::PrintTangoDataMultiGraph(const char* y_axis, bool is3D)
699{
700 if (arrTangoData == nullptr) {
701 cout << "ERROR: Tango parameter has not been obtained" << endl;
702 return -1;
703 }
704
705 if (arrTangoData->GetEntries() < 1) {
706 cout << "WARNING: There are no elements in the Tango array" << endl;
707 return -2;
708 }
709
710 TCanvas* c1 = CreateTangoCanvas(GetDataName(this), is3D ? "multigraph3d" : "multigraph");
711
712 // cout<<"Tango data array size = "<<arrTangoData->GetEntries()<<endl;
713 int par_length = ((TangoTimeParameter*)arrTangoData->At(0))->double_parameter_value.size();
714 // cout<<"par_length = "<<par_length<<endl;
715 TGraph* tango_graphs = new TGraph[par_length]();
716 gRandom->SetSeed();
717 for (int j = 0; j < par_length; j++) {
718 Int_t color = gRandom->Integer(50);
719 if ((color == 0) || (color == 10) || ((color > 16) && (color < 20)))
720 color += 20;
721 tango_graphs[j].SetLineColor(color);
722 }
723
724 // the 3D view does not support time display, so time is shown in hours from the start date
725 UInt_t start_time = TDatime(strStartDate).Convert();
726 for (int i = 0; i < arrTangoData->GetEntriesFast(); i++) {
728 par_length = pParameter->double_parameter_value.size();
729 for (int j = 0; j < par_length; j++) {
730 UInt_t cur_time = pParameter->parameter_time.Convert();
731 double x = is3D ? ((double)cur_time - start_time) / 3600 : cur_time;
732 double value = pParameter->double_parameter_value[j];
733 AddStepPoint(tango_graphs[j], x, value);
734 }
735 }
736
737 TMultiGraph* tango_multi = new TMultiGraph();
738 tango_multi->SetTitle(arrTangoData->GetName());
739 for (int j = 0; j < par_length; j++) {
740 tango_multi->Add(&tango_graphs[j]);
741 tango_graphs[j].SetTitle(TString::Format("%d", j));
742 tango_graphs[j].SetLineWidth(3);
743 }
744
745 TString draw_par = "AL";
746 if (is3D)
747 draw_par += "3D";
748 tango_multi->Draw(draw_par.Data());
749 gPad->Update();
750
751 if (!is3D) {
752 tango_multi->GetXaxis()->SetTitle("time");
753 tango_multi->GetXaxis()->CenterTitle();
754 tango_multi->GetXaxis()->SetTitleOffset(1.3);
755 tango_multi->GetXaxis()->SetLabelSize(0.025);
756 tango_multi->GetXaxis()->SetLabelOffset(0.009);
757 tango_multi->GetXaxis()->SetNdivisions(-503);
758 // form X-axis with time ticks
759 tango_multi->GetXaxis()->SetTimeDisplay(1);
760 tango_multi->GetXaxis()->SetTimeFormat("%Y.%m.%d %H:%M");
761 tango_multi->GetXaxis()->SetTimeOffset(0, "local");
762
763 tango_multi->GetYaxis()->SetTitle(y_axis);
764 tango_multi->GetYaxis()->CenterTitle();
765 tango_multi->GetYaxis()->SetTitleOffset(1.3);
766 tango_multi->GetYaxis()->SetLabelSize(0.025);
767 tango_multi->GetYaxis()->SetLabelOffset(0.001);
768 tango_multi->GetYaxis()->CenterLabels();
769 // gr->GetYaxis()->SetNdivisions(10, 0, 0);
770 }
771 // the titles are passed to the 3D frame: X axis title - to the time axis, Y axis title - to the value axis
772 else
773 {
774 tango_multi->GetXaxis()->SetTitle(TString::Format("time, hours from %s", strStartDate.Data()));
775 tango_multi->GetYaxis()->SetTitle(y_axis);
776 }
777
778 TLegend* pLegend = c1->BuildLegend(0.92, 0.77, 0.99, 0.98, "");
779 pLegend->SetMargin(0.80);
780
781 c1->Modified();
782 return 0;
783}
784
785// Function displays a set of "simple" parameters obtained from Tango, e.g. GEMs high voltages voltage, graphically as a
786// set of Line Graphs
787int TangoData::PrintTangoArrayMultiGraph(vector<TangoData*> vecTangoData, const char* y_axis, bool is3D)
788{
789 if (vecTangoData.size() < 1) {
790 cout << "WARNING: There are no parameters in the specified array" << endl;
791 return -1;
792 }
793
794 // check all the parameters before drawing
795 for (const auto& current_parameter : vecTangoData) {
796 if ((current_parameter->GetTangoData() == nullptr) || (current_parameter->GetTangoData()->IsEmpty())) {
797 cout << "ERROR: There are no elements in the parameter (" << current_parameter->GetFullName() << ")"
798 << endl;
799 return -2;
800 }
801
802 if ((((TangoTimeParameter*)current_parameter->GetTangoData()->At(0))->double_parameter_value.size()) != 1) {
803 cout << "ERROR: the parameter " << current_parameter->GetFullName() << " must have single value" << endl;
804 return -3;
805 }
806 }
807
808 // cout<<"Tango data array size = "<<vecTangoData.size()<<endl;
809 int par_length = vecTangoData.size();
810 // cout<<"par_length = "<<par_length<<endl;
811
812 TCanvas* c1 = CreateTangoCanvas(GetArrayDataName(vecTangoData), is3D ? "multigraph3d" : "multigraph");
813 TGraph* tango_graphs = new TGraph[par_length]();
814 gRandom->SetSeed();
815 int j;
816 for (j = 0; j < par_length; j++) {
817 Int_t color = gRandom->Integer(50);
818 if ((color == 0) || (color == 10) || ((color > 16) && (color < 20)))
819 color += 20;
820 tango_graphs[j].SetLineColor(color);
821 }
822
823 // the 3D view does not support time display, so time is shown in hours from the start date of the first parameter
824 TString start_date = vecTangoData[0]->GetStartDate();
825 UInt_t start_time = TDatime(start_date).Convert();
826 j = 0;
827 for (const auto& current_parameter : vecTangoData) {
828 TObjArray* arrTangoData = current_parameter->GetTangoData();
829 for (int i = 0; i < arrTangoData->GetEntriesFast(); i++) {
830 UInt_t cur_time = ((TangoTimeParameter*)arrTangoData->At(i))->parameter_time.Convert();
831 double x = is3D ? ((double)cur_time - start_time) / 3600 : cur_time;
832 double value = ((TangoTimeParameter*)arrTangoData->At(i))->double_parameter_value[0];
833 AddStepPoint(tango_graphs[j], x, value);
834 }
835 j++;
836 }
837
838 TMultiGraph* tango_multi = new TMultiGraph();
839 tango_multi->SetTitle(GetArrayTitle(vecTangoData));
840 for (j = 0; j < par_length; j++) {
841 tango_multi->Add(&tango_graphs[j]);
842 tango_graphs[j].SetTitle(TString::Format("%d", j));
843 tango_graphs[j].SetLineWidth(3);
844 }
845
846 TString draw_par = "AL";
847 if (is3D)
848 draw_par += "3D";
849 tango_multi->Draw(draw_par.Data());
850 gPad->Update();
851
852 if (!is3D) {
853 tango_multi->GetXaxis()->SetTitle("time");
854 tango_multi->GetXaxis()->CenterTitle();
855 tango_multi->GetXaxis()->SetTitleOffset(1.3);
856 tango_multi->GetXaxis()->SetLabelSize(0.025);
857 tango_multi->GetXaxis()->SetLabelOffset(0.009);
858 tango_multi->GetXaxis()->SetNdivisions(-503);
859 // form X-axis with time ticks
860 tango_multi->GetXaxis()->SetTimeDisplay(1);
861 tango_multi->GetXaxis()->SetTimeFormat("%Y.%m.%d %H:%M");
862 tango_multi->GetXaxis()->SetTimeOffset(0, "local");
863
864 tango_multi->GetYaxis()->SetTitle(y_axis);
865 tango_multi->GetYaxis()->CenterTitle();
866 tango_multi->GetYaxis()->SetTitleOffset(1.3);
867 tango_multi->GetYaxis()->SetLabelSize(0.025);
868 tango_multi->GetYaxis()->SetLabelOffset(0.001);
869 tango_multi->GetYaxis()->CenterLabels();
870 // gr->GetYaxis()->SetNdivisions(10, 0, 0);
871 }
872 // the titles are passed to the 3D frame: X axis title - to the time axis, Y axis title - to the value axis
873 else
874 {
875 tango_multi->GetXaxis()->SetTitle(TString::Format("time, hours from %s", start_date.Data()));
876 tango_multi->GetYaxis()->SetTitle(y_axis);
877 }
878
879 TLegend* pLegend = c1->BuildLegend(0.92, 0.77, 0.99, 0.98, "");
880 pLegend->SetMargin(0.80);
881
882 c1->Modified();
883 return 0;
884}
885
886/** Function displays a set of "simple" parameters obtained from Tango, e.g. FHCal or GEM high voltages, graphically
887 * as 2D Surface (X - time, Y - channel, i.e. index of the parameter in the array, Z - value of the parameter)
888 * The time interval of the first parameter is divided into equal time bins, and every bin is filled with
889 * the time-weighted average value of the channel in the bin (every value is valid up to the next time point)
890 * Parameters:
891 * z_axis - label of Z axis (parameter values), y_axis - label of Y axis (channels)
892 * draw_option - draw option of the 2D histogram: "SURF1" - surface (default), "LEGO2" - columns,
893 * "COLZ" - 2D color map, etc.
894 * time_bins - number of the time bins
895 * Returns: 0 - in case of the success, < 0 - if an error occured
896 **/
897int TangoData::PrintTangoArraySurface(vector<TangoData*> vecTangoData,
898 const char* z_axis,
899 const char* y_axis,
900 const char* draw_option,
901 int time_bins)
902{
903 if (vecTangoData.size() < 1) {
904 cout << "WARNING: There are no parameters in the specified array" << endl;
905 return -1;
906 }
907 if (time_bins < 1) {
908 cout << "ERROR: the number of time bins should be greater than 0" << endl;
909 return -2;
910 }
911
912 // check all the parameters before drawing
913 for (const auto& current_parameter : vecTangoData) {
914 if ((current_parameter->GetTangoData() == nullptr) || (current_parameter->GetTangoData()->IsEmpty())) {
915 cout << "ERROR: There are no elements in the parameter (" << current_parameter->GetFullName() << ")"
916 << endl;
917 return -3;
918 }
919
920 if ((((TangoTimeParameter*)current_parameter->GetTangoData()->At(0))->double_parameter_value.size()) != 1) {
921 cout << "ERROR: the parameter " << current_parameter->GetFullName() << " must have single value" << endl;
922 return -4;
923 }
924 }
925
926 // the time interval is taken from the first parameter
927 UInt_t start_time = TDatime(vecTangoData[0]->GetStartDate()).Convert();
928 UInt_t end_time = TDatime(vecTangoData[0]->GetEndDate()).Convert();
929 if (end_time <= start_time) {
930 cout << "ERROR: the end time should be greater than the start time of the parameters" << endl;
931 return -5;
932 }
933 int channel_count = vecTangoData.size();
934 double bin_width = (double)(end_time - start_time) / time_bins;
935
936 // the histogram is not added to the current directory to avoid replacing of the previous one
937 bool add_directory = TH1::AddDirectoryStatus();
938 TH1::AddDirectory(kFALSE);
939 TH2D* tango_hist = new TH2D("tango_surface", GetArrayTitle(vecTangoData), time_bins, start_time, end_time,
940 channel_count, -0.5, channel_count - 0.5);
941 TH1::AddDirectory(add_directory);
942
943 vector<double> bin_sum(time_bins), bin_sec(time_bins);
944 for (int j = 0; j < channel_count; j++) {
945 TangoData* current_parameter = vecTangoData[j];
946 TObjArray* arrParameterData = current_parameter->GetTangoData();
947 UInt_t data_start = TDatime(current_parameter->GetStartDate()).Convert();
948 UInt_t data_end = TDatime(current_parameter->GetEndDate()).Convert();
949 fill(bin_sum.begin(), bin_sum.end(), 0);
950 fill(bin_sec.begin(), bin_sec.end(), 0);
951 for (int i = 0; i < arrParameterData->GetEntriesFast(); i++) {
952 UInt_t value_start, value_end;
953 current_parameter->GetValuePeriod(i, data_start, data_end, value_start, value_end);
954 double value = ((TangoTimeParameter*)arrParameterData->At(i))->double_parameter_value[0];
955
956 // add the value weighted by its time overlapped with every time bin
957 int first_bin = max(0, (int)floor(((double)value_start - start_time) / bin_width));
958 int last_bin = min(time_bins - 1, (int)floor(((double)value_end - start_time) / bin_width));
959 for (int b = first_bin; b <= last_bin; b++) {
960 double bin_start = start_time + b * bin_width, bin_end = bin_start + bin_width;
961 double overlap = min((double)value_end, bin_end) - max((double)value_start, bin_start);
962 if (overlap <= 0)
963 continue;
964 bin_sum[b] += value * overlap;
965 bin_sec[b] += overlap;
966 }
967 }
968
969 for (int b = 0; b < time_bins; b++)
970 if (bin_sec[b] > 0)
971 tango_hist->SetBinContent(b + 1, j + 1, bin_sum[b] / bin_sec[b]);
972 }
973
974 // the view name is the draw option, e.g. "surf1" or "lego2"
975 TString view_name(draw_option);
976 view_name.ToLower();
977 TCanvas* c1 = CreateTangoCanvas(GetArrayDataName(vecTangoData), view_name);
978 tango_hist->SetStats(kFALSE);
979 if (tango_hist->GetMinimum() > 0)
980 tango_hist->SetMinimum(0);
981
982 // 3D view ("SURF", "LEGO") or 2D view (e.g. "COLZ" color map), where the right margin is used for the palette
983 bool is3D = view_name.Contains("surf") || view_name.Contains("lego");
984 if (!is3D)
985 c1->SetRightMargin(0.15);
986
987 tango_hist->GetXaxis()->SetTitle("time");
988 tango_hist->GetXaxis()->CenterTitle();
989 tango_hist->GetXaxis()->SetTitleOffset(is3D ? 1.9 : 1.2);
990 tango_hist->GetXaxis()->SetLabelSize(0.025);
991 tango_hist->GetXaxis()->SetNdivisions(-503);
992 // form X-axis with time ticks
993 tango_hist->GetXaxis()->SetTimeDisplay(1);
994 tango_hist->GetXaxis()->SetTimeFormat("%Y.%m.%d %H:%M");
995 tango_hist->GetXaxis()->SetTimeOffset(0, "local");
996
997 tango_hist->GetYaxis()->SetTitle(y_axis);
998 tango_hist->GetYaxis()->CenterTitle();
999 tango_hist->GetYaxis()->SetTitleOffset(is3D ? 1.9 : 1.0);
1000 tango_hist->GetYaxis()->SetLabelSize(0.025);
1001
1002 tango_hist->GetZaxis()->SetTitle(z_axis);
1003 tango_hist->GetZaxis()->CenterTitle();
1004 tango_hist->GetZaxis()->SetTitleOffset(is3D ? 1.5 : 1.2);
1005 tango_hist->GetZaxis()->SetLabelSize(0.025);
1006
1007 tango_hist->Draw(draw_option);
1008 c1->Modified();
1009 return 0;
1010}
1011
1012// Function calculates and returns average value for Tango data array (result vector with size > 1 is used in case of
1013// many channels)
1015{
1016 vector<double> result;
1017 if (arrTangoData == nullptr) {
1018 cout << "ERROR: Tango parameter has not been obtained" << endl;
1019 return result;
1020 }
1021
1022 if (iVerbose)
1023 cout << "strStartDateAvg = " << strStartDate.Data() << endl;
1024 if (iVerbose)
1025 cout << "strEndDateAvg = " << strEndDate.Data() << endl;
1026 int time_count = arrTangoData->GetEntriesFast();
1027 TDatime start_date(strStartDate), end_date(strEndDate);
1028
1029 // get arithmetic average value
1030 if ((IsOldMySQL) || (time_count < 2)) {
1031 for (int i = 0; i < time_count; i++) {
1033 // cycle for Tango parameter array (from 1 to array size)
1034 for (size_t j = 0; j < pParameter->double_parameter_value.size(); j++) {
1035 if (i == 0)
1036 result.push_back(pParameter->double_parameter_value[j]);
1037 else
1038 result[j] += pParameter->double_parameter_value[j];
1039 }
1040 }
1041
1042 for (size_t j = 0; j < result.size(); j++)
1043 result[j] /= time_count;
1044 }
1045 // get time-weighted average value over the whole time interval (for the new architecture of the Tango database)
1046 else
1047 result = GetTimeWeightedAverage(vector<TangoTimeInterval>{TangoTimeInterval(start_date, end_date)});
1048
1049 return result;
1050}
1051
1052// Function calculates and returns time-weighted average value for Tango data array only over the time of the runs,
1053// i.e. the gaps between runs are excluded (result vector with size > 1 is used in case of many channels)
1054// Every Tango value is considered valid from its time point to the next one
1055// It is available only if the object was created by the Run Range Constructor
1057{
1058 if (arrTangoData == nullptr) {
1059 cout << "ERROR: Tango parameter has not been obtained" << endl;
1060 return vector<double>();
1061 }
1062 if (vecRunIntervals.empty()) {
1063 cout << "ERROR: there are no run time intervals, the object should be created by the Run Range Constructor"
1064 << endl;
1065 return vector<double>();
1066 }
1067
1069}
1070
1071// non-user function GetTimeWeightedAverage calculates average value for Tango data array over the given time
1072// intervals, where every value is weighted by the length of its validity period inside the intervals
1073// Every Tango time point is a transition to a new value: the value is valid from its time point to the next one,
1074// the first value is also used from the start date, the last one - up to the end date
1075// Returns empty vector in case of errors
1076vector<double> TangoData::GetTimeWeightedAverage(const vector<TangoTimeInterval>& time_intervals)
1077{
1078 vector<double> result;
1079 int time_count = arrTangoData->GetEntriesFast();
1080 if (time_count == 0) {
1081 cout << "ERROR: there are no elements in the Tango array" << endl;
1082 return result;
1083 }
1084
1085 size_t channel_count = ((TangoTimeParameter*)arrTangoData->At(0))->double_parameter_value.size();
1086 result.assign(channel_count, 0);
1087 UInt_t data_start = TDatime(strStartDate).Convert(), data_end = TDatime(strEndDate).Convert();
1088 double total_sec = 0;
1089 for (int i = 0; i < time_count; i++) {
1090 TangoTimeParameter* pParameter = (TangoTimeParameter*)arrTangoData->At(i);
1091 if (pParameter->double_parameter_value.size() != channel_count) {
1092 cout << "ERROR: channel count of the Tango parameter is not constant during the time interval" << endl;
1093 result.clear();
1094 return result;
1095 }
1096
1097 UInt_t value_start, value_end;
1098 GetValuePeriod(i, data_start, data_end, value_start, value_end);
1099
1100 // add the value weighted by its time overlapped with every interval
1101 for (const auto& time_interval : time_intervals) {
1102 UInt_t overlap_start = max(value_start, time_interval.start_time.Convert());
1103 UInt_t overlap_end = min(value_end, time_interval.end_time.Convert());
1104 if (overlap_end <= overlap_start)
1105 continue;
1106
1107 UInt_t sec = overlap_end - overlap_start;
1108 for (size_t j = 0; j < channel_count; j++)
1109 result[j] += pParameter->double_parameter_value[j] * sec;
1110 total_sec += sec;
1111 }
1112 }
1113
1114 if (total_sec == 0) {
1115 cout << "ERROR: the total time of the intervals for the average value is equal 0" << endl;
1116 result.clear();
1117 return result;
1118 }
1119 if (iVerbose)
1120 cout << "Total time of " << time_intervals.size() << " interval(s) used for the average value = " << total_sec
1121 << " s" << endl;
1122
1123 for (size_t j = 0; j < channel_count; j++)
1124 result[j] /= total_sec;
1125
1126 return result;
1127}
1128
1129// non-user function GetValuePeriod gets the time period where the value of the i-th Tango time point is valid:
1130// from its time point to the next one, the first value is also used from the start date (data_start),
1131// the last one - up to the end date (data_end)
1132void TangoData::GetValuePeriod(int i, UInt_t data_start, UInt_t data_end, UInt_t& value_start, UInt_t& value_end)
1133{
1134 value_start = ((TangoTimeParameter*)arrTangoData->At(i))->parameter_time.Convert();
1135 value_end = data_end;
1136 if ((i == 0) && (data_start < value_start))
1137 value_start = data_start;
1138 if (i < arrTangoData->GetEntriesFast() - 1)
1139 value_end = ((TangoTimeParameter*)arrTangoData->At(i + 1))->parameter_time.Convert();
1140}
1141
1142/** Function SearchTangoIntervals gets time intervals for defined condition on the parameter values
1143 * NOTE: it works only if channel count is constant during given time period
1144 * Parameters:
1145 * condition - condition of time interval sampling, default: conditionEqual (the possible list is presented above in
1146 * 'enumConditions', except conditionLike, conditionNull and conditionNotNull)
1147 * value - numeric value for the condition with which the comparison is performed, default: 1 (true);
1148 * boolean values of the parameter are compared as 0 (false) and 1 (true)
1149 * mapChannel - vector of integer values (map) to change the order of result TObjArray-s in the common result array,
1150 * if, for example, channels go in a different sequence; nullptr - if not used
1151 * Returns common TObjArray with TObjArray objects containing TangoTimeInterval for every channel
1152 * (i.e. conditionally TObjArray<TObjArray<TangoTimeInterval*>>). If there are no intervals found, it returns
1153 * an empty TObjArray with zero elements. In case of errors it returns nullptr
1154 **/
1155TObjArray* TangoData::SearchTangoIntervals(enumConditions condition, double value, vector<int>* mapChannel)
1156{
1157 if (arrTangoData == nullptr) {
1158 cout << "ERROR: Tango parameter has not been obtained" << endl;
1159 return nullptr;
1160 }
1161 if ((condition == conditionLike) || (condition == conditionNull) || (condition == conditionNotNull)) {
1162 cout << "ERROR: comparison operator in the searching of intervals is not supported" << endl;
1163 return nullptr;
1164 }
1165
1166 TObjArray* pTimeIntervals = new TObjArray();
1167 pTimeIntervals->SetOwner(kTRUE);
1168
1169 // if there is no points in the Tango period then return empty common TObjArray (without any elements)
1170 int time_count = arrTangoData->GetEntriesFast();
1171 if (time_count == 0)
1172 return pTimeIntervals;
1173
1174 // TObjArray with the found time intervals for every channel
1175 size_t channel_count = ((TangoTimeParameter*)arrTangoData->At(0))->double_parameter_value.size();
1176 for (size_t j = 0; j < channel_count; j++) {
1177 TObjArray* pChannel = new TObjArray();
1178 pChannel->SetOwner(kTRUE);
1179 pTimeIntervals->Add(pChannel);
1180 }
1181
1182 // add the found time interval of the channel to the result array considering the channel map
1183 auto AddInterval = [&](size_t j, TDatime start_interval, TDatime end_interval) {
1184 int real_channel = j;
1185 if (mapChannel != nullptr) {
1186 if (mapChannel->size() > j) {
1187 real_channel = mapChannel->at(j);
1188 if (pTimeIntervals->GetEntriesFast() <= real_channel) {
1189 cout << "CRITICAL WARNING: Tango array size is less than the corrected channel: " << real_channel
1190 << endl;
1191 return;
1192 }
1193 } else
1194 cout << "CRITICAL WARNING: map channel size is less than the current channel: " << j << endl;
1195 }
1196 ((TObjArray*)pTimeIntervals->At(real_channel))->Add(new TangoTimeInterval(start_interval, end_interval));
1197 };
1198 // start time of the interval beginning at the given time point (the middle between the points for old MySQL)
1199 auto GetStartTime = [&](int start_i) {
1200 TDatime start_interval = ((TangoTimeParameter*)arrTangoData->At(start_i))->parameter_time;
1201 if ((start_i > 0) && (IsOldMySQL)) {
1202 TDatime previous_time = ((TangoTimeParameter*)arrTangoData->At(start_i - 1))->parameter_time;
1203 start_interval.Set((start_interval.Convert() + previous_time.Convert()) / 2);
1204 }
1205 return start_interval;
1206 };
1207
1208 // start indices of the current intervals satisfying the condition for every channel (-1 - no interval)
1209 vector<int> vecStart(channel_count, -1);
1210 for (int i = 0; i < time_count; i++) {
1211 TangoTimeParameter* pParameter = (TangoTimeParameter*)arrTangoData->At(i);
1212 if (pParameter->double_parameter_value.size() != channel_count) {
1213 cout << "ERROR: channel count of the Tango parameter is not constant during the time interval" << endl;
1214 delete pTimeIntervals;
1215 return nullptr;
1216 }
1217
1218 // cycle for array parameter data (if the parameter is an array) and checking the given condition
1219 for (size_t j = 0; j < channel_count; j++) {
1220 double cur_value = pParameter->double_parameter_value[j];
1221 bool isCondition = false;
1222 switch (condition) {
1223 case conditionLess:
1224 isCondition = cur_value < value;
1225 break;
1227 isCondition = cur_value <= value;
1228 break;
1229 case conditionEqual:
1230 isCondition = cur_value == value;
1231 break;
1232 case conditionNotEqual:
1233 isCondition = cur_value != value;
1234 break;
1235 case conditionGreater:
1236 isCondition = cur_value > value;
1237 break;
1239 isCondition = cur_value >= value;
1240 break;
1241 default:
1242 break;
1243 }
1244
1245 // save the start index of a new interval satisfying the condition
1246 if (isCondition) {
1247 if (vecStart[j] < 0)
1248 vecStart[j] = i;
1249 }
1250 // the interval has ended: write it (the end is just before the current time point)
1251 else if (vecStart[j] >= 0)
1252 {
1253 UInt_t uiEndTime = pParameter->parameter_time.Convert();
1254 TDatime end_interval(uiEndTime - 1);
1255 if (IsOldMySQL)
1256 end_interval.Set(
1257 (uiEndTime + ((TangoTimeParameter*)arrTangoData->At(i - 1))->parameter_time.Convert()) / 2);
1258 AddInterval(j, GetStartTime(vecStart[j]), end_interval);
1259 vecStart[j] = -1;
1260 }
1261 } // for (size_t j = 0; j < channel_count; j++)
1262 } // for (int i = 0; i < time_count; i++)
1263
1264 // write the intervals lasting up to the end of the time period
1265 TDatime end_time = ((TangoTimeParameter*)arrTangoData->At(time_count - 1))->parameter_time;
1266 for (size_t j = 0; j < channel_count; j++)
1267 if (vecStart[j] >= 0)
1268 AddInterval(j, GetStartTime(vecStart[j]), end_time);
1269
1270 return pTimeIntervals;
1271}
1272
1273/** Function displays (in console) time intervals obtained from Tango for a defined condition
1274 * Parameters:
1275 * tango_intervals - TObjArray with TObjArray objects containing TangoTimeInterval objects obtained from
1276 *'SearchTangoIntervals' function channel_name - name of the dimension to display on the screen, default: Channel
1277 * isShowOnlyExists - if true, print only intervals which satisfy the condition (skip empty intervals)
1278 **/
1279void TangoData::PrintTangoIntervalConsole(TObjArray* tango_intervals, TString channel_name, bool isShowOnlyExists)
1280{
1281 for (int i = 0; i < tango_intervals->GetEntriesFast(); i++) {
1282 TObjArray* pChannel = (TObjArray*)tango_intervals->At(i);
1283 if (pChannel->GetEntriesFast() == 0) {
1284 if (!isShowOnlyExists)
1285 cout << channel_name.Data() << " " << i << ":" << endl
1286 << " No intervals correspond to the specified conditions" << endl;
1287 continue;
1288 } else
1289 cout << channel_name.Data() << " " << i << ":" << endl;
1290 for (int j = 0; j < pChannel->GetEntriesFast(); j++) {
1291 TangoTimeInterval* pInterval = (TangoTimeInterval*)pChannel->At(j);
1292 cout << " " << pInterval->start_time.AsSQLString();
1293 cout << " - ";
1294 cout << pInterval->end_time.AsSQLString();
1295 }
1296 cout << endl;
1297 }
1298
1299 return;
1300}
1301
1302// delete Tango parameter
1304{
1305 IsOldMySQL = false;
1307 iPeriodNumber = -1, iStartRun = -1, iEndRun = -1;
1308 vecRunIntervals.clear();
1309 if (arrTangoData != nullptr) {
1310 arrTangoData->Delete();
1311 delete arrTangoData;
1312 arrTangoData = nullptr;
1313 }
1314}
int i
Definition P4_F32vec4.h:22
friend F32vec4 min(const F32vec4 &a, const F32vec4 &b)
Definition P4_F32vec4.h:30
friend F32vec4 max(const F32vec4 &a, const F32vec4 &b)
Definition P4_F32vec4.h:31
int Int_t
int Ssiz_t
unsigned int UInt_t
constexpr Ssiz_t kNPOS
constexpr Bool_t kTRUE
R__EXTERN TRandom * gRandom
#define gPad
static int cached_end_run
const char *const TANGO_DB_USERNAME_b2020
Definition TangoData.cxx:27
static TString GetRangeSuffix(TangoData *pTangoData)
static TString cached_end_date
const char *const TANGO_DB_NAME_b2020
Definition TangoData.cxx:30
const char *const TANGO_DB_PASSWORD_b2020
Definition TangoData.cxx:28
static void AddStepPoint(TGraph &graph, double x, double y)
const char *const TANGO_DB_HOST_b2020
Definition TangoData.cxx:29
static int cached_period
static TString GetArrayDataName(vector< TangoData * > &vecTangoData)
static TString GetArrayTitle(vector< TangoData * > &vecTangoData)
static TString cached_start_date
static TString GetSourceName(TangoData *pTangoData)
static TString GetDataName(TangoData *pTangoData)
static vector< TangoTimeInterval > cached_run_intervals
static int cached_start_run
static TCanvas * CreateTangoCanvas(TString data_name, TString view_name)
virtual void SetTitleOffset(Float_t offset=1)
virtual void SetLabelSize(Float_t size=0.04)
virtual void SetLabelOffset(Float_t offset=0.005)
virtual void SetNdivisions(Int_t n1, Int_t n2, Int_t n3, Bool_t optim=kTRUE)
virtual void SetLineWidth(Width_t lwidth)
virtual void SetLineColor(Color_t lcolor)
virtual void SetRightMargin(Float_t rightmargin)
virtual void SetTimeOffset(Double_t toffset, Option_t *option="local")
void CenterLabels(Bool_t center=kTRUE)
virtual void SetTimeDisplay(Int_t value)
void CenterTitle(Bool_t center=kTRUE)
virtual void SetTimeFormat(const char *format="")
virtual void SetOwner(Bool_t enable=kTRUE)
Int_t GetDate() const
const char * AsSQLString() const
void Set()
UInt_t Convert(Bool_t toGMT=kFALSE) const
Int_t GetTime() const
TAxis * GetZaxis() const
void SetTitle(const char *title="") override
TAxis * GetYaxis() const
virtual void SetPoint(Int_t point, Double_t x, Double_t y, Double_t z)
void Draw(Option_t *option="P0") override
TAxis * GetXaxis() const
virtual void SetPoint(Int_t i, Double_t x, Double_t y)
Double_t * GetY() const
Int_t GetN() const
void SetTitle(const char *title="") override
TAxis * GetZaxis()
static void AddDirectory(Bool_t add=kTRUE)
TAxis * GetXaxis()
TAxis * GetYaxis()
void Draw(Option_t *option="") override
virtual void SetMinimum(Double_t minimum=-1111)
virtual Double_t GetMinimum(Double_t minval=-FLT_MAX) const
static Bool_t AddDirectoryStatus()
virtual void SetStats(Bool_t stats=kTRUE)
void SetBinContent(Int_t bin, Double_t content) override
void SetMargin(Float_t margin)
virtual void Add(TGraph *graph, Option_t *chopt="")
void Draw(Option_t *chopt="") override
TAxis * GetYaxis()
TAxis * GetXaxis()
virtual void SetTitle(const char *title="")
Int_t GetEntriesFast() const
TObject * At(Int_t idx) const override
void Add(TObject *obj) override
TLegend * BuildLegend(Double_t x1=0.3, Double_t y1=0.21, Double_t x2=0.3, Double_t y2=0.21, const char *title="", Option_t *option="") override
void Modified(Bool_t flag=true) override
virtual void SetSeed(ULong_t seed=0)
virtual UInt_t Integer(UInt_t imax)
const char * GetDB() const
virtual TSQLResult * GetTables(const char *dbname, const char *wild=nullptr)=0
virtual TSQLStatement * Statement(const char *, Int_t=100)
virtual const char * GetString(Int_t)
virtual Bool_t NextResultRow()=0
virtual Int_t GetNumAffectedRows()
virtual Int_t GetInt(Int_t)
virtual Bool_t Process()=0
virtual Double_t GetDouble(Int_t)
virtual Bool_t StoreResult()=0
Ssiz_t Length() const
Int_t Atoi() const
const char * Data() const
static TString Format(const char *fmt,...)
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
TSQLServer * GetSQLServer()
static TangoConnection * Open()
TString strMemberName
Definition TangoData.h:228
TString GetEndDate()
Definition TangoData.h:144
TString GetSystemName()
Definition TangoData.h:145
void GetValuePeriod(int i, UInt_t data_start, UInt_t data_end, UInt_t &value_start, UInt_t &value_end)
int iStartRun
Definition TangoData.h:233
TString GetFullName()
int GetEndRun()
Definition TangoData.h:151
std::vector< double > GetAverageTangoData()
TString strParameterName
Definition TangoData.h:228
TObjArray * arrTangoData
Definition TangoData.h:230
static int PrintTangoArraySurface(std::vector< TangoData * > vecTangoData, const char *z_axis="parameter", const char *y_axis="channel", const char *draw_option="SURF1", int time_bins=100)
Function displays a set of "simple" parameters obtained from Tango, e.g.
TObjArray * SearchTangoIntervals(enumConditions condition=conditionEqual, double value=1, std::vector< int > *mapChannel=nullptr)
Function SearchTangoIntervals gets time intervals for defined condition on the parameter values (e....
std::vector< double > GetRunAverageTangoData()
std::vector< double > GetTimeWeightedAverage(const std::vector< TangoTimeInterval > &time_intervals)
int GetStartRun()
Definition TangoData.h:150
static void PrintTangoArrayConsole(std::vector< TangoData * > vecTangoData)
TString strEndDate
Definition TangoData.h:229
int SetRunRangeDates(int period_number, int start_run, int end_run)
std::vector< TangoTimeInterval > vecRunIntervals
Definition TangoData.h:234
void PrintTangoDataConsole()
void InitTangoData()
TString strStartDate
Definition TangoData.h:228
TString GetStartDate()
Definition TangoData.h:143
@ conditionLike
Definition TangoData.h:95
@ conditionGreaterOrEqual
Definition TangoData.h:94
@ conditionNull
Definition TangoData.h:96
@ conditionGreater
Definition TangoData.h:93
@ conditionLess
Definition TangoData.h:89
@ conditionLessOrEqual
Definition TangoData.h:90
@ conditionNotEqual
Definition TangoData.h:92
@ conditionNotNull
Definition TangoData.h:97
@ conditionEqual
Definition TangoData.h:91
int iEndRun
Definition TangoData.h:233
int GetTangoParameter()
void DeleteTangoParameter()
virtual ~TangoData()
bool IsOldMySQL
Definition TangoData.h:227
TString strUserName
Definition TangoData.h:228
void PrintTangoDataSurface(const char *y_axis="tango parameter")
TObjArray * GetTangoData()
Definition TangoData.h:141
TString strSystemName
Definition TangoData.h:228
int PrintTangoDataMultiGraph(const char *y_axis="parameter", bool is3D=false)
TString GetParameterName()
Definition TangoData.h:146
int iVerbose
Definition TangoData.h:231
TangoData(const char *start_date, const char *end_date, const char *system_name, const char *parameter_name, const char *member_name="", int verbose=0)
Time Range Constructor: fill Tango data array according to the given parameters Tango database connec...
Definition TangoData.cxx:80
TString GetMemberName()
Definition TangoData.h:147
static int PrintTangoArrayMultiGraph(std::vector< TangoData * > vecTangoData, const char *y_axis="parameter", bool is3D=false)
int GetPeriodNumber()
Definition TangoData.h:149
void PrintTangoIntervalConsole(TObjArray *tango_intervals, TString channel_name="Channel", bool isShowOnlyExists=false)
Function displays (in console) time intervals obtained from Tango for a defined condition Parameters:...
int iPeriodNumber
Definition TangoData.h:233
TangoTimeInterval()
Default constructor.
Definition TangoData.cxx:52
TDatime start_time
Definition TangoData.h:61
virtual ~TangoTimeInterval()
Destructor.
Definition TangoData.cxx:60
std::vector< bool > bool_parameter_value
Definition TangoData.h:40
Tango_Parameter_Type parameter_type
Definition TangoData.h:37
TangoTimeParameter()
Default constructor.
Definition TangoData.cxx:32
std::vector< double > double_parameter_value
Definition TangoData.h:41
TDatime parameter_time
Definition TangoData.h:35
virtual ~TangoTimeParameter()
Destructor.
Definition TangoData.cxx:50
UniRun.h Class for the table: run_.
Definition UniRun.h:21
static UniRun * GetRun(int period_number, int run_number)
get run from the database
Definition UniRun.cxx:161
TDatime * GetEndDatetime()
get end datetime of the current run
Definition UniRun.h:101
TDatime GetStartDatetime()
get start datetime of the current run
Definition UniRun.h:99
static int GetRunNumbers(UniqueRunNumber *&run_numbers, int start_period, int start_run=0, int end_period=-1, int end_run=-1)
get numbers of runs stored in the Database for a selected range
Definition UniRun.cxx:804
RVec< PromoteType< T > > floor(const RVec< T > &v)
Tango_Parameter_Type
Definition TangoData.h:18
@ Tango_Bool
Definition TangoData.h:19
@ Tango_Bool_Array
Definition TangoData.h:24
@ Tango_Double
Definition TangoData.h:20
@ Tango_Double_Array
Definition TangoData.h:26
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:20362
json_pointer result
Definition json.hpp:11939
*brief create JSON pointer *sa reference_tokens const std::string const std::string & b
Definition json.hpp:11787
Definition json.hpp:4446