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
875std::set<std::string> TRestTools::GetMatchingStrings(const std::vector<std::string>& stack,
876 const std::vector<std::string>& wantedStrings) {
877 std::set<std::string> result;
878 for (auto& ws : wantedStrings) {
879 if (ws.find("*") != std::string::npos || ws.find("?") != std::string::npos) {
880 for (auto& c : stack)
881 if (MatchString(c, ws)) result.insert(c);
882 } else if (std::find(stack.begin(), stack.end(), ws) != stack.end())
883 result.insert(ws);
884 }
885 // return std::vector<std::string>(result.begin(), result.end()); // convert to vector
886 return result;
887}
888
896 // we replace multiple appearances of "/" (slash) by a single "/"
897 string to_replace = "//";
898 size_t start_pos = str.find(to_replace);
899 while (start_pos != string::npos) {
900 str.replace(start_pos, to_replace.length(), "/");
901 start_pos = str.find(to_replace);
902 }
903 return str;
904}
905
914string TRestTools::GetPureFileName(const string& path) { return filesystem::path(path).filename().string(); }
915
919string TRestTools::ToAbsoluteName(const string& filename) {
920 filesystem::path path;
921 for (const auto& directory : filesystem::path(filename)) {
922 if (path.empty() && directory == "~") {
923 // path starts with ~
924 const auto envVariableHome = getenv("HOME");
925 if (envVariableHome == nullptr) {
926 cout << "TRestTools::ToAbsoluteName - ERROR - "
927 "cannot resolve ~ because 'HOME' env variable does not exist"
928 << endl;
929 exit(1);
930 }
931 const auto userHomePath = filesystem::path(envVariableHome);
932 if (userHomePath.empty()) {
933 cout << "TRestTools::ToAbsoluteName - ERROR - "
934 "cannot resolve ~ because 'HOME' env variable is not set to a valid value"
935 << endl;
936 exit(1);
937 }
938 path /= userHomePath;
939 } else {
940 path /= directory;
941 }
942 }
943 return filesystem::weakly_canonical(path).string();
944}
945
955vector<string> TRestTools::GetSubdirectories(const string& _path, int recursion) {
956 vector<string> result;
957
958 std::filesystem::path path(_path);
959 if (exists(path)) {
960 std::filesystem::directory_iterator iter(path);
961 for (auto& it : iter) {
962 if (it.is_directory()) {
963 result.push_back(it.path().string());
964
965 if (recursion != 0) {
966 vector<string> subD = GetSubdirectories(it.path().string(), recursion - 1);
967 result.insert(result.begin(), subD.begin(), subD.end());
968 }
969 }
970 }
971 }
972
973 return result;
974}
975
980string TRestTools::SearchFileInPath(vector<string> paths, string filename) {
981 if (fileExists(filename)) {
982 return filename;
983 } else {
984 for (unsigned int i = 0; i < paths.size(); i++) {
985 string path = paths[i];
986 if (path[path.size() - 1] != '/') {
987 path = path + "/";
988 }
989
990 if (fileExists(path + filename)) {
991 return path + filename;
992 }
993
994 // search also in subdirectory, but only 5 times of recursion
995 vector<string> pathsExpanded = GetSubdirectories(paths[i], 5);
996 for (unsigned int j = 0; j < pathsExpanded.size(); j++)
997 if (fileExists(pathsExpanded[j] + "/" + filename)) return pathsExpanded[j] + "/" + filename;
998 }
999 }
1000 return "";
1001}
1002
1007bool TRestTools::CheckFileIsAccessible(const std::string& filename) {
1008 ifstream ifs;
1009 ifs.open(filename.c_str());
1010
1011 if (!ifs) {
1012 return false;
1013 } else {
1014 ifs.close();
1015 }
1016 return true;
1017}
1018
1027vector<string> TRestTools::GetFilesMatchingPattern(string pattern, bool unlimited) {
1028 std::vector<string> outputFileNames;
1029 if (pattern != "") {
1030 vector<string> items = Split(pattern, "\n");
1031 for (auto item : items) {
1032 if (item.find_first_of("*?") != string::npos) {
1033#ifdef WIN32
1034 item = Replace(item, "/", "\\");
1035 string item_trim =
1036 item.substr(0, item.find_first_of("*?")); // trim string to before wildcard character
1037 auto path_name = SeparatePathAndName(item_trim);
1038 string _path = path_name.first;
1039 if (!std::filesystem::exists(_path)) {
1040 RESTError << "TRestTools::GetFilesMatchingPattern(): path " << _path << " does not exist!"
1041 << RESTendl;
1042 return outputFileNames;
1043 }
1044
1045 std::filesystem::path path(_path);
1046 std::filesystem::recursive_directory_iterator iter(path);
1047 for (auto& it : iter) {
1048 if (it.is_regular_file()) {
1049 string filename = it.path().string();
1050 if (MatchString(filename, item)) {
1051 outputFileNames.push_back(it.path().string());
1052 }
1053 }
1054 }
1055#else
1056 auto path_name = SeparatePathAndName(item);
1057 if (unlimited) {
1058 std::string currentDir = filesystem::current_path();
1059 ChangeDirectory(path_name.first);
1060 string a = Execute("find -type f -name \'" + path_name.second + "\'");
1061 ChangeDirectory(currentDir);
1062 auto b = Split(a, "\n");
1063
1064 for (unsigned int i = 0; i < b.size(); i++) {
1065 outputFileNames.push_back(path_name.first + "/" + b[i]);
1066 }
1067
1068 } else {
1069 string a = Execute("find " + item);
1070 auto b = Split(a, "\n");
1071
1072 for (unsigned int i = 0; i < b.size(); i++) {
1073 outputFileNames.push_back(b[i]);
1074 }
1075 }
1076#endif
1077
1078 } else {
1079 if (fileExists(item)) outputFileNames.push_back(item);
1080 }
1081 }
1082 }
1083 return outputFileNames;
1084}
1085
1090#ifndef REST_Version
1091#define REST_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
1092#endif
1093 vector<string> ver = Split(in, ".");
1094 if (ver.size() == 3) {
1095 vector<int> verint;
1096 for (auto v : ver) {
1097 int n = StringToInteger(v.substr(0, v.find_first_not_of("0123456789")));
1098 if (n != -1) {
1099 verint.push_back(n);
1100 } else {
1101 return -1;
1102 }
1103 }
1104 return REST_VERSION(verint[0], verint[1], verint[2]);
1105 }
1106 return -1;
1107}
1108
1112string TRestTools::Execute(string cmd) {
1113 std::array<char, 128> buffer;
1114 string result;
1115#ifdef WIN32
1116 std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(("powershell.exe " + cmd).c_str(), "r"), _pclose);
1117#else
1118 std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
1119#endif // WIN32
1120
1121 if (!pipe) {
1122 throw std::runtime_error("popen() failed!");
1123 }
1124 while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
1125 result += buffer.data();
1126 }
1127
1128 if (result.size() > 0 && result[result.size() - 1] == '\n')
1129 result = result.substr(0, result.size() - 1); // remove last "\n"
1130
1131 return result;
1132}
1133
1138std::istream& TRestTools::GetLine(std::istream& is, std::string& t) {
1139 t.clear();
1140
1141 // The characters in the stream are read one-by-one using a std::streambuf.
1142 // That is faster than reading them one-by-one using the std::istream.
1143 // Code that uses streambuf this way must be guarded by a sentry object.
1144 // The sentry object performs various tasks,
1145 // such as thread synchronization and updating the stream state.
1146
1147 std::istream::sentry se(is, true);
1148 std::streambuf* sb = is.rdbuf();
1149
1150 for (;;) {
1151 int c = sb->sbumpc();
1152 switch (c) {
1153 case '\n':
1154 return is;
1155 case '\r':
1156 if (sb->sgetc() == '\n') sb->sbumpc();
1157 return is;
1158 case std::streambuf::traits_type::eof():
1159 // Also handle the case when the last line has no line ending
1160 if (t.empty()) is.setstate(std::ios::eofbit);
1161 return is;
1162 default:
1163 t += (char)c;
1164 }
1165 }
1166}
1167
1175std::string TRestTools::DownloadRemoteFile(const string& url, bool pidPrefix) {
1176 string pureName = TRestTools::GetPureFileName(url);
1177 if (pureName.empty()) {
1178 RESTWarning << "error! (TRestTools::DownloadRemoteFile): url is not a file!" << RESTendl;
1179 RESTWarning << "please specify a concrete file name in this url" << RESTendl;
1180 RESTWarning << "url: " << url << RESTendl;
1181 return "";
1182 }
1183
1184 if (url.find("local:") == 0) {
1185 return Replace(url, "local:", "");
1186 } else {
1187 string fullpath =
1188 REST_USER_PATH + "/download/" + (pidPrefix ? "PID_" + ToString(getpid()) + "_" : "") + pureName;
1189 int out;
1190 int attempts = 10;
1191 do {
1192 out = TRestTools::DownloadRemoteFile(url, fullpath);
1193 if (out == 1024) {
1194 RESTWarning << "Retrying download in 5 seconds" << RESTendl;
1195 std::this_thread::sleep_for(std::chrono::seconds(5));
1196 } else if (attempts < 10) {
1197 RESTSuccess << "Download succeeded after " << 10 - attempts << " attempts" << RESTendl;
1198 }
1199 attempts--;
1200 } while (out == 1024 && attempts > 0);
1201
1202 if (out == 0 || TRestTools::fileExists(fullpath)) {
1203 return fullpath;
1204 } else {
1205 return "";
1206 }
1207 }
1208}
1209
1216int TRestTools::DownloadRemoteFile(string remoteFile, string localFile) {
1217 TUrl url(remoteFile.c_str());
1218
1219 RESTInfo << "Downloading remote file : " << remoteFile << RESTendl;
1220 RESTInfo << "To local file : " << localFile << RESTendl;
1221
1222 string localFiletmp = localFile + ".restdownload";
1223 if ((string)url.GetProtocol() == "https" || (string)url.GetProtocol() == "http") {
1224 string path = TRestTools::SeparatePathAndName(localFiletmp).first;
1225 if (!TRestTools::fileExists(path)) {
1226 if (!filesystem::create_directories(path)) {
1227 std::cerr << "mkdir failed to create directory: " << path << std::endl;
1228 return -1;
1229 }
1230 }
1231
1232 string cmd = "wget --no-check-certificate " + EscapeSpecialLetters(remoteFile) + " -O " +
1233 EscapeSpecialLetters(localFiletmp) + " -q";
1234 RESTDebug << cmd << RESTendl;
1235 int a = system(cmd.c_str());
1236
1237 if (a == 0) {
1238 rename(localFiletmp.c_str(), localFile.c_str());
1239 return 0;
1240 } else {
1241 RESTError << "download failed! (" << remoteFile << ")" << RESTendl;
1242 if (a == 1024) {
1243 RESTError << "Network connection problem?" << RESTendl;
1244 return 1024;
1245 }
1246 if (a == 2048) {
1247 RESTError << "File does NOT exist in remotely?" << RESTendl;
1248 return 2048;
1249 }
1250 }
1251 } else if ((string)url.GetProtocol() == "ssh") {
1252 string cmd = "scp -P " + ToString(url.GetPort() == 0 ? 22 : url.GetPort()) + " " + url.GetUser() +
1253 "@" + url.GetHost() + ":" + EscapeSpecialLetters(url.GetFile()) + " " + localFiletmp;
1254 cout << cmd << endl;
1255 int a = system(cmd.c_str());
1256 if (a == 0) {
1257 rename(localFiletmp.c_str(), localFile.c_str());
1258 return 0;
1259 }
1260 } else {
1261 if (!TRestTools::fileExists(remoteFile)) {
1262 RESTWarning << "Trying to download: " << remoteFile << RESTendl;
1263 RESTWarning << "Unknown protocol!" << RESTendl;
1264 }
1265 }
1266
1267 return -1;
1268}
1269
1274std::string TRestTools::POSTRequest(const std::string& url, const std::map<std::string, std::string>& keys) {
1275 std::string file_content = "";
1276#ifdef USE_Curl
1277 CURL* curl;
1278 CURLcode res;
1279
1280 string filename = REST_USER_PATH + "/download/curl.out";
1281
1282 /* In windows, this will init the winsock stuff */
1283 curl_global_init(CURL_GLOBAL_ALL);
1284
1285 FILE* f = fopen(filename.c_str(), "wt");
1286
1287 std::string request = "";
1288 int n = 0;
1289 for (auto const& x : keys) {
1290 if (n > 0) request += "&";
1291 request += x.first + "=" + x.second;
1292 n++;
1293 }
1294 /* get a curl handle */
1295 curl = curl_easy_init();
1296 if (curl) {
1297 /* First set the URL that is about to receive our POST. This URL can
1298 just as well be a https:// URL if that is what should receive the
1299 data. */
1300 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
1301 curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)f);
1302 /* Now specify the POST data */
1303 curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request.c_str());
1304
1305 /* Perform the request, res will get the return code */
1306 res = curl_easy_perform(curl);
1307 /* Check for errors */
1308 if (res != CURLE_OK)
1309 RESTError << "curl_easy_perform() failed: " << curl_easy_strerror(res) << RESTendl;
1310
1311 /* always cleanup */
1312 curl_easy_cleanup(curl);
1313 }
1314 fclose(f);
1315 curl_global_cleanup();
1316
1317 std::getline(std::ifstream(filename), file_content, '\0');
1318#else
1319 RESTError << "TRestTools::POSTRequest. REST framework was compiled without CURL support" << RESTendl;
1320 RESTError << "Please recompile REST after installing curl development libraries." << RESTendl;
1321 RESTError << "Depending on your system this might be: curl-dev, curl-devel or libcurl-openssl-dev. "
1322 << RESTendl;
1323 RESTError << "No file will be downloaded" << RESTendl;
1324#endif
1325
1326 return file_content;
1327}
1328
1336int TRestTools::UploadToServer(string localFile, string remoteFile, string methodUrl) {
1337 if (!TRestTools::fileExists(localFile)) {
1338 cout << "error! local file not exist!" << endl;
1339 return -1;
1340 }
1341 // construct path
1342 // [proto://][user[:passwd]@]host[:port]/file.ext[#anchor][?options]
1343 TUrl url(remoteFile.c_str());
1344 TUrl method(methodUrl.c_str());
1345 if (method.GetProtocol() != (string) "") url.SetProtocol(method.GetProtocol());
1346 if (method.GetPort() != 0) url.SetPort(method.GetPort());
1347 if (method.GetUser() != (string) "") url.SetUser(method.GetUser());
1348 if (method.GetPasswd() != (string) "") url.SetPasswd(method.GetPasswd());
1349
1350 if ((string)url.GetProtocol() == "https" || (string)url.GetProtocol() == "http") {
1351 // maybe we use curl to upload to http in future
1352 } else if ((string)url.GetProtocol() == "ssh") {
1353 string cmd = "scp -P " + ToString(url.GetPort() == 0 ? 22 : url.GetPort()) + " " +
1354 EscapeSpecialLetters(localFile) + " " + url.GetUser() + "@" + url.GetHost() + ":" +
1355 EscapeSpecialLetters(url.GetFile());
1356 cout << cmd << endl;
1357 int a = system(cmd.c_str());
1358
1359 if (a != 0) {
1360 RESTError << __PRETTY_FUNCTION__ << RESTendl;
1361 RESTError << "problem copying gases definitions to remote server" << RESTendl;
1362 RESTError << "Please report this problem at "
1363 "http://gifna.unizar.es/rest-forum/"
1364 << RESTendl;
1365 return -1;
1366 }
1367
1368 return 0;
1369 }
1370 return 0;
1371}
1372
1373void TRestTools::ChangeDirectory(const string& toDirectory) { filesystem::current_path(toDirectory); }
1374
1383std::vector<int> TRestTools::CanvasDivisions(int n) {
1384 std::vector<int> r;
1385 for (int i = 2; i * i <= n; i += 1 + (i > 2)) {
1386 while ((n % i) == 0) {
1387 r.push_back(i);
1388 n /= i;
1389 }
1390 }
1391 if (n != 1) r.push_back(n);
1392
1393 while (r.size() > 2) {
1394 // We multiply the 2 lowest elements and
1395 // replace the elements in the vector by the result
1396 auto min1 = std::min_element(r.begin(), r.end());
1397 int low1 = *min1;
1398
1399 // Remove the first element equal to min1 (efficient way)
1400 auto it = std::find(r.begin(), r.end(), low1);
1401 if (it != r.end()) {
1402 std::iter_swap(it, r.end() - 1);
1403 r.erase(r.end() - 1);
1404 }
1405
1406 auto min2 = std::min_element(r.begin(), r.end());
1407 int low2 = *min2;
1408
1409 // Remove the first element equal to min2 (efficient way)
1410 it = std::find(r.begin(), r.end(), low2);
1411 if (it != r.end()) {
1412 std::iter_swap(it, r.end() - 1);
1413 r.erase(r.end() - 1);
1414 }
1415
1416 int resultado = low1 * low2;
1417 r.push_back(resultado);
1418 }
1419
1420 std::sort(r.begin(), r.end());
1421
1422 if (r.size() == 1) r.push_back(1);
1423
1424 return r;
1425}
1426
1427string ValueWithQuantity::ToString() const {
1428 string unit;
1429 auto value = fValue;
1430 if (fQuantity == ENERGY) {
1431 unit = "eV";
1432 value *= 1E3; // since we store energy in keV, not in eV
1433 } else if (fQuantity == TIME) {
1434 unit = "s"; // time is stored in microseconds
1435 value *= 1E-6;
1436 } else if (fQuantity == LENGTH) {
1437 unit = "m";
1438 value *= 1E-3; // since we store length in mm, not in m
1439 } else {
1440 return "";
1441 }
1442
1443 const auto abs = TMath::Abs(value);
1444 if (abs == 0) {
1445 return TString::Format("%d", 0).Data();
1446 } else if (abs < 1E-6) {
1447 return TString::Format("%.2f %s%s", value * 1E9, "n", unit.c_str()).Data();
1448 } else if (abs < 1E-3) {
1449 return TString::Format("%.2f %s%s", value * 1E6, "u", unit.c_str()).Data();
1450 } else if (abs < 1E0) {
1451 return TString::Format("%.2f %s%s", value * 1E3, "m", unit.c_str()).Data();
1452 } else if (abs < 1E3) {
1453 return TString::Format("%.2f %s%s", value * 1E0, "", unit.c_str()).Data();
1454 } else if (abs < 1E6) {
1455 return TString::Format("%.2f %s%s", value * 1E-3, "k", unit.c_str()).Data();
1456 } else if (abs < 1E9) {
1457 return TString::Format("%.2f %s%s", value * 1E-6, "M", unit.c_str()).Data();
1458 } else if (abs < 1E12) {
1459 return TString::Format("%.2f %s%s", value * 1E-9, "G", unit.c_str()).Data();
1460 } else {
1461 return TString::Format("%.2f %s%s", value * 1E-12, "T", unit.c_str()).Data();
1462 }
1463}
1464
1465string ToTimeStringLong(double seconds) {
1466 const auto abs = TMath::Abs(seconds);
1467 if (abs < 60) {
1468 return TString::Format("%.2f %s", seconds, "seconds").Data();
1469 } else if (abs < 60 * 60) {
1470 return TString::Format("%.2f %s", seconds / 60.0, "minutes").Data();
1471 } else if (abs < 60 * 60 * 24) {
1472 return TString::Format("%.2f %s", seconds / (60.0 * 60.0), "hours").Data();
1473 } else {
1474 return TString::Format("%.2f %s", seconds / (60.0 * 60.0 * 24.0), "days").Data();
1475 }
1476}
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::set< std::string > GetMatchingStrings(const std::vector< std::string > &stack, const std::vector< std::string > &wantedStrings)
Returns a set of strings that match the wanted strings from the stack. The wanted strings can contain...
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.