REST-for-Physics  v2.3
Rare Event Searches ToolKit for Physics
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 TFile* f = TFile::Open((TString)filename);
758
759 TIter nextkey(f->GetListOfKeys());
760 TKey* key;
761 while ((key = (TKey*)nextkey())) {
762 if ((std::string)key->GetClassName() == "TRestDataSet") return true;
763 }
764 return false;
765}
766
770bool TRestTools::isURL(const string& s) {
771 std::regex pattern("^https?://(.+)");
772 return std::regex_match(s, pattern);
773}
774
778bool TRestTools::isPathWritable(const string& path) {
779 int result = 0;
780#ifdef WIN32
781 result = _access(path.c_str(), 2);
782#else
783 result = access(path.c_str(), 2);
784#endif
785
786 if (result == 0)
787 return true;
788 else
789 return false;
790}
791
795bool TRestTools::isAbsolutePath(const string& path) {
796 if (path[0] == '/' || path[0] == '~' || path.find(':') != string::npos) {
797 return true;
798 }
799 return false;
800}
801
813std::pair<string, string> TRestTools::SeparatePathAndName(const string& fullname) {
814 filesystem::path path(fullname);
815 return {path.parent_path().string(), path.filename().string()};
816}
817
823string TRestTools::GetFileNameExtension(const string& fullname) {
824 string extension = filesystem::path(fullname).extension().string();
825 if (extension.size() > 1) return extension.substr(1);
826 return extension;
827}
828
834string TRestTools::GetFileNameRoot(const string& fullname) {
835 return filesystem::path(fullname).stem().string();
836}
837
845 // we replace multiple appearances of "/" (slash) by a single "/"
846 string to_replace = "//";
847 size_t start_pos = str.find(to_replace);
848 while (start_pos != string::npos) {
849 str.replace(start_pos, to_replace.length(), "/");
850 start_pos = str.find(to_replace);
851 }
852 return str;
853}
854
863string TRestTools::GetPureFileName(const string& path) { return filesystem::path(path).filename().string(); }
864
868string TRestTools::ToAbsoluteName(const string& filename) {
869 filesystem::path path;
870 for (const auto& directory : filesystem::path(filename)) {
871 if (path.empty() && directory == "~") {
872 // path starts with ~
873 const auto envVariableHome = getenv("HOME");
874 if (envVariableHome == nullptr) {
875 cout << "TRestTools::ToAbsoluteName - ERROR - "
876 "cannot resolve ~ because 'HOME' env variable does not exist"
877 << endl;
878 exit(1);
879 }
880 const auto userHomePath = filesystem::path(envVariableHome);
881 if (userHomePath.empty()) {
882 cout << "TRestTools::ToAbsoluteName - ERROR - "
883 "cannot resolve ~ because 'HOME' env variable is not set to a valid value"
884 << endl;
885 exit(1);
886 }
887 path /= userHomePath;
888 } else {
889 path /= directory;
890 }
891 }
892 return filesystem::weakly_canonical(path).string();
893}
894
904vector<string> TRestTools::GetSubdirectories(const string& _path, int recursion) {
905 vector<string> result;
906
907 std::filesystem::path path(_path);
908 if (exists(path)) {
909 std::filesystem::directory_iterator iter(path);
910 for (auto& it : iter) {
911 if (it.is_directory()) {
912 result.push_back(it.path().string());
913
914 if (recursion != 0) {
915 vector<string> subD = GetSubdirectories(it.path().string(), recursion - 1);
916 result.insert(result.begin(), subD.begin(), subD.end());
917 }
918 }
919 }
920 }
921
922 return result;
923}
924
929string TRestTools::SearchFileInPath(vector<string> paths, string filename) {
930 if (fileExists(filename)) {
931 return filename;
932 } else {
933 for (unsigned int i = 0; i < paths.size(); i++) {
934 string path = paths[i];
935 if (path[path.size() - 1] != '/') {
936 path = path + "/";
937 }
938
939 if (fileExists(path + filename)) {
940 return path + filename;
941 }
942
943 // search also in subdirectory, but only 5 times of recursion
944 vector<string> pathsExpanded = GetSubdirectories(paths[i], 5);
945 for (unsigned int j = 0; j < pathsExpanded.size(); j++)
946 if (fileExists(pathsExpanded[j] + "/" + filename)) return pathsExpanded[j] + "/" + filename;
947 }
948 }
949 return "";
950}
951
956bool TRestTools::CheckFileIsAccessible(const std::string& filename) {
957 ifstream ifs;
958 ifs.open(filename.c_str());
959
960 if (!ifs) {
961 return false;
962 } else {
963 ifs.close();
964 }
965 return true;
966}
967
976vector<string> TRestTools::GetFilesMatchingPattern(string pattern, bool unlimited) {
977 std::vector<string> outputFileNames;
978 if (pattern != "") {
979 vector<string> items = Split(pattern, "\n");
980 for (auto item : items) {
981 if (item.find_first_of("*?") != string::npos) {
982#ifdef WIN32
983 item = Replace(item, "/", "\\");
984 string item_trim =
985 item.substr(0, item.find_first_of("*?")); // trim string to before wildcard character
986 auto path_name = SeparatePathAndName(item_trim);
987 string _path = path_name.first;
988 if (!std::filesystem::exists(_path)) {
989 RESTError << "TRestTools::GetFilesMatchingPattern(): path " << _path << " does not exist!"
990 << RESTendl;
991 return outputFileNames;
992 }
993
994 std::filesystem::path path(_path);
995 std::filesystem::recursive_directory_iterator iter(path);
996 for (auto& it : iter) {
997 if (it.is_regular_file()) {
998 string filename = it.path().string();
999 if (MatchString(filename, item)) {
1000 outputFileNames.push_back(it.path().string());
1001 }
1002 }
1003 }
1004#else
1005 auto path_name = SeparatePathAndName(item);
1006 if (unlimited) {
1007 std::string currentDir = filesystem::current_path();
1008 ChangeDirectory(path_name.first);
1009 string a = Execute("find -type f -name \'" + path_name.second + "\'");
1010 ChangeDirectory(currentDir);
1011 auto b = Split(a, "\n");
1012
1013 for (unsigned int i = 0; i < b.size(); i++) {
1014 outputFileNames.push_back(path_name.first + "/" + b[i]);
1015 }
1016
1017 } else {
1018 string a = Execute("find " + item);
1019 auto b = Split(a, "\n");
1020
1021 for (unsigned int i = 0; i < b.size(); i++) {
1022 outputFileNames.push_back(b[i]);
1023 }
1024 }
1025#endif
1026
1027 } else {
1028 if (fileExists(item)) outputFileNames.push_back(item);
1029 }
1030 }
1031 }
1032 return outputFileNames;
1033}
1034
1039#ifndef REST_Version
1040#define REST_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
1041#endif
1042 vector<string> ver = Split(in, ".");
1043 if (ver.size() == 3) {
1044 vector<int> verint;
1045 for (auto v : ver) {
1046 int n = StringToInteger(v.substr(0, v.find_first_not_of("0123456789")));
1047 if (n != -1) {
1048 verint.push_back(n);
1049 } else {
1050 return -1;
1051 }
1052 }
1053 return REST_VERSION(verint[0], verint[1], verint[2]);
1054 }
1055 return -1;
1056}
1057
1061string TRestTools::Execute(string cmd) {
1062 std::array<char, 128> buffer;
1063 string result;
1064#ifdef WIN32
1065 std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(("powershell.exe " + cmd).c_str(), "r"), _pclose);
1066#else
1067 std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
1068#endif // WIN32
1069
1070 if (!pipe) {
1071 throw std::runtime_error("popen() failed!");
1072 }
1073 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
1074 result += buffer.data();
1075 }
1076
1077 if (result.size() > 0 && result[result.size() - 1] == '\n')
1078 result = result.substr(0, result.size() - 1); // remove last "\n"
1079
1080 return result;
1081}
1082
1087std::istream& TRestTools::GetLine(std::istream& is, std::string& t) {
1088 t.clear();
1089
1090 // The characters in the stream are read one-by-one using a std::streambuf.
1091 // That is faster than reading them one-by-one using the std::istream.
1092 // Code that uses streambuf this way must be guarded by a sentry object.
1093 // The sentry object performs various tasks,
1094 // such as thread synchronization and updating the stream state.
1095
1096 std::istream::sentry se(is, true);
1097 std::streambuf* sb = is.rdbuf();
1098
1099 for (;;) {
1100 int c = sb->sbumpc();
1101 switch (c) {
1102 case '\n':
1103 return is;
1104 case '\r':
1105 if (sb->sgetc() == '\n') sb->sbumpc();
1106 return is;
1107 case std::streambuf::traits_type::eof():
1108 // Also handle the case when the last line has no line ending
1109 if (t.empty()) is.setstate(std::ios::eofbit);
1110 return is;
1111 default:
1112 t += (char)c;
1113 }
1114 }
1115}
1116
1124std::string TRestTools::DownloadRemoteFile(const string& url, bool pidPrefix) {
1125 string pureName = TRestTools::GetPureFileName(url);
1126 if (pureName.empty()) {
1127 RESTWarning << "error! (TRestTools::DownloadRemoteFile): url is not a file!" << RESTendl;
1128 RESTWarning << "please specify a concrete file name in this url" << RESTendl;
1129 RESTWarning << "url: " << url << RESTendl;
1130 return "";
1131 }
1132
1133 if (url.find("local:") == 0) {
1134 return Replace(url, "local:", "");
1135 } else {
1136 string fullpath =
1137 REST_USER_PATH + "/download/" + (pidPrefix ? "PID_" + ToString(getpid()) + "_" : "") + pureName;
1138 int out;
1139 int attempts = 10;
1140 do {
1141 out = TRestTools::DownloadRemoteFile(url, fullpath);
1142 if (out == 1024) {
1143 RESTWarning << "Retrying download in 5 seconds" << RESTendl;
1144 std::this_thread::sleep_for(std::chrono::seconds(5));
1145 } else if (attempts < 10) {
1146 RESTSuccess << "Download succeeded after " << 10 - attempts << " attempts" << RESTendl;
1147 }
1148 attempts--;
1149 } while (out == 1024 && attempts > 0);
1150
1151 if (out == 0 || TRestTools::fileExists(fullpath)) {
1152 return fullpath;
1153 } else {
1154 return "";
1155 }
1156 }
1157}
1158
1165int TRestTools::DownloadRemoteFile(string remoteFile, string localFile) {
1166 TUrl url(remoteFile.c_str());
1167
1168 RESTInfo << "Downloading remote file : " << remoteFile << RESTendl;
1169 RESTInfo << "To local file : " << localFile << RESTendl;
1170
1171 string localFiletmp = localFile + ".restdownload";
1172 if ((string)url.GetProtocol() == "https" || (string)url.GetProtocol() == "http") {
1173 string path = TRestTools::SeparatePathAndName(localFiletmp).first;
1174 if (!TRestTools::fileExists(path)) {
1175 if (!filesystem::create_directories(path)) {
1176 std::cerr << "mkdir failed to create directory: " << path << std::endl;
1177 return -1;
1178 }
1179 }
1180
1181 string cmd = "wget --no-check-certificate " + EscapeSpecialLetters(remoteFile) + " -O " +
1182 EscapeSpecialLetters(localFiletmp) + " -q";
1183 RESTDebug << cmd << RESTendl;
1184 int a = system(cmd.c_str());
1185
1186 if (a == 0) {
1187 rename(localFiletmp.c_str(), localFile.c_str());
1188 return 0;
1189 } else {
1190 RESTError << "download failed! (" << remoteFile << ")" << RESTendl;
1191 if (a == 1024) {
1192 RESTError << "Network connection problem?" << RESTendl;
1193 return 1024;
1194 }
1195 if (a == 2048) {
1196 RESTError << "File does NOT exist in remotely?" << RESTendl;
1197 return 2048;
1198 }
1199 }
1200 } else if ((string)url.GetProtocol() == "ssh") {
1201 string cmd = "scp -P " + ToString(url.GetPort() == 0 ? 22 : url.GetPort()) + " " + url.GetUser() +
1202 "@" + url.GetHost() + ":" + EscapeSpecialLetters(url.GetFile()) + " " + localFiletmp;
1203 cout << cmd << endl;
1204 int a = system(cmd.c_str());
1205 if (a == 0) {
1206 rename(localFiletmp.c_str(), localFile.c_str());
1207 return 0;
1208 }
1209 } else {
1210 if (!TRestTools::fileExists(remoteFile)) {
1211 RESTWarning << "Trying to download: " << remoteFile << RESTendl;
1212 RESTWarning << "Unknown protocol!" << RESTendl;
1213 }
1214 }
1215
1216 return -1;
1217}
1218
1223std::string TRestTools::POSTRequest(const std::string& url, const std::map<std::string, std::string>& keys) {
1224 std::string file_content = "";
1225#ifdef USE_Curl
1226 CURL* curl;
1227 CURLcode res;
1228
1229 string filename = REST_USER_PATH + "/download/curl.out";
1230
1231 /* In windows, this will init the winsock stuff */
1232 curl_global_init(CURL_GLOBAL_ALL);
1233
1234 FILE* f = fopen(filename.c_str(), "wt");
1235
1236 std::string request = "";
1237 int n = 0;
1238 for (auto const& x : keys) {
1239 if (n > 0) request += "&";
1240 request += x.first + "=" + x.second;
1241 n++;
1242 }
1243 /* get a curl handle */
1244 curl = curl_easy_init();
1245 if (curl) {
1246 /* First set the URL that is about to receive our POST. This URL can
1247 just as well be a https:// URL if that is what should receive the
1248 data. */
1249 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
1250 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)f);
1251 /* Now specify the POST data */
1252 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.c_str());
1253
1254 /* Perform the request, res will get the return code */
1255 res = curl_easy_perform(curl);
1256 /* Check for errors */
1257 if (res != CURLE_OK)
1258 RESTError << "curl_easy_perform() failed: " << curl_easy_strerror(res) << RESTendl;
1259
1260 /* always cleanup */
1261 curl_easy_cleanup(curl);
1262 }
1263 fclose(f);
1264 curl_global_cleanup();
1265
1266 std::getline(std::ifstream(filename), file_content, '\0');
1267#else
1268 RESTError << "TRestTools::POSTRequest. REST framework was compiled without CURL support" << RESTendl;
1269 RESTError << "Please recompile REST after installing curl development libraries." << RESTendl;
1270 RESTError << "Depending on your system this might be: curl-dev, curl-devel or libcurl-openssl-dev. "
1271 << RESTendl;
1272 RESTError << "No file will be downloaded" << RESTendl;
1273#endif
1274
1275 return file_content;
1276}
1277
1285int TRestTools::UploadToServer(string localFile, string remoteFile, string methodUrl) {
1286 if (!TRestTools::fileExists(localFile)) {
1287 cout << "error! local file not exist!" << endl;
1288 return -1;
1289 }
1290 // construct path
1291 // [proto://][user[:passwd]@]host[:port]/file.ext[#anchor][?options]
1292 TUrl url(remoteFile.c_str());
1293 TUrl method(methodUrl.c_str());
1294 if (method.GetProtocol() != (string) "") url.SetProtocol(method.GetProtocol());
1295 if (method.GetPort() != 0) url.SetPort(method.GetPort());
1296 if (method.GetUser() != (string) "") url.SetUser(method.GetUser());
1297 if (method.GetPasswd() != (string) "") url.SetPasswd(method.GetPasswd());
1298
1299 if ((string)url.GetProtocol() == "https" || (string)url.GetProtocol() == "http") {
1300 // maybe we use curl to upload to http in future
1301 } else if ((string)url.GetProtocol() == "ssh") {
1302 string cmd = "scp -P " + ToString(url.GetPort() == 0 ? 22 : url.GetPort()) + " " +
1303 EscapeSpecialLetters(localFile) + " " + url.GetUser() + "@" + url.GetHost() + ":" +
1304 EscapeSpecialLetters(url.GetFile());
1305 cout << cmd << endl;
1306 int a = system(cmd.c_str());
1307
1308 if (a != 0) {
1309 RESTError << __PRETTY_FUNCTION__ << RESTendl;
1310 RESTError << "problem copying gases definitions to remote server" << RESTendl;
1311 RESTError << "Please report this problem at "
1312 "http://gifna.unizar.es/rest-forum/"
1313 << RESTendl;
1314 return -1;
1315 }
1316
1317 return 0;
1318 }
1319 return 0;
1320}
1321
1322void TRestTools::ChangeDirectory(const string& toDirectory) { filesystem::current_path(toDirectory); }
1323
1332std::vector<int> TRestTools::CanvasDivisions(int n) {
1333 std::vector<int> r;
1334 for (int i = 2; i * i <= n; i += 1 + (i > 2)) {
1335 while ((n % i) == 0) {
1336 r.push_back(i);
1337 n /= i;
1338 }
1339 }
1340 if (n != 1) r.push_back(n);
1341
1342 while (r.size() > 2) {
1343 // We multiply the 2 lowest elements and
1344 // replace the elements in the vector by the result
1345 auto min1 = std::min_element(r.begin(), r.end());
1346 int low1 = *min1;
1347
1348 // Remove the first element equal to min1 (efficient way)
1349 auto it = std::find(r.begin(), r.end(), low1);
1350 if (it != r.end()) {
1351 std::iter_swap(it, r.end() - 1);
1352 r.erase(r.end() - 1);
1353 }
1354
1355 auto min2 = std::min_element(r.begin(), r.end());
1356 int low2 = *min2;
1357
1358 // Remove the first element equal to min2 (efficient way)
1359 it = std::find(r.begin(), r.end(), low2);
1360 if (it != r.end()) {
1361 std::iter_swap(it, r.end() - 1);
1362 r.erase(r.end() - 1);
1363 }
1364
1365 int resultado = low1 * low2;
1366 r.push_back(resultado);
1367 }
1368
1369 std::sort(r.begin(), r.end());
1370
1371 if (r.size() == 1) r.push_back(1);
1372
1373 return r;
1374}
1375
1376string ValueWithQuantity::ToString() const {
1377 string unit;
1378 auto value = fValue;
1379 if (fQuantity == ENERGY) {
1380 unit = "eV";
1381 value *= 1E3; // since we store energy in keV, not in eV
1382 } else if (fQuantity == TIME) {
1383 unit = "s"; // time is stored in microseconds
1384 value *= 1E-6;
1385 } else if (fQuantity == LENGTH) {
1386 unit = "m";
1387 value *= 1E-3; // since we store length in mm, not in m
1388 } else {
1389 return "";
1390 }
1391
1392 const auto abs = TMath::Abs(value);
1393 if (abs == 0) {
1394 return TString::Format("%d", 0).Data();
1395 } else if (abs < 1E-6) {
1396 return TString::Format("%.2f %s%s", value * 1E9, "n", unit.c_str()).Data();
1397 } else if (abs < 1E-3) {
1398 return TString::Format("%.2f %s%s", value * 1E6, "u", unit.c_str()).Data();
1399 } else if (abs < 1E0) {
1400 return TString::Format("%.2f %s%s", value * 1E3, "m", unit.c_str()).Data();
1401 } else if (abs < 1E3) {
1402 return TString::Format("%.2f %s%s", value * 1E0, "", unit.c_str()).Data();
1403 } else if (abs < 1E6) {
1404 return TString::Format("%.2f %s%s", value * 1E-3, "k", unit.c_str()).Data();
1405 } else if (abs < 1E9) {
1406 return TString::Format("%.2f %s%s", value * 1E-6, "M", unit.c_str()).Data();
1407 } else if (abs < 1E12) {
1408 return TString::Format("%.2f %s%s", value * 1E-9, "G", unit.c_str()).Data();
1409 } else {
1410 return TString::Format("%.2f %s%s", value * 1E-12, "T", unit.c_str()).Data();
1411 }
1412}
1413
1414string ToTimeStringLong(double seconds) {
1415 const auto abs = TMath::Abs(seconds);
1416 if (abs < 60) {
1417 return TString::Format("%.2f %s", seconds, "seconds").Data();
1418 } else if (abs < 60 * 60) {
1419 return TString::Format("%.2f %s", seconds / 60.0, "minutes").Data();
1420 } else if (abs < 60 * 60 * 24) {
1421 return TString::Format("%.2f %s", seconds / (60.0 * 60.0), "hours").Data();
1422 } else {
1423 return TString::Format("%.2f %s", seconds / (60.0 * 60.0 * 24.0), "days").Data();
1424 }
1425}
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.
Definition: TRestTools.cxx:813
static Int_t isValidFile(const std::string &path)
Returns true if the file with path filename exists.
Definition: TRestTools.cxx:719
static std::string GetFileNameExtension(const std::string &fullname)
Gets the file extension as the substring found after the latest ".".
Definition: TRestTools.cxx:823
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.
Definition: TRestTools.cxx:904
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.
Definition: TRestTools.cxx:577
static bool CheckFileIsAccessible(const std::string &)
Checks if the config file can be opened (and thus exists). It returns true in case of success,...
Definition: TRestTools.cxx:956
static std::string GetPureFileName(const std::string &fullPathFileName)
Removes all directories in the full path filename description given in the argument.
Definition: TRestTools.cxx:863
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.
Definition: TRestTools.cxx:253
static int GetBinaryFileColumns(std::string fname)
It extracts the number of columns from the filename extension given by argument. The file should cont...
Definition: TRestTools.cxx:315
static std::vector< std::string > GetOptions(std::string optionsStr)
Returns all the options in an option string.
Definition: TRestTools.cxx:86
static int PrintTable(std::vector< std::vector< T > > data, Int_t start=0, Int_t end=0)
Prints the contents of the vector table given as argument in screen. Allowed types are Int_t,...
Definition: TRestTools.cxx:163
static std::string GetFileNameRoot(const std::string &fullname)
Gets the filename root as the substring found before the latest ".".
Definition: TRestTools.cxx:834
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....
Definition: TRestTools.cxx:370
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...
Definition: TRestTools.cxx:442
static void LoadRESTLibrary(bool silent=false)
Calls gSystem to load REST library.
Definition: TRestTools.cxx:95
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.
Definition: TRestTools.cxx:695
static bool isRunFile(const std::string &filename)
It checks if the file has been processed using a REST event processing chain.
Definition: TRestTools.cxx:738
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,...
Definition: TRestTools.cxx:185
static bool fileExists(const std::string &filename)
Returns true if the file (or directory) with path filename exists.
Definition: TRestTools.cxx:728
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....
Definition: TRestTools.cxx:405
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....
Definition: TRestTools.cxx:976
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.
Definition: TRestTools.cxx:778
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...
Definition: TRestTools.cxx:472
static bool isAbsolutePath(const std::string &path)
Check if the path is absolute path or not.
Definition: TRestTools.cxx:795
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....
Definition: TRestTools.cxx:214
static Bool_t IsBinaryFile(std::string fname)
It identifies if the filename extension follows the formatting ".Nxyzf", where the number of columns ...
Definition: TRestTools.cxx:303
static std::string RemoveMultipleSlash(std::string)
Returns the input string but without multiple slashes ("/")
Definition: TRestTools.cxx:844
static bool isDataSet(const std::string &filename)
It checks if the file contains a dataset object.
Definition: TRestTools.cxx:754
static bool isURL(const std::string &filename)
Returns true if filename is an http address.
Definition: TRestTools.cxx:770
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 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.
Definition: TRestTools.cxx:733
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.
Definition: TRestTools.cxx:929
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...
Definition: TRestTools.cxx:345
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 ...
Definition: TRestTools.cxx:494
static std::string ToAbsoluteName(const std::string &filename)
It takes a path and returns its absolute path.
Definition: TRestTools.cxx:868
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.