REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
Loading...
Searching...
No Matches
TRestTools.cxx
1/******************** REST disclaimer ***********************************
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
44#include "TRestTools.h"
45
46#include <TClass.h>
47#include <TFile.h>
48#include <TKey.h>
49#include <TSystem.h>
50#include <TUrl.h>
51
52#include <regex>
53
54#ifdef USE_Curl
55#include <curl/curl.h>
56#endif
57
58#ifdef WIN32
59#include <io.h>
60#else
61#include "unistd.h"
62#endif // !WIN32
63
64#ifdef __APPLE__
65#include <array>
66#endif
67
68#include <chrono>
69#include <filesystem>
70#include <iostream>
71#include <limits>
72#include <memory>
73#include <thread>
74
75#include "TRestStringHelper.h"
76#include "TRestStringOutput.h"
77
78using namespace std;
79
86std::vector<string> TRestTools::GetOptions(string optionsStr) { return Split(optionsStr, ":"); }
87
95void TRestTools::LoadRESTLibrary(bool silent) {
96 const set<string> libraryExtension{".so", ".dylib", ".dll"};
97 const set<string> excludedLibraries{
98 "RestG4"}; // Ignoring package libraries if they exist. TODO: do not hardcode this
99
100 vector<string> ldPaths;
101#ifdef WIN32
102 ldPaths.push_back(REST_PATH + "/bin/");
103#elif __APPLE__
104 ldPaths.push_back(REST_PATH + "/bin/");
105#else
106 ldPaths.push_back(REST_PATH + "/lib/");
107#endif // WIN32
108 ldPaths.push_back(REST_USER_PATH + "/userlib/");
109
110 vector<string> fileList;
111 for (const std::filesystem::path path : ldPaths) {
112 if (!exists(path)) {
113 // RESTWarning << "Directory " << string(path) << " for library loading not exist" << RESTendl;
114 continue;
115 }
116 for (const auto& it : std::filesystem::directory_iterator(path)) {
117 if (!it.is_regular_file()) {
118 continue;
119 }
120 if (libraryExtension.count(it.path().extension().string()) == 0) {
121 // needs correct extension e.g. ".so"
122 continue;
123 }
124 const TString pathRootString = it.path().string();
125 TString libName = TRestTools::SeparatePathAndName((std::string)pathRootString).second;
126 if (!libName.Contains("Rest", TString::kExact)) {
127 // e.g. "libRestFramework.so"
128 continue;
129 }
130 // Check if library is excluded from loading e.g. is from a package
131 bool excluded = false;
132 for (const TString excludedLibrary : excludedLibraries) {
133 if (libName.Contains(excludedLibrary, TString::kExact)) {
134 excluded = true;
135 // RESTWarning << "Library '" << pathRootString << "' excluded from loading" << RESTendl;
136 break;
137 }
138 }
139 if (excluded) {
140 continue;
141 }
142 fileList.emplace_back(it.path().string());
143 }
144 }
145
146 // load the found REST libraries
147 if (!silent) cout << "= Loading libraries ..." << endl;
148 for (const auto& library : fileList) {
149 if (!silent) cout << " - " << library << endl;
150 gSystem->Load(library.c_str());
151 }
152 if (!silent) cout << endl;
153}
154
162template <typename T>
163int TRestTools::PrintTable(std::vector<std::vector<T>> data, Int_t start, Int_t end) {
164 Int_t size = data.size();
165 if (end > 0 && size > end) size = end;
166 for (int n = start; n < size; n++) {
167 for (unsigned int m = 0; m < data[n].size(); m++) cout << data[n][m] << "\t";
168 cout << endl;
169 }
170 return 0;
171}
172
173template int TRestTools::PrintTable<Int_t>(std::vector<std::vector<Int_t>> data, Int_t start, Int_t end);
174template int TRestTools::PrintTable<Float_t>(std::vector<std::vector<Float_t>> data, Int_t start, Int_t end);
175template int TRestTools::PrintTable<Double_t>(std::vector<std::vector<Double_t>> data, Int_t start,
176 Int_t end);
177template int TRestTools::PrintTable<std::string>(std::vector<std::vector<std::string>> data, Int_t start,
178 Int_t end);
179
184template <typename T>
185int TRestTools::ExportASCIITable(std::string fname, std::vector<std::vector<T>>& data) {
186 ofstream file(fname);
187 if (!file.is_open()) {
188 RESTError << "Unable to open file for writing : " << fname << RESTendl;
189 return 1;
190 }
191
192 for (unsigned int n = 0; n < data.size(); n++)
193 for (unsigned int m = 0; m < data[n].size(); m++) {
194 file << data[n][m];
195 if (m + 1 < data[n].size()) file << "\t";
196 if (m + 1 == data[n].size()) file << "\n";
197 }
198 file.close();
199
200 return 0;
201}
202
203template int TRestTools::ExportASCIITable<Int_t>(std::string fname, std::vector<std::vector<Int_t>>& data);
204template int TRestTools::ExportASCIITable<Float_t>(std::string fname,
205 std::vector<std::vector<Float_t>>& data);
206template int TRestTools::ExportASCIITable<Double_t>(std::string fname,
207 std::vector<std::vector<Double_t>>& data);
208
213template <typename T>
214int TRestTools::ExportBinaryTable(std::string fname, std::vector<std::vector<T>>& data) {
215 ofstream file(fname, ios::out | ios::binary);
216 if (!file.is_open()) {
217 RESTError << "Unable to open file for writing : " << fname << RESTendl;
218 return 1;
219 }
220
221 for (unsigned int n = 0; n < data.size(); n++)
222 for (unsigned int m = 0; m < data[n].size(); m++) {
223 file.write((char*)&data[n][m], sizeof(T));
224 }
225 file.close();
226
227 return 0;
228}
229
230template int TRestTools::ExportBinaryTable<Int_t>(std::string fname, std::vector<std::vector<Int_t>>& data);
231template int TRestTools::ExportBinaryTable<Float_t>(std::string fname,
232 std::vector<std::vector<Float_t>>& data);
233template int TRestTools::ExportBinaryTable<Double_t>(std::string fname,
234 std::vector<std::vector<Double_t>>& data);
235
252template <typename T>
253int TRestTools::ReadBinaryTable(string fName, std::vector<std::vector<T>>& data, Int_t columns) {
254 if (!TRestTools::isValidFile((string)fName)) {
255 RESTError << "TRestTools::ReadBinaryTable. Error." << RESTendl;
256 RESTError << "Cannot open file : " << fName << RESTendl;
257 return 0;
258 }
259
260 if (columns == -1) {
261 columns = GetBinaryFileColumns(fName);
262 if (columns == -1) {
263 RESTError << "TRestTools::ReadBinaryTable. Format extension error." << RESTendl;
264 RESTError << "Please, specify the number of columns at the method 3rd argument" << RESTendl;
265 return 0;
266 }
267 }
268
269 std::ifstream fin(fName, std::ios::binary);
270 fin.seekg(0, std::ios::end);
271 const size_t num_elements = fin.tellg() / sizeof(T);
272 fin.seekg(0, std::ios::beg);
273
274 if (num_elements % columns != 0) {
275 cout << "TRestTools::ReadBinaryTable. Error." << endl;
276 cout << "Number of elements : " << num_elements
277 << " is not compatible with the number of columns : " << columns << endl;
278 fin.close();
279 return 0;
280 }
281
282 std::vector<T> dataArray(columns);
283 fin.read(reinterpret_cast<char*>(&dataArray[0]), columns * sizeof(T));
284 while (fin.good()) {
285 data.push_back(dataArray);
286 fin.read(reinterpret_cast<char*>(&dataArray[0]), columns * sizeof(T));
287 }
288 return 1;
289}
290
291template int TRestTools::ReadBinaryTable<Int_t>(string fName, std::vector<std::vector<Int_t>>& data,
292 Int_t columns);
293template int TRestTools::ReadBinaryTable<Float_t>(string fName, std::vector<std::vector<Float_t>>& data,
294 Int_t columns);
295template int TRestTools::ReadBinaryTable<Double_t>(string fName, std::vector<std::vector<Double_t>>& data,
296 Int_t columns);
297
303Bool_t TRestTools::IsBinaryFile(string fname) {
304 if (GetBinaryFileColumns(fname) > 0) return true;
305 return false;
306}
307
316 string extension = GetFileNameExtension(fname);
317 if (extension.find("N") != 0) {
318 return -1;
319 }
320
321 size_t pos = extension.find("i");
322 if (pos != string::npos) {
323 return StringToInteger(extension.substr(1, pos - 1));
324 }
325
326 pos = extension.find("f");
327 if (pos != string::npos) {
328 return StringToInteger(extension.substr(1, pos - 1));
329 }
330
331 pos = extension.find("d");
332 if (pos != string::npos) {
333 return StringToInteger(extension.substr(1, pos - 1));
334 }
335
336 RESTError << "Format " << ToUpper(extension) << " not recognized" << RESTendl;
337 return -1;
338}
339
344template <typename T>
345void TRestTools::TransposeTable(std::vector<std::vector<T>>& data) {
346 if (data.size() == 0) return;
347
348 std::vector<std::vector<T>> trans_vec(data[0].size(), std::vector<T>());
349
350 for (unsigned int i = 0; i < data.size(); i++)
351 for (unsigned int j = 0; j < data[i].size(); j++) trans_vec[j].push_back(data[i][j]);
352
353 data = trans_vec;
354}
355
356template void TRestTools::TransposeTable<Double_t>(std::vector<std::vector<Double_t>>& data);
357
358template void TRestTools::TransposeTable<Float_t>(std::vector<std::vector<Float_t>>& data);
359
360template void TRestTools::TransposeTable<Int_t>(std::vector<std::vector<Int_t>>& data);
361
369template <typename T>
370T TRestTools::GetMaxValueFromTable(const std::vector<std::vector<T>>& data, Int_t column) {
371 if (data.size() == 0) return 0;
372 if (column > -1 && data[0].size() <= (unsigned int)column) return 0;
373
374 T maxValue = data[0][0];
375 if (column == -1) {
376 for (unsigned int n = 0; n < data.size(); n++)
377 for (unsigned int c = 0; c < data[n].size(); c++)
378 if (maxValue < data[n][c]) maxValue = data[n][c];
379 } else {
380 maxValue = data[0][column];
381 for (unsigned int n = 0; n < data.size(); n++)
382 if (maxValue < data[n][column]) maxValue = data[n][column];
383 }
384
385 return maxValue;
386}
387
388template Int_t TRestTools::GetMaxValueFromTable<Int_t>(const std::vector<std::vector<Int_t>>& data,
389 Int_t column);
390
391template Float_t TRestTools::GetMaxValueFromTable<Float_t>(const std::vector<std::vector<Float_t>>& data,
392 Int_t column);
393
394template Double_t TRestTools::GetMaxValueFromTable<Double_t>(const std::vector<std::vector<Double_t>>& data,
395 Int_t column);
396
404template <typename T>
405T TRestTools::GetMinValueFromTable(const std::vector<std::vector<T>>& data, Int_t column) {
406 if (data.empty()) return 0;
407 if (column != -1 && data[0].size() <= (unsigned int)column) return 0;
408
409 T minValue = data[0][0];
410 if (column == -1) {
411 for (unsigned int n = 0; n < data.size(); n++)
412 for (unsigned int c = 0; c < data[n].size(); c++)
413 if (minValue > data[n][c]) minValue = data[n][c];
414 } else {
415 minValue = data[0][column];
416 for (unsigned int n = 0; n < data.size(); n++)
417 if (minValue > data[n][column]) minValue = data[n][column];
418 }
419
420 return minValue;
421}
422
423template Int_t TRestTools::GetMinValueFromTable<Int_t>(const std::vector<std::vector<Int_t>>& data,
424 Int_t column);
425
426template Float_t TRestTools::GetMinValueFromTable<Float_t>(const std::vector<std::vector<Float_t>>& data,
427 Int_t column);
428
429template Double_t TRestTools::GetMinValueFromTable<Double_t>(const std::vector<std::vector<Double_t>>& data,
430 Int_t column);
431
441template <typename T>
442T TRestTools::GetLowestIncreaseFromTable(std::vector<std::vector<T>> data, Int_t column) {
443 if (data.size() == 0 || data[0].size() <= (unsigned int)column) return 0;
444 T lowestIncrease = abs(data[0][column] - data[1][column]);
445 for (unsigned int n = 1; n < data.size(); n++) {
446 T value = abs(data[n - 1][column] - data[n][column]);
447 if (lowestIncrease == 0) lowestIncrease = value;
448 if (value > 0 && value < lowestIncrease) lowestIncrease = value;
449 }
450 return lowestIncrease;
451}
452
453template Int_t TRestTools::GetLowestIncreaseFromTable<Int_t>(std::vector<std::vector<Int_t>> data,
454 Int_t column);
455
456template Float_t TRestTools::GetLowestIncreaseFromTable<Float_t>(std::vector<std::vector<Float_t>> data,
457 Int_t column);
458
459template Double_t TRestTools::GetLowestIncreaseFromTable<Double_t>(std::vector<std::vector<Double_t>> data,
460 Int_t column);
461
471template <typename T>
472T TRestTools::GetIntegralFromTable(const std::vector<std::vector<T>>& data) {
473 if (data.size() == 0) return 0;
474 T sum = 0;
475 for (unsigned int n = 0; n < data.size(); n++) {
476 for (unsigned int m = 0; m < data[n].size(); m++) sum += data[n][m];
477 }
478 return sum;
479}
480
481template Int_t TRestTools::GetIntegralFromTable<Int_t>(const std::vector<std::vector<Int_t>>& data);
482
483template Float_t TRestTools::GetIntegralFromTable<Float_t>(const std::vector<std::vector<Float_t>>& data);
484
485template Double_t TRestTools::GetIntegralFromTable<Double_t>(const std::vector<std::vector<Double_t>>& data);
486
493template <typename T>
494std::vector<T> TRestTools::GetColumnFromTable(const std::vector<std::vector<T>>& data, unsigned int column) {
495 std::vector<T> columnData;
496 if (data.size() == 0 || data[0].size() <= column) return columnData;
497
498 for (unsigned int n = 0; n < data.size(); n++) columnData.push_back(data[n][column]);
499
500 return columnData;
501}
502
503template std::vector<Int_t> TRestTools::GetColumnFromTable<Int_t>(const std::vector<std::vector<Int_t>>& data,
504 unsigned int column);
505
506template std::vector<Float_t> TRestTools::GetColumnFromTable<Float_t>(
507 const std::vector<std::vector<Float_t>>& data, unsigned int column);
508
509template std::vector<Double_t> TRestTools::GetColumnFromTable<Double_t>(
510 const std::vector<std::vector<Double_t>>& data, unsigned int column);
511
512template std::vector<std::string> TRestTools::GetColumnFromTable<std::string>(
513 const std::vector<std::vector<std::string>>& data, unsigned int column);
514
528int TRestTools::ReadASCIITable(string fName, std::vector<std::vector<std::string>>& data, Int_t skipLines,
529 std::string separator) {
530 if (!TRestTools::isValidFile((string)fName)) {
531 cout << "TRestTools::ReadASCIITable. Error" << endl;
532 cout << "Cannot open file : " << fName << endl;
533 return 0;
534 }
535
536 data.clear();
537
538 std::ifstream fin(fName);
539
540 // First we create a table with string values
541 std::vector<std::vector<string>> values;
542
543 for (string line; std::getline(fin, line);) {
544 if (skipLines > 0) {
545 skipLines--;
546 continue;
547 }
548
549 if (line.find("#") == string::npos) {
550 std::istringstream in(line);
551
552 std::string token;
553 std::vector<std::string> tokens;
554 while (std::getline(in, token, (char)separator[0])) {
555 tokens.push_back(token);
556 }
557 data.push_back(tokens);
558 }
559 }
560
561 return 1;
562}
563
577int TRestTools::ReadASCIITable(string fName, std::vector<std::vector<Double_t>>& data, Int_t skipLines,
578 std::string separator) {
579 if (!TRestTools::isValidFile((string)fName)) {
580 cout << "TRestTools::ReadASCIITable. Error" << endl;
581 cout << "Cannot open file : " << fName << endl;
582 return 0;
583 }
584
585 data.clear();
586
587 std::ifstream fin(fName);
588
589 // First we create a table with string values
590 std::vector<std::vector<string>> values;
591
592 for (string line; std::getline(fin, line);) {
593 if (skipLines > 0) {
594 skipLines--;
595 continue;
596 }
597
598 if (line.find("#") == string::npos) {
599 std::istringstream in(line);
600
601 std::string token;
602 std::vector<std::string> tokens;
603 while (std::getline(in, token, (char)separator[0])) {
604 tokens.push_back(token);
605 }
606 values.push_back(tokens);
607 }
608 }
609
610 // Filling the double values table (TODO error handling in case ToDouble conversion fails)
611 for (unsigned int n = 0; n < values.size(); n++) {
612 std::vector<Double_t> dblTmp;
613 dblTmp.clear();
614
615 for (unsigned int m = 0; m < values[n].size(); m++) dblTmp.push_back(StringToDouble(values[n][m]));
616
617 data.push_back(dblTmp);
618 }
619
620 return 1;
621}
622
636int TRestTools::ReadASCIITable(string fName, std::vector<std::vector<Float_t>>& data, Int_t skipLines,
637 std::string separator) {
638 if (!TRestTools::isValidFile((string)fName)) {
639 cout << "TRestTools::ReadASCIITable. Error" << endl;
640 cout << "Cannot open file : " << fName << endl;
641 return 0;
642 }
643
644 data.clear();
645
646 std::ifstream fin(fName);
647
648 // First we create a table with string values
649 std::vector<std::vector<string>> values;
650
651 for (string line; std::getline(fin, line);) {
652 if (skipLines > 0) {
653 skipLines--;
654 continue;
655 }
656
657 if (line.find("#") == string::npos) {
658 std::istringstream in(line);
659
660 std::string token;
661 std::vector<std::string> tokens;
662 while (std::getline(in, token, (char)separator[0])) {
663 tokens.push_back(token);
664 }
665 values.push_back(tokens);
666 }
667 }
668
669 // Filling the float values table (TODO error handling in case ToFloat conversion fails)
670 for (unsigned int n = 0; n < values.size(); n++) {
671 std::vector<Float_t> dblTmp;
672 dblTmp.clear();
673
674 for (unsigned int m = 0; m < values[n].size(); m++) dblTmp.push_back(StringToFloat(values[n][m]));
675
676 data.push_back(dblTmp);
677 }
678
679 return 1;
680}
681
695int TRestTools::ReadCSVFile(std::string fName, std::vector<std::vector<Double_t>>& data, Int_t skipLines) {
696 return ReadASCIITable(fName, data, skipLines, ",");
697}
698
712int TRestTools::ReadCSVFile(std::string fName, std::vector<std::vector<Float_t>>& data, Int_t skipLines) {
713 return ReadASCIITable(fName, data, skipLines, ",");
714}
715
719Int_t TRestTools::isValidFile(const string& path) { return std::filesystem::is_regular_file(path); }
720
728bool TRestTools::fileExists(const string& filename) { return std::filesystem::exists(filename); }
729
733bool TRestTools::isRootFile(const string& filename) { return GetFileNameExtension(filename) == "root"; }
734
738bool TRestTools::isRunFile(const std::string& filename) {
739 if (!isRootFile(filename)) return false;
740
741 TFile* f = TFile::Open((TString)filename);
742
743 TIter nextkey(f->GetListOfKeys());
744 TKey* key;
745 while ((key = (TKey*)nextkey())) {
746 if ((std::string)key->GetClassName() == "TRestRun") return true;
747 }
748 return false;
749}
750
754bool TRestTools::isDataSet(const std::string& filename) {
755 if (!isRootFile(filename)) return false;
756
757 if (!TRestTools::fileExists(filename)) return false;
758
759 TFile* f = TFile::Open((TString)filename);
760
761 TIter nextkey(f->GetListOfKeys());
762 TKey* key;
763 while ((key = (TKey*)nextkey())) {
764 if ((std::string)key->GetClassName() == "TRestDataSet") return true;
765 }
766 return false;
767}
768
772bool TRestTools::isURL(const string& s) {
773 std::regex pattern("^https?://(.+)");
774 return std::regex_match(s, pattern);
775}
776
780bool TRestTools::isPathWritable(const string& path) {
781 int result = 0;
782#ifdef WIN32
783 result = _access(path.c_str(), 2);
784#else
785 result = access(path.c_str(), 2);
786#endif
787
788 if (result == 0)
789 return true;
790 else
791 return false;
792}
793
797bool TRestTools::isAbsolutePath(const string& path) {
798 if (path[0] == '/' || path[0] == '~' || path.find(':') != string::npos) {
799 return true;
800 }
801 return false;
802}
803
815std::pair<string, string> TRestTools::SeparatePathAndName(const string& fullname) {
816 filesystem::path path(fullname);
817 return {path.parent_path().string(), path.filename().string()};
818}
819
825string TRestTools::GetFileNameExtension(const string& fullname) {
826 string extension = filesystem::path(fullname).extension().string();
827 if (extension.size() > 1) return extension.substr(1);
828 return extension;
829}
830
836string TRestTools::GetFileNameRoot(const string& fullname) {
837 return filesystem::path(fullname).stem().string();
838}
839
845// Output: {"hitsAna_xMean", "hitsAna_yMean"}.
849std::vector<std::string> TRestTools::GetObservablesInString(const std::string& observablesStr,
850 bool removeDuplicates) {
851 std::vector<std::string> obsList;
852 std::string text = observablesStr;
853 while (text.find("_") != std::string::npos) {
854 size_t pos_ = text.find("_");
855 size_t beginning = text.find_last_of(" -+*/)(^%<>", pos_) + 1;
856 size_t end = text.find_first_of(" -+*/)(^%<>", pos_);
857 std::string obs = text.substr(beginning, end - beginning);
858 text = Replace(text, obs, "1", 0, removeDuplicates ? 0 : 1);
859 obsList.push_back(obs);
860 }
861 return obsList;
862}
863
871 // we replace multiple appearances of "/" (slash) by a single "/"
872 string to_replace = "//";
873 size_t start_pos = str.find(to_replace);
874 while (start_pos != string::npos) {
875 str.replace(start_pos, to_replace.length(), "/");
876 start_pos = str.find(to_replace);
877 }
878 return str;
879}
880
889string TRestTools::GetPureFileName(const string& path) { return filesystem::path(path).filename().string(); }
890
894string TRestTools::ToAbsoluteName(const string& filename) {
895 filesystem::path path;
896 for (const auto& directory : filesystem::path(filename)) {
897 if (path.empty() && directory == "~") {
898 // path starts with ~
899 const auto envVariableHome = getenv("HOME");
900 if (envVariableHome == nullptr) {
901 cout << "TRestTools::ToAbsoluteName - ERROR - "
902 "cannot resolve ~ because 'HOME' env variable does not exist"
903 << endl;
904 exit(1);
905 }
906 const auto userHomePath = filesystem::path(envVariableHome);
907 if (userHomePath.empty()) {
908 cout << "TRestTools::ToAbsoluteName - ERROR - "
909 "cannot resolve ~ because 'HOME' env variable is not set to a valid value"
910 << endl;
911 exit(1);
912 }
913 path /= userHomePath;
914 } else {
915 path /= directory;
916 }
917 }
918 return filesystem::weakly_canonical(path).string();
919}
920
930vector<string> TRestTools::GetSubdirectories(const string& _path, int recursion) {
931 vector<string> result;
932
933 std::filesystem::path path(_path);
934 if (exists(path)) {
935 std::filesystem::directory_iterator iter(path);
936 for (auto& it : iter) {
937 if (it.is_directory()) {
938 result.push_back(it.path().string());
939
940 if (recursion != 0) {
941 vector<string> subD = GetSubdirectories(it.path().string(), recursion - 1);
942 result.insert(result.begin(), subD.begin(), subD.end());
943 }
944 }
945 }
946 }
947
948 return result;
949}
950
955string TRestTools::SearchFileInPath(vector<string> paths, string filename) {
956 if (fileExists(filename)) {
957 return filename;
958 } else {
959 for (unsigned int i = 0; i < paths.size(); i++) {
960 string path = paths[i];
961 if (path[path.size() - 1] != '/') {
962 path = path + "/";
963 }
964
965 if (fileExists(path + filename)) {
966 return path + filename;
967 }
968
969 // search also in subdirectory, but only 5 times of recursion
970 vector<string> pathsExpanded = GetSubdirectories(paths[i], 5);
971 for (unsigned int j = 0; j < pathsExpanded.size(); j++)
972 if (fileExists(pathsExpanded[j] + "/" + filename)) return pathsExpanded[j] + "/" + filename;
973 }
974 }
975 return "";
976}
977
982bool TRestTools::CheckFileIsAccessible(const std::string& filename) {
983 ifstream ifs;
984 ifs.open(filename.c_str());
985
986 if (!ifs) {
987 return false;
988 } else {
989 ifs.close();
990 }
991 return true;
992}
993
1002vector<string> TRestTools::GetFilesMatchingPattern(string pattern, bool unlimited) {
1003 std::vector<string> outputFileNames;
1004 if (pattern != "") {
1005 vector<string> items = Split(pattern, "\n");
1006 for (auto item : items) {
1007 if (item.find_first_of("*?") != string::npos) {
1008#ifdef WIN32
1009 item = Replace(item, "/", "\\");
1010 string item_trim =
1011 item.substr(0, item.find_first_of("*?")); // trim string to before wildcard character
1012 auto path_name = SeparatePathAndName(item_trim);
1013 string _path = path_name.first;
1014 if (!std::filesystem::exists(_path)) {
1015 RESTError << "TRestTools::GetFilesMatchingPattern(): path " << _path << " does not exist!"
1016 << RESTendl;
1017 return outputFileNames;
1018 }
1019
1020 std::filesystem::path path(_path);
1021 std::filesystem::recursive_directory_iterator iter(path);
1022 for (auto& it : iter) {
1023 if (it.is_regular_file()) {
1024 string filename = it.path().string();
1025 if (MatchString(filename, item)) {
1026 outputFileNames.push_back(it.path().string());
1027 }
1028 }
1029 }
1030#else
1031 auto path_name = SeparatePathAndName(item);
1032 if (unlimited) {
1033 std::string currentDir = filesystem::current_path();
1034 ChangeDirectory(path_name.first);
1035 string a = Execute("find -type f -name \'" + path_name.second + "\'");
1036 ChangeDirectory(currentDir);
1037 auto b = Split(a, "\n");
1038
1039 for (unsigned int i = 0; i < b.size(); i++) {
1040 outputFileNames.push_back(path_name.first + "/" + b[i]);
1041 }
1042
1043 } else {
1044 string a = Execute("find " + item);
1045 auto b = Split(a, "\n");
1046
1047 for (unsigned int i = 0; i < b.size(); i++) {
1048 outputFileNames.push_back(b[i]);
1049 }
1050 }
1051#endif
1052
1053 } else {
1054 if (fileExists(item)) outputFileNames.push_back(item);
1055 }
1056 }
1057 }
1058 return outputFileNames;
1059}
1060
1065#ifndef REST_Version
1066#define REST_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
1067#endif
1068 vector<string> ver = Split(in, ".");
1069 if (ver.size() == 3) {
1070 vector<int> verint;
1071 for (auto v : ver) {
1072 int n = StringToInteger(v.substr(0, v.find_first_not_of("0123456789")));
1073 if (n != -1) {
1074 verint.push_back(n);
1075 } else {
1076 return -1;
1077 }
1078 }
1079 return REST_VERSION(verint[0], verint[1], verint[2]);
1080 }
1081 return -1;
1082}
1083
1087string TRestTools::Execute(string cmd) {
1088 std::array<char, 128> buffer;
1089 string result;
1090#ifdef WIN32
1091 std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(("powershell.exe " + cmd).c_str(), "r"), _pclose);
1092#else
1093 std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
1094#endif // WIN32
1095
1096 if (!pipe) {
1097 throw std::runtime_error("popen() failed!");
1098 }
1099 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
1100 result += buffer.data();
1101 }
1102
1103 if (result.size() > 0 && result[result.size() - 1] == '\n')
1104 result = result.substr(0, result.size() - 1); // remove last "\n"
1105
1106 return result;
1107}
1108
1113std::istream& TRestTools::GetLine(std::istream& is, std::string& t) {
1114 t.clear();
1115
1116 // The characters in the stream are read one-by-one using a std::streambuf.
1117 // That is faster than reading them one-by-one using the std::istream.
1118 // Code that uses streambuf this way must be guarded by a sentry object.
1119 // The sentry object performs various tasks,
1120 // such as thread synchronization and updating the stream state.
1121
1122 std::istream::sentry se(is, true);
1123 std::streambuf* sb = is.rdbuf();
1124
1125 for (;;) {
1126 int c = sb->sbumpc();
1127 switch (c) {
1128 case '\n':
1129 return is;
1130 case '\r':
1131 if (sb->sgetc() == '\n') sb->sbumpc();
1132 return is;
1133 case std::streambuf::traits_type::eof():
1134 // Also handle the case when the last line has no line ending
1135 if (t.empty()) is.setstate(std::ios::eofbit);
1136 return is;
1137 default:
1138 t += (char)c;
1139 }
1140 }
1141}
1142
1150std::string TRestTools::DownloadRemoteFile(const string& url, bool pidPrefix) {
1151 string pureName = TRestTools::GetPureFileName(url);
1152 if (pureName.empty()) {
1153 RESTWarning << "error! (TRestTools::DownloadRemoteFile): url is not a file!" << RESTendl;
1154 RESTWarning << "please specify a concrete file name in this url" << RESTendl;
1155 RESTWarning << "url: " << url << RESTendl;
1156 return "";
1157 }
1158
1159 if (url.find("local:") == 0) {
1160 return Replace(url, "local:", "");
1161 } else {
1162 string fullpath =
1163 REST_USER_PATH + "/download/" + (pidPrefix ? "PID_" + ToString(getpid()) + "_" : "") + pureName;
1164 int out;
1165 int attempts = 10;
1166 do {
1167 out = TRestTools::DownloadRemoteFile(url, fullpath);
1168 if (out == 1024) {
1169 RESTWarning << "Retrying download in 5 seconds" << RESTendl;
1170 std::this_thread::sleep_for(std::chrono::seconds(5));
1171 } else if (attempts < 10) {
1172 RESTSuccess << "Download succeeded after " << 10 - attempts << " attempts" << RESTendl;
1173 }
1174 attempts--;
1175 } while (out == 1024 && attempts > 0);
1176
1177 if (out == 0 || TRestTools::fileExists(fullpath)) {
1178 return fullpath;
1179 } else {
1180 return "";
1181 }
1182 }
1183}
1184
1191int TRestTools::DownloadRemoteFile(string remoteFile, string localFile) {
1192 TUrl url(remoteFile.c_str());
1193
1194 RESTInfo << "Downloading remote file : " << remoteFile << RESTendl;
1195 RESTInfo << "To local file : " << localFile << RESTendl;
1196
1197 string localFiletmp = localFile + ".restdownload";
1198 if ((string)url.GetProtocol() == "https" || (string)url.GetProtocol() == "http") {
1199 string path = TRestTools::SeparatePathAndName(localFiletmp).first;
1200 if (!TRestTools::fileExists(path)) {
1201 if (!filesystem::create_directories(path)) {
1202 std::cerr << "mkdir failed to create directory: " << path << std::endl;
1203 return -1;
1204 }
1205 }
1206
1207 string cmd = "wget --no-check-certificate " + EscapeSpecialLetters(remoteFile) + " -O " +
1208 EscapeSpecialLetters(localFiletmp) + " -q";
1209 RESTDebug << cmd << RESTendl;
1210 int a = system(cmd.c_str());
1211
1212 if (a == 0) {
1213 rename(localFiletmp.c_str(), localFile.c_str());
1214 return 0;
1215 } else {
1216 RESTError << "download failed! (" << remoteFile << ")" << RESTendl;
1217 if (a == 1024) {
1218 RESTError << "Network connection problem?" << RESTendl;
1219 return 1024;
1220 }
1221 if (a == 2048) {
1222 RESTError << "File does NOT exist in remotely?" << RESTendl;
1223 return 2048;
1224 }
1225 }
1226 } else if ((string)url.GetProtocol() == "ssh") {
1227 string cmd = "scp -P " + ToString(url.GetPort() == 0 ? 22 : url.GetPort()) + " " + url.GetUser() +
1228 "@" + url.GetHost() + ":" + EscapeSpecialLetters(url.GetFile()) + " " + localFiletmp;
1229 cout << cmd << endl;
1230 int a = system(cmd.c_str());
1231 if (a == 0) {
1232 rename(localFiletmp.c_str(), localFile.c_str());
1233 return 0;
1234 }
1235 } else {
1236 if (!TRestTools::fileExists(remoteFile)) {
1237 RESTWarning << "Trying to download: " << remoteFile << RESTendl;
1238 RESTWarning << "Unknown protocol!" << RESTendl;
1239 }
1240 }
1241
1242 return -1;
1243}
1244
1249std::string TRestTools::POSTRequest(const std::string& url, const std::map<std::string, std::string>& keys) {
1250 std::string file_content = "";
1251#ifdef USE_Curl
1252 CURL* curl;
1253 CURLcode res;
1254
1255 string filename = REST_USER_PATH + "/download/curl.out";
1256
1257 /* In windows, this will init the winsock stuff */
1258 curl_global_init(CURL_GLOBAL_ALL);
1259
1260 FILE* f = fopen(filename.c_str(), "wt");
1261
1262 std::string request = "";
1263 int n = 0;
1264 for (auto const& x : keys) {
1265 if (n > 0) request += "&";
1266 request += x.first + "=" + x.second;
1267 n++;
1268 }
1269 /* get a curl handle */
1270 curl = curl_easy_init();
1271 if (curl) {
1272 /* First set the URL that is about to receive our POST. This URL can
1273 just as well be a https:// URL if that is what should receive the
1274 data. */
1275 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
1276 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)f);
1277 /* Now specify the POST data */
1278 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.c_str());
1279
1280 /* Perform the request, res will get the return code */
1281 res = curl_easy_perform(curl);
1282 /* Check for errors */
1283 if (res != CURLE_OK)
1284 RESTError << "curl_easy_perform() failed: " << curl_easy_strerror(res) << RESTendl;
1285
1286 /* always cleanup */
1287 curl_easy_cleanup(curl);
1288 }
1289 fclose(f);
1290 curl_global_cleanup();
1291
1292 std::getline(std::ifstream(filename), file_content, '\0');
1293#else
1294 RESTError << "TRestTools::POSTRequest. REST framework was compiled without CURL support" << RESTendl;
1295 RESTError << "Please recompile REST after installing curl development libraries." << RESTendl;
1296 RESTError << "Depending on your system this might be: curl-dev, curl-devel or libcurl-openssl-dev. "
1297 << RESTendl;
1298 RESTError << "No file will be downloaded" << RESTendl;
1299#endif
1300
1301 return file_content;
1302}
1303
1311int TRestTools::UploadToServer(string localFile, string remoteFile, string methodUrl) {
1312 if (!TRestTools::fileExists(localFile)) {
1313 cout << "error! local file not exist!" << endl;
1314 return -1;
1315 }
1316 // construct path
1317 // [proto://][user[:passwd]@]host[:port]/file.ext[#anchor][?options]
1318 TUrl url(remoteFile.c_str());
1319 TUrl method(methodUrl.c_str());
1320 if (method.GetProtocol() != (string) "") url.SetProtocol(method.GetProtocol());
1321 if (method.GetPort() != 0) url.SetPort(method.GetPort());
1322 if (method.GetUser() != (string) "") url.SetUser(method.GetUser());
1323 if (method.GetPasswd() != (string) "") url.SetPasswd(method.GetPasswd());
1324
1325 if ((string)url.GetProtocol() == "https" || (string)url.GetProtocol() == "http") {
1326 // maybe we use curl to upload to http in future
1327 } else if ((string)url.GetProtocol() == "ssh") {
1328 string cmd = "scp -P " + ToString(url.GetPort() == 0 ? 22 : url.GetPort()) + " " +
1329 EscapeSpecialLetters(localFile) + " " + url.GetUser() + "@" + url.GetHost() + ":" +
1330 EscapeSpecialLetters(url.GetFile());
1331 cout << cmd << endl;
1332 int a = system(cmd.c_str());
1333
1334 if (a != 0) {
1335 RESTError << __PRETTY_FUNCTION__ << RESTendl;
1336 RESTError << "problem copying gases definitions to remote server" << RESTendl;
1337 RESTError << "Please report this problem at "
1338 "http://gifna.unizar.es/rest-forum/"
1339 << RESTendl;
1340 return -1;
1341 }
1342
1343 return 0;
1344 }
1345 return 0;
1346}
1347
1348void TRestTools::ChangeDirectory(const string& toDirectory) { filesystem::current_path(toDirectory); }
1349
1358std::vector<int> TRestTools::CanvasDivisions(int n) {
1359 std::vector<int> r;
1360 for (int i = 2; i * i <= n; i += 1 + (i > 2)) {
1361 while ((n % i) == 0) {
1362 r.push_back(i);
1363 n /= i;
1364 }
1365 }
1366 if (n != 1) r.push_back(n);
1367
1368 while (r.size() > 2) {
1369 // We multiply the 2 lowest elements and
1370 // replace the elements in the vector by the result
1371 auto min1 = std::min_element(r.begin(), r.end());
1372 int low1 = *min1;
1373
1374 // Remove the first element equal to min1 (efficient way)
1375 auto it = std::find(r.begin(), r.end(), low1);
1376 if (it != r.end()) {
1377 std::iter_swap(it, r.end() - 1);
1378 r.erase(r.end() - 1);
1379 }
1380
1381 auto min2 = std::min_element(r.begin(), r.end());
1382 int low2 = *min2;
1383
1384 // Remove the first element equal to min2 (efficient way)
1385 it = std::find(r.begin(), r.end(), low2);
1386 if (it != r.end()) {
1387 std::iter_swap(it, r.end() - 1);
1388 r.erase(r.end() - 1);
1389 }
1390
1391 int resultado = low1 * low2;
1392 r.push_back(resultado);
1393 }
1394
1395 std::sort(r.begin(), r.end());
1396
1397 if (r.size() == 1) r.push_back(1);
1398
1399 return r;
1400}
1401
1402string ValueWithQuantity::ToString() const {
1403 string unit;
1404 auto value = fValue;
1405 if (fQuantity == ENERGY) {
1406 unit = "eV";
1407 value *= 1E3; // since we store energy in keV, not in eV
1408 } else if (fQuantity == TIME) {
1409 unit = "s"; // time is stored in microseconds
1410 value *= 1E-6;
1411 } else if (fQuantity == LENGTH) {
1412 unit = "m";
1413 value *= 1E-3; // since we store length in mm, not in m
1414 } else {
1415 return "";
1416 }
1417
1418 const auto abs = TMath::Abs(value);
1419 if (abs == 0) {
1420 return TString::Format("%d", 0).Data();
1421 } else if (abs < 1E-6) {
1422 return TString::Format("%.2f %s%s", value * 1E9, "n", unit.c_str()).Data();
1423 } else if (abs < 1E-3) {
1424 return TString::Format("%.2f %s%s", value * 1E6, "u", unit.c_str()).Data();
1425 } else if (abs < 1E0) {
1426 return TString::Format("%.2f %s%s", value * 1E3, "m", unit.c_str()).Data();
1427 } else if (abs < 1E3) {
1428 return TString::Format("%.2f %s%s", value * 1E0, "", unit.c_str()).Data();
1429 } else if (abs < 1E6) {
1430 return TString::Format("%.2f %s%s", value * 1E-3, "k", unit.c_str()).Data();
1431 } else if (abs < 1E9) {
1432 return TString::Format("%.2f %s%s", value * 1E-6, "M", unit.c_str()).Data();
1433 } else if (abs < 1E12) {
1434 return TString::Format("%.2f %s%s", value * 1E-9, "G", unit.c_str()).Data();
1435 } else {
1436 return TString::Format("%.2f %s%s", value * 1E-12, "T", unit.c_str()).Data();
1437 }
1438}
1439
1440string ToTimeStringLong(double seconds) {
1441 const auto abs = TMath::Abs(seconds);
1442 if (abs < 60) {
1443 return TString::Format("%.2f %s", seconds, "seconds").Data();
1444 } else if (abs < 60 * 60) {
1445 return TString::Format("%.2f %s", seconds / 60.0, "minutes").Data();
1446 } else if (abs < 60 * 60 * 24) {
1447 return TString::Format("%.2f %s", seconds / (60.0 * 60.0), "hours").Data();
1448 } else {
1449 return TString::Format("%.2f %s", seconds / (60.0 * 60.0 * 24.0), "days").Data();
1450 }
1451}
static std::string Execute(std::string cmd)
Executes a shell command and returns its output in a string.
static std::pair< std::string, std::string > SeparatePathAndName(const std::string &fullname)
Separate path and filename in a full path+filename string, returns a pair of string.
static Int_t isValidFile(const std::string &path)
Returns true if the file with path filename exists.
static std::string GetFileNameExtension(const std::string &fullname)
Gets the file extension as the substring found after the latest ".".
static std::string POSTRequest(const std::string &url, const std::map< std::string, std::string > &keys)
It performs a POST web protocol request using a set of keys and values given by argument,...
static std::vector< std::string > GetSubdirectories(const std::string &path, int recursion=-1)
It lists all the subdirectories inside path and adds them to the result vector.
static int ReadASCIITable(std::string fName, std::vector< std::vector< Double_t > > &data, Int_t skipLines=0, std::string separator="\t")
Reads an ASCII file containing a table with values.
static bool CheckFileIsAccessible(const std::string &)
Checks if the config file can be opened (and thus exists). It returns true in case of success,...
static std::string GetPureFileName(const std::string &fullPathFileName)
Removes all directories in the full path filename description given in the argument.
static int ReadBinaryTable(std::string fName, std::vector< std::vector< T > > &data, Int_t columns=-1)
Reads a binary file containing a fixed-columns table with values.
static int GetBinaryFileColumns(std::string fname)
It extracts the number of columns from the filename extension given by argument. The file should cont...
static std::vector< std::string > GetOptions(std::string optionsStr)
Returns all the options in an option string.
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,...
static std::string GetFileNameRoot(const std::string &fullname)
Gets the filename root as the substring found before the latest ".".
static T GetMaxValueFromTable(const std::vector< std::vector< T > > &data, Int_t column=-1)
It returns the maximum value for a particular column from the table given by argument....
static T GetLowestIncreaseFromTable(std::vector< std::vector< T > > data, Int_t column)
It returns the lowest increase, different from zero, between the elements of a particular column from...
static void LoadRESTLibrary(bool silent=false)
Calls gSystem to load REST library.
static int ReadCSVFile(std::string fName, std::vector< std::vector< Double_t > > &data, Int_t skipLines=0)
Reads a CSV file containing a table with comma separated values.
static bool isRunFile(const std::string &filename)
It checks if the file has been processed using a REST event processing chain.
static int ExportASCIITable(std::string fname, std::vector< std::vector< T > > &data)
Writes the contents of the vector table given as argument to fname. Allowed types are Int_t,...
static bool fileExists(const std::string &filename)
Returns true if the file (or directory) with path filename exists.
static std::vector< int > CanvasDivisions(int n)
It returns a vector with 2 components {a,b}, the components satisfy that a x b = n,...
static std::string DownloadRemoteFile(const std::string &remoteFile, bool pidPrefix=false)
download the remote file automatically, returns the downloaded file name.
static T GetMinValueFromTable(const std::vector< std::vector< T > > &data, Int_t column=-1)
It returns the minimum value for a particular column from the table given by argument....
static std::vector< std::string > GetFilesMatchingPattern(std::string pattern, bool unlimited=false)
Returns a list of files whose name match the pattern string. Key word is "*". e.g....
static int ConvertVersionCode(std::string in)
Convert version to a unique string.
static bool isPathWritable(const std::string &path)
Returns true if the path given by argument is writable.
static T GetIntegralFromTable(const std::vector< std::vector< T > > &data)
It returns the lowest increase, different from zero, between the elements of a particular column from...
static bool isAbsolutePath(const std::string &path)
Check if the path is absolute path or not.
static int ExportBinaryTable(std::string fname, std::vector< std::vector< T > > &data)
Writes the contents of the vector table given as argument to fname as a binary file....
static Bool_t IsBinaryFile(std::string fname)
It identifies if the filename extension follows the formatting ".Nxyzf", where the number of columns ...
static std::string RemoveMultipleSlash(std::string)
Returns the input string but without multiple slashes ("/")
static bool isDataSet(const std::string &filename)
It checks if the file contains a dataset object.
static bool isURL(const std::string &filename)
Returns true if filename is an http address.
static std::istream & GetLine(std::istream &is, std::string &t)
It reads the next line from the incoming istream and puts it in the string argument t....
static std::vector< std::string > GetObservablesInString(const std::string &observablesStr, bool removeDuplicates=true)
Returns a vector with the observables names found in the input string. The observables names must con...
static int UploadToServer(std::string localFile, std::string remoteFile, std::string methodUrl="")
static bool isRootFile(const std::string &filename)
Returns true if the filename has *.root* extension.
static std::string SearchFileInPath(std::vector< std::string > path, std::string filename)
Search file in the given vector of path strings, return a full name if found, return "" if not.
static void TransposeTable(std::vector< std::vector< T > > &data)
It transposes the std::vector<std::vector> table given in the argument. It will transform rows in col...
static std::vector< T > GetColumnFromTable(const std::vector< std::vector< T > > &data, unsigned int column)
It returns a vector with the values extracted from the particular column inside the data table given ...
static std::string ToAbsoluteName(const std::string &filename)
It takes a path and returns its absolute path.
Float_t StringToFloat(std::string in)
Gets a float from a string.
std::vector< std::string > Split(std::string in, std::string separator, bool allowBlankString=false, bool removeWhiteSpaces=false, int startPos=-1)
Split the input string according to the given separator. Returning a vector of fragments.
Bool_t MatchString(std::string str, std::string matcher)
This method matches a string with certain matcher. Returns true if matched. Supports wildcard charact...
Double_t StringToDouble(std::string in)
Gets a double from a string.
std::string ToUpper(std::string in)
Convert string to its upper case. Alternative of TString::ToUpper.
Int_t StringToInteger(std::string in)
Gets an integer from a string.
std::string Replace(std::string in, std::string thisString, std::string byThisString, size_t fromPosition=0, Int_t N=0)
Replace any occurences of thisSring by byThisString inside string in.