13 #include <THnSparse.h>
15 #if defined(__linux__)
17 #elif defined(__APPLE__)
20 #include <sys/types.h>
21 #include <sys/socket.h>
24 #include "NHttpRequest.h"
27 #include <arrow/api.h>
28 #include <arrow/io/api.h>
29 #include <parquet/arrow/reader.h>
30 #include <parquet/exception.h>
49 bool previouslyEnabled = ROOT::IsImplicitMTEnabled();
51 if (ROOT::IsImplicitMTEnabled()) {
52 ROOT::DisableImplicitMT();
61 if (numthreads == -1) {
63 const char * nThreadsEnv = gSystem->Getenv(
"ROOT_MAX_THREADS");
66 numthreads = std::stoul(nThreadsEnv);
68 catch (
const std::exception & e) {
69 NLogError(
"Error parsing ROOT_MAX_THREADS: %s !!! Setting it to '1' ...", e.what());
79 ROOT::EnableThreadSafety();
83 ROOT::EnableImplicitMT(numthreads);
87 if (ROOT::IsImplicitMTEnabled()) {
88 NLogInfo(
"ROOT::ImplicitMT is enabled with number of threads: %d", ROOT::GetThreadPoolSize());
91 return previouslyEnabled;
100 if (filename.find(
"http://") == 0 || filename.find(
"https://") == 0 || filename.find(
"root://") == 0 ||
101 filename.find(
"file://") == 0 || filename.find(
"alien://") == 0) {
104 TString fn(filename.c_str());
105 if (fn.BeginsWith(
"/") || !fn.Contains(
"://")) {
108 NLogError(
"NUtils::IsFileSupported: File '%s' not found", filename.c_str());
117 TString pathStr(gSystem->ExpandPathName(path.c_str()));
119 if (pathStr.BeginsWith(
"http://") || pathStr.BeginsWith(
"https://")) {
124 int http_code = request.
head(pathStr.Data());
125 if (http_code == 200) {
131 else if (pathStr.BeginsWith(
"file://") || pathStr.BeginsWith(
"/") || !pathStr.Contains(
"://")) {
133 return gSystem->AccessPathName(pathStr.Data()) ==
false;
135 else if (pathStr.BeginsWith(
"root://") || pathStr.BeginsWith(
"alien://")) {
137 if (!pathStr.EndsWith(
".root")) {
139 pathStr +=
"?filetype=raw";
141 NLogDebug(
"NUtils::AccessPathName: Trying to open file '%s' ...", pathStr.Data());
142 TFile * f = TFile::Open(pathStr.Data());
143 if (f && !f->IsZombie()) {
159 if (source.empty()) {
160 NLogError(
"NUtils::Cp: Source file is empty");
163 if (destination.empty()) {
164 NLogError(
"NUtils::Cp: Destination file is empty");
169 NLogError(
"NUtils::Cp: Source file '%s' is not supported", source.c_str());
173 NLogError(
"NUtils::Cp: Destination file '%s' is not supported", destination.c_str());
177 NLogInfo(
"Copying file from '%s' to '%s' ...", source.c_str(), destination.c_str());
183 const std::vector<std::string> & labels)
188 int nBins = labels.size();
189 TAxis * a =
new TAxis(nBins, 0, nBins);
190 a->SetName(name.c_str());
191 a->SetTitle(title.c_str());
192 for (
int i = 0; i < nBins; i++) {
193 NLogTrace(
"NUtils::CreateAxisFromLabels: Adding label: %s", labels[i].c_str());
194 a->SetBinLabel(i + 1, labels[i].c_str());
200 const std::set<std::string> & labels)
205 int nBins = labels.size();
206 TAxis * a =
new TAxis(nBins, 0, nBins);
207 a->SetName(name.c_str());
208 a->SetTitle(title.c_str());
210 for (
const auto & label : labels) {
211 NLogTrace(
"NUtils::CreateAxisFromLabels: Adding label: %s", label.c_str());
212 a->SetBinLabel(i, label.c_str());
218 THnSparse *
NUtils::Convert(TH1 * h1, std::vector<std::string> names, std::vector<std::string> titles)
225 NLogError(
"TH1 h1 is null");
229 NLogInfo(
"Converting TH1 '%s' to THnSparse ...", h1->GetName());
235 auto bins = std::make_unique<Int_t[]>(nDims);
236 auto xmin = std::make_unique<Double_t[]>(nDims);
237 auto xmax = std::make_unique<Double_t[]>(nDims);
239 TAxis * aIn = h1->GetXaxis();
240 bins[0] = aIn->GetNbins();
241 xmin[0] = aIn->GetXmin();
242 xmax[0] = aIn->GetXmax();
244 THnSparse * hns =
new THnSparseD(h1->GetName(), h1->GetTitle(), nDims, bins.get(), xmin.get(), xmax.get());
247 for (
int i = 0; i < nDims; i++) {
248 TAxis * a = hns->GetAxis(i);
249 TAxis * aIn = h1->GetXaxis();
250 a->SetName(aIn->GetName());
251 a->SetTitle(aIn->GetTitle());
252 if (aIn->GetXbins()->GetSize() > 0) {
254 auto arr = std::make_unique<Double_t[]>(aIn->GetNbins() + 1);
255 arr[0] = aIn->GetBinLowEdge(1);
256 for (
int iBin = 1; iBin <= aIn->GetNbins(); iBin++) {
257 arr[iBin] = aIn->GetBinUpEdge(iBin);
259 a->Set(a->GetNbins(), arr.get());
263 for (
int i = 0; i < nDims; i++) {
264 if (!names[i].empty()) hns->GetAxis(i)->SetName(names[i].c_str());
265 if (!titles[i].empty()) hns->GetAxis(i)->SetTitle(titles[i].c_str());
269 for (Int_t i = 0; i <= h1->GetNbinsX() + 1; i++) {
270 double content = h1->GetBinContent(i);
272 hns->SetBinContent(p, content);
275 hns->SetEntries(h1->GetEntries());
276 if (h1->GetSumw2N() > 0) {
283 THnSparse *
NUtils::Convert(TH2 * h2, std::vector<std::string> names, std::vector<std::string> titles)
289 NLogError(
"TH2 h2 is null");
292 NLogInfo(
"Converting TH2 '%s' to THnSparse ...", h2->GetName());
294 auto bins = std::make_unique<Int_t[]>(nDims);
295 auto xmin = std::make_unique<Double_t[]>(nDims);
296 auto xmax = std::make_unique<Double_t[]>(nDims);
298 for (
int i = 0; i < nDims; i++) {
299 TAxis * aIn =
nullptr;
301 aIn = h2->GetXaxis();
303 aIn = h2->GetYaxis();
305 NLogError(
"Invalid axis index %d", i);
308 bins[i] = aIn->GetNbins();
309 xmin[i] = aIn->GetXmin();
310 xmax[i] = aIn->GetXmax();
313 THnSparse * hns =
new THnSparseD(h2->GetName(), h2->GetTitle(), nDims, bins.get(), xmin.get(), xmax.get());
315 for (Int_t i = 0; i < nDims; i++) {
316 TAxis * a = hns->GetAxis(i);
317 TAxis * aIn =
nullptr;
319 aIn = h2->GetXaxis();
321 aIn = h2->GetYaxis();
323 NLogError(
"Invalid axis index %d", i);
327 a->SetName(aIn->GetName());
328 a->SetTitle(aIn->GetTitle());
329 if (aIn->GetXbins()->GetSize() > 0) {
330 auto arr = std::make_unique<Double_t[]>(aIn->GetNbins() + 1);
331 arr[0] = aIn->GetBinLowEdge(1);
332 for (
int iBin = 1; iBin <= aIn->GetNbins(); iBin++) {
333 arr[iBin] = aIn->GetBinUpEdge(iBin);
335 a->Set(a->GetNbins(), arr.get());
339 for (Int_t i = 0; i < nDims; i++) {
340 if (!names[i].empty()) hns->GetAxis(i)->SetName(names[i].c_str());
341 if (!titles[i].empty()) hns->GetAxis(i)->SetTitle(titles[i].c_str());
345 for (Int_t i = 0; i <= h2->GetNbinsX() + 1; i++) {
346 for (Int_t j = 0; j <= h2->GetNbinsY() + 1; j++) {
347 double content = h2->GetBinContent(i, j);
349 hns->SetBinContent(p, content);
353 hns->SetEntries(h2->GetEntries());
354 if (h2->GetSumw2N() > 0) {
361 THnSparse *
NUtils::Convert(TH3 * h3, std::vector<std::string> names, std::vector<std::string> titles)
368 NLogError(
"TH3 h3 is null");
372 NLogInfo(
"Converting TH3 '%s' to THnSparse ...", h3->GetName());
375 auto bins = std::make_unique<Int_t[]>(nDims);
376 auto xmin = std::make_unique<Double_t[]>(nDims);
377 auto xmax = std::make_unique<Double_t[]>(nDims);
379 for (
int i = 0; i < nDims; i++) {
380 TAxis * aIn =
nullptr;
382 aIn = h3->GetXaxis();
384 aIn = h3->GetYaxis();
386 aIn = h3->GetZaxis();
388 NLogError(
"Invalid axis index %d", i);
391 bins[i] = aIn->GetNbins();
392 xmin[i] = aIn->GetXmin();
393 xmax[i] = aIn->GetXmax();
396 THnSparse * hns =
new THnSparseD(h3->GetName(), h3->GetTitle(), nDims, bins.get(), xmin.get(), xmax.get());
399 for (
int i = 0; i < nDims; i++) {
400 TAxis * a = hns->GetAxis(i);
401 TAxis * aIn =
nullptr;
403 aIn = h3->GetXaxis();
405 aIn = h3->GetYaxis();
407 aIn = h3->GetZaxis();
409 NLogError(
"Invalid axis index %d", i);
413 a->SetName(aIn->GetName());
414 a->SetTitle(aIn->GetTitle());
415 if (aIn->GetXbins()->GetSize() > 0) {
416 auto arr = std::make_unique<Double_t[]>(aIn->GetNbins() + 1);
417 arr[0] = aIn->GetBinLowEdge(1);
418 for (
int iBin = 1; iBin <= aIn->GetNbins(); iBin++) {
419 arr[iBin] = aIn->GetBinUpEdge(iBin);
421 a->Set(a->GetNbins(), arr.get());
425 for (Int_t i = 0; i < nDims; i++) {
426 if (!names[i].empty()) hns->GetAxis(i)->SetName(names[i].c_str());
427 if (!titles[i].empty()) hns->GetAxis(i)->SetTitle(titles[i].c_str());
431 for (Int_t i = 0; i <= h3->GetNbinsX() + 1; i++) {
432 for (Int_t j = 0; j <= h3->GetNbinsY() + 1; j++) {
433 for (Int_t k = 0; k <= h3->GetNbinsZ() + 1; k++) {
434 double content = h3->GetBinContent(i, j, k);
435 Int_t p[3] = {i, j, k};
436 hns->SetBinContent(p, content);
441 hns->SetEntries(h3->GetEntries());
442 if (h3->GetSumw2N() > 0) {
450 std::vector<int> newPoint, Option_t * option)
458 if (hns ==
nullptr) {
459 NLogError(
"NUtils::ReshapeSparseAxes: THnSparse hns is null");
464 NLogTrace(
"NUtils::ReshapeSparseAxes: Order vector is empty");
465 for (
long unsigned int i = 0; i < hns->GetNdimensions() + newAxes.size(); i++) {
466 NLogTrace(
"NUtils::ReshapeSparseAxes: Adding axis %d to order", i);
471 if (order.size() != hns->GetNdimensions() + newAxes.size()) {
472 NLogError(
"NUtils::ReshapeSparseAxes: Invalid size %d [order] != %d [hns->GetNdimensions()+newAxes]", order.size(),
473 hns->GetNdimensions() + newAxes.size());
477 if (newPoint.empty()) {
480 if (newAxes.size() != newPoint.size()) {
481 NLogError(
"NUtils::ReshapeSparseAxes: Invalid size %d [newAxes] != %d [newPoint]", newAxes.size(),
487 for (
size_t i = 0; i < order.size(); i++) {
488 if (order[i] < 0 || order[i] >= hns->GetNdimensions() + (
int)newAxes.size()) {
489 NLogError(
"NUtils::ReshapeSparseAxes: Invalid order[%d]=%d. Value is negative or higher then "
490 "'hns->GetNdimensions() + newAxes.size()' !!!",
497 for (
size_t i = 0; i < order.size(); i++) {
498 for (
size_t j = i + 1; j < order.size(); j++) {
499 if (order[i] == order[j]) {
500 NLogError(
"NUtils::ReshapeSparseAxes: Invalid order[%d]=%d and order[%d]=%d. Value is not unique !!!", i,
501 order[i], j, order[j]);
511 NLogTrace(
"NUtils::ReshapeSparseAxes: Reshaping sparse axes ...");
513 int nDims = hns->GetNdimensions() + newAxes.size();
514 auto bins = std::make_unique<Int_t[]>(nDims);
515 auto xmin = std::make_unique<Double_t[]>(nDims);
516 auto xmax = std::make_unique<Double_t[]>(nDims);
518 int newAxesIndex = 0;
519 for (
int i = 0; i < nDims; i++) {
522 if (id < hns->GetNdimensions()) {
523 a = hns->GetAxis(
id);
524 NLogTrace(
"NUtils::ReshapeSparseAxes: [ORIG] Axis [%d]->[%d]: %s %s %d %.2f %.2f",
id, i, a->GetName(),
525 a->GetTitle(), a->GetNbins(), a->GetXmin(), a->GetXmax());
528 newAxesIndex =
id - hns->GetNdimensions();
529 a = newAxes[newAxesIndex];
530 NLogTrace(
"NUtils::ReshapeSparseAxes: [NEW ] Axis [%d]->[%d]: %s %s %d %.2f %.2f",
id, i, a->GetName(),
531 a->GetTitle(), a->GetNbins(), a->GetXmin(), a->GetXmax());
533 bins[i] = a->GetNbins();
534 xmin[i] = a->GetXmin();
535 xmax[i] = a->GetXmax();
538 THnSparse * hnsNew =
new THnSparseD(hns->GetName(), hns->GetTitle(), nDims, bins.get(), xmin.get(), xmax.get());
541 for (
int i = 0; i < hnsNew->GetNdimensions(); i++) {
542 TAxis * aIn =
nullptr;
543 if (order[i] < hns->GetNdimensions()) {
544 aIn = hns->GetAxis(order[i]);
547 newAxesIndex = order[i] - hns->GetNdimensions();
548 aIn = newAxes[newAxesIndex];
551 TAxis * a = hnsNew->GetAxis(i);
552 a->SetName(aIn->GetName());
553 a->SetTitle(aIn->GetTitle());
554 if (aIn->GetXbins()->GetSize() > 0) {
555 auto arr = std::make_unique<Double_t[]>(aIn->GetNbins() + 1);
556 arr[0] = aIn->GetBinLowEdge(1);
557 for (
int iBin = 1; iBin <= aIn->GetNbins(); iBin++) {
558 arr[iBin] = aIn->GetBinUpEdge(iBin);
560 a->Set(a->GetNbins(), arr.get());
564 if (aIn->IsAlphanumeric()) {
565 for (
int j = 1; j <= aIn->GetNbins(); j++) {
566 const char * label = aIn->GetBinLabel(j);
567 a->SetBinLabel(j, label);
572 if (newPoint.empty()) {
573 NLogTrace(
"NUtils::ReshapeSparseAxes: New point is empty, filling is skipped and doing reset ...");
579 if (hns->GetNbins() > 0) {
581 NLogTrace(
"NUtils::ReshapeSparseAxes: Filling all bins ...");
582 for (Long64_t i = 0; i < hns->GetNbins(); i++) {
583 auto p = std::make_unique<Int_t[]>(nDims);
584 auto pNew = std::make_unique<Int_t[]>(nDims);
585 hns->GetBinContent(i, p.get());
586 Double_t v = hns->GetBinContent(i);
588 for (
int j = 0; j < nDims; j++) {
590 if (id < hns->GetNdimensions()) {
594 newAxesIndex =
id - hns->GetNdimensions();
595 pNew[j] = newPoint[newAxesIndex];
598 hnsNew->SetBinContent(pNew.get(), v);
600 hnsNew->SetEntries(hns->GetEntries());
603 if (opt.Contains(
"E")) {
604 NLogTrace(
"ReshapeSparseAxes: Calculating sumw2 ...");
607 NLogTrace(
"ReshapeSparseAxes: Reshaped sparse axes:");
609 for (
int i = 0; i < nDims; i++) {
610 TAxis * a = hnsNew->GetAxis(i);
611 NLogTrace(
"ReshapeSparseAxes: Axis %d: %s %s %d %.2f %.2f", i, a->GetName(), a->GetTitle(), a->GetNbins(),
612 a->GetXmin(), a->GetXmax());
629 max_val = -std::numeric_limits<double>::max();
630 min_val = std::numeric_limits<double>::max();
632 int first_bin_x = include_overflow_underflow ? 0 : 1;
633 int last_bin_x = include_overflow_underflow ? h->GetNbinsX() + 1 : h->GetNbinsX();
635 int first_bin_y = include_overflow_underflow ? 0 : 1;
636 int last_bin_y = include_overflow_underflow ? h->GetNbinsY() + 1 : h->GetNbinsY();
638 int first_bin_z = include_overflow_underflow ? 0 : 1;
639 int last_bin_z = include_overflow_underflow ? h->GetNbinsZ() + 1 : h->GetNbinsZ();
642 if (h->GetDimension() == 1) {
643 for (
int i = first_bin_x; i <= last_bin_x; ++i) {
644 double content = h->GetBinContent(i);
645 if (content > max_val) max_val = content;
646 if (content < min_val) min_val = content;
649 else if (h->GetDimension() == 2) {
650 for (
int i = first_bin_x; i <= last_bin_x; ++i) {
651 for (
int j = first_bin_y; j <= last_bin_y; ++j) {
652 double content = h->GetBinContent(i, j);
653 if (content > max_val) max_val = content;
654 if (content < min_val) min_val = content;
658 else if (h->GetDimension() == 3) {
659 for (
int i = first_bin_x; i <= last_bin_x; ++i) {
660 for (
int j = first_bin_y; j <= last_bin_y; ++j) {
661 for (
int k = first_bin_z; k <= last_bin_z; ++k) {
662 double content = h->GetBinContent(i, j, k);
663 if (content > max_val) max_val = content;
664 if (content < min_val) min_val = content;
670 NLogWarning(
"GetTrueHistogramMinMax: Histogram '%s' has unsupported dimension %d. "
671 "Using GetMaximum/GetMinimum as fallback.",
672 h->GetName(), h->GetDimension());
674 max_val = h->GetMaximum();
675 min_val = h->GetMinimum();
679 if (max_val == -std::numeric_limits<double>::max() && min_val == std::numeric_limits<double>::max()) {
691 filename = gSystem->ExpandPathName(filename.c_str());
692 if (createLocalDir) {
694 if (!mode.compare(
"RECREATE") || !mode.compare(
"UPDATE") || !mode.compare(
"WRITE")) {
696 TString filenameT(filename.c_str());
697 bool isLocalFile = filenameT.BeginsWith(
"file://");
700 filenameT.ReplaceAll(
"file://",
"");
703 isLocalFile = !filenameT.Contains(
"://");
708 std::string pwd = gSystem->pwd();
709 if (filenameT[0] !=
'/') filenameT = pwd +
"/" + filenameT;
710 filenameT.ReplaceAll(
"?remote=1&",
"?");
711 filenameT.ReplaceAll(
"?remote=1",
"");
712 filenameT.ReplaceAll(
"&remote=1",
"");
713 TUrl url(filenameT.Data());
715 std::string filenameLocal = gSystem->GetDirName(url.GetFile()).Data();
717 gSystem->mkdir(filenameLocal.c_str(), kTRUE);
721 return TFile::Open(filename.c_str(), mode.c_str());
731 TFile * f =
OpenFile(TString::Format(
"%s?filetype=raw", filename.c_str()).Data());
738 auto buff = std::make_unique<char[]>(buffsize + 1);
741 Long64_t buffread = 0;
742 while (buffread < f->GetSize()) {
743 if (buffread + buffsize > f->GetSize()) buffsize = f->GetSize() - buffread;
746 f->ReadBuffer(buff.get(), buffread, buffsize);
747 buff[buffsize] =
'\0';
748 content += buff.get();
749 buffread += buffsize;
760 TFile * f =
OpenFile(TString::Format(
"%s?filetype=raw", filename.c_str()).Data(),
"RECREATE");
762 NLogError(
"Error: Problem opening file '%s' in 'rw' mode ...", filename.c_str());
765 f->WriteBuffer(content.c_str(), content.size());
777 if (content.empty()) {
779 Printf(
"Error: Problem opening macro '%s' ...", filename.c_str());
782 Printf(
"Using macro '%s' ...", filename.c_str());
783 TUrl url(filename.c_str());
784 std::string basefilename = gSystem->BaseName(url.GetFile());
785 basefilename.pop_back();
786 basefilename.pop_back();
787 TMacro * m =
new TMacro();
788 m->SetName(basefilename.c_str());
789 m->AddLine(content.c_str());
800 if (content.empty()) {
801 NLogError(
"NUtils::LoadJsonFile: Problem opening JSON file '%s' ...", filename.c_str());
806 json myCfg = json::parse(content.c_str());
807 cfg.merge_patch(myCfg);
808 NLogInfo(
"NUtils::LoadJsonFile: Successfully parsed JSON file '%s' ...", filename.c_str());
810 catch (json::parse_error & e) {
811 NLogError(
"NUtils::LoadJsonFile: JSON parse error in file '%s' at byte %d: %s", filename.c_str(), e.byte, e.what());
818 std::vector<std::string>
NUtils::Find(std::string path, std::string filename)
824 std::vector<std::string> files;
825 TString pathStr = gSystem->ExpandPathName(path.c_str());
826 if (pathStr.IsNull() || filename.empty()) {
827 NLogError(
"NUtils::Find: Path or filename is empty");
831 if (pathStr.BeginsWith(
"root://")) {
832 return FindEos(path, filename);
847 std::vector<std::string> files;
848 if (gSystem->AccessPathName(path.c_str())) {
849 NLogError(
"NUtils::FindLocal: Path '%s' does not exist", path.c_str());
852 NLogInfo(
"Doing find %s -name %s", path.c_str(), filename.c_str());
853 std::string linesMerge =
854 gSystem->GetFromPipe(TString::Format(
"find %s -name %s", path.c_str(), filename.c_str())).Data();
856 std::stringstream check2(linesMerge);
858 while (std::getline(check2, line)) {
859 files.push_back(line);
869 std::vector<std::string> files;
870 NLogInfo(
"Doing eos find -f --name %s %s ", filename.c_str(), path.c_str());
872 TUrl url(path.c_str());
873 std::string host = url.GetHost();
874 std::string directory = url.GetFile();
875 std::string findUrl =
"root://";
876 findUrl += host +
"//proc/user/";
877 findUrl +=
"?mgm.cmd=find&mgm.find.match=" + filename;
878 findUrl +=
"&mgm.path=" + directory;
879 findUrl +=
"&mgm.format=json&mgm.option=f&filetype=raw";
880 NLogInfo(
"Doing TFile::Open on '%s' ...", findUrl.c_str());
883 if (!f)
return files;
889 auto buff = std::make_unique<char[]>(buffsize + 1);
892 Long64_t buffread = 0;
894 while (buffread < f->GetSize()) {
896 if (buffread + buffsize > f->GetSize()) buffsize = f->GetSize() - buffread;
899 f->ReadBuffer(buff.get(), buffread, buffsize);
900 buff[buffsize] =
'\0';
901 content += buff.get();
902 buffread += buffsize;
907 std::string ss =
"mgm.proc.stdout=";
908 size_t pos = ss.size() + 1;
909 content = content.substr(pos);
912 std::stringstream check1(content);
914 std::string intermediate;
917 std::vector<std::string> tokens;
918 while (getline(check1, intermediate,
'&')) {
919 tokens.push_back(intermediate);
921 std::string linesString = tokens[0];
923 files.push_back(
"root://" + host +
"/" + line);
933 std::vector<std::string> out;
935 size_t end = input.find(delim);
937 while (end != std::string_view::npos) {
939 out.emplace_back(input.substr(start, end - start));
942 end = input.find(delim, start);
945 if (start < input.length()) {
946 out.emplace_back(input.substr(start));
956 std::vector<int> out;
957 std::vector<std::string> tokens =
Tokenize(input, delim);
958 for (
auto & t : tokens) {
959 if (t.empty())
continue;
960 out.push_back(std::stoi(t));
966 std::string
NUtils::Join(
const std::vector<std::string> & values,
const char delim)
973 for (
const auto & v : values) {
974 if (!out.empty()) out += delim;
979 std::string
NUtils::Join(
const std::vector<int> & values,
const char delim)
986 for (
const auto & v : values) {
987 if (!out.empty()) out += delim;
988 out += std::to_string(v);
993 std::vector<std::string>
NUtils::Truncate(std::vector<std::string> values, std::string value)
999 std::vector<std::string> out;
1000 for (
auto & v : values) {
1001 v = std::string(v.begin() + value.size(), v.end());
1007 std::set<std::string>
NUtils::Unique(std::vector<std::string> & paths,
int axis, std::string path,
char token)
1013 std::set<std::string> out;
1015 for (
auto & p : truncatedPaths) {
1016 std::vector<std::string> tokens =
Tokenize(p, token);
1017 out.insert(tokens[axis]);
1027 if (sparse ==
nullptr) {
1028 NLogError(
"Error: Sparse is nullptr ...");
1033 if (axes.size() == 1) {
1034 h = sparse->Projection(axes[0], option);
1036 else if (axes.size() == 2) {
1037 h = sparse->Projection(axes[1], axes[0], option);
1039 else if (axes.size() == 3) {
1040 h = sparse->Projection(axes[0], axes[1], axes[2], option);
1043 NLogError(
"Error: Only projection onto single axis is supported for TH1 ...");
1046 h->SetName(TString::Format(
"%s_proj", sparse->GetName()).Data());
1047 h->SetTitle(TString::Format(
"%s Projection", sparse->GetTitle()).Data());
1051 h->SetDirectory(
nullptr);
1054 for (
size_t i = 0; i < axes.size(); i++) {
1055 TAxis * axisSparse = sparse->GetAxis(axes[i]);
1056 TAxis * axisHist = h->GetXaxis();
1057 if (i == 1) axisHist = h->GetYaxis();
1058 if (i == 2) axisHist = h->GetZaxis();
1060 axisHist->SetName(axisSparse->GetName());
1061 axisHist->SetTitle(axisSparse->GetTitle());
1064 if (axisSparse->IsAlphanumeric()) {
1065 for (
int j = 1; j <= axisSparse->GetNbins(); j++) {
1066 const char * label = axisSparse->GetBinLabel(j);
1067 axisHist->SetBinLabel(j, label);
1076 bool modifyTitle,
bool reset)
1083 if (sparse ==
nullptr) {
1084 NLogError(
"Error: Sparse is nullptr ...");
1087 if (sparse->GetNdimensions() == 0)
return true;
1090 NLogTrace(
"Setting axis ranges on '%s' THnSparse ...", sparse->GetName());
1092 for (
int i = 0; i < sparse->GetNdimensions(); i++) {
1094 NLogTrace(
"Resetting '%s' axis ...", sparse->GetAxis(i)->GetName());
1095 sparse->GetAxis(i)->SetRange(0, 0);
1098 NLogTrace(
"Resetting '%s' axis [%d,%d] ...", sparse->GetAxis(i)->GetName(), 1, sparse->GetAxis(i)->GetNbins());
1099 sparse->GetAxis(i)->SetRange(1, sparse->GetAxis(i)->GetNbins());
1104 if (ranges.empty()) {
1105 NLogTrace(
"No axis ranges to set ...");
1109 TAxis * axis =
nullptr;
1110 TString title = sparse->GetTitle();
1111 if (modifyTitle) title +=
" Ranges:";
1112 for (
size_t i = 0; i < ranges.size(); i++) {
1113 axis = sparse->GetAxis(ranges[i][0]);
1114 NLogTrace(
"Setting axis range %s=[%d,%d] ...", axis->GetName(), ranges[i][1], ranges[i][2]);
1115 if (ranges[i].size() != 3) {
1116 NLogError(
"Error: Axis range must have 3 values, but has %zu ...", ranges[i].size());
1119 axis->SetRange(ranges[i][1], ranges[i][2]);
1120 if (axis->IsAlphanumeric()) {
1122 title += TString::Format(
" %s[%s]", axis->GetName(), axis->GetBinLabel(ranges[i][1]));
1125 title += TString::Format(
" %s[%0.2f - %0.2f]", axis->GetName(), axis->GetBinLowEdge(ranges[i][1]),
1126 axis->GetBinUpEdge(ranges[i][2]));
1129 if (modifyTitle) sparse->SetTitle(title.Data());
1134 bool modifyTitle,
bool reset)
1141 if (sparse ==
nullptr) {
1142 NLogError(
"NUtils::SetAxisRanges: Sparse is nullptr ...");
1145 if (sparse->GetNdimensions() == 0)
return true;
1147 NLogTrace(
"NUtils::SetAxisRanges: Setting axis ranges on '%s' THnSparse ...", sparse->GetName());
1150 for (
int i = 0; i < sparse->GetNdimensions(); i++) {
1152 NLogTrace(
"NUtils::SetAxisRanges: Resetting '%s' axis ...", sparse->GetAxis(i)->GetName());
1153 sparse->GetAxis(i)->SetRange(0, 0);
1156 NLogTrace(
"NUtils::SetAxisRanges: Resetting '%s' axis [%d,%d] ...", sparse->GetAxis(i)->GetName(), 1,
1157 sparse->GetAxis(i)->GetNbins());
1158 sparse->GetAxis(i)->SetRange(1, sparse->GetAxis(i)->GetNbins());
1163 if (ranges.empty()) {
1164 NLogTrace(
"NUtils::SetAxisRanges: No axis ranges to set ...");
1167 TAxis * axis =
nullptr;
1168 TString title = sparse->GetTitle();
1169 for (
const auto & [key, val] : ranges) {
1170 NLogTrace(
"NUtils::SetAxisRanges: Setting axis range for axis %d to [%d,%d] ...", key, val[0], val[1]);
1171 axis = sparse->GetAxis(key);
1172 if (axis ==
nullptr) {
1173 NLogError(
"NUtils::SetAxisRanges: Axis %d is nullptr ...", key);
1176 NLogTrace(
"NUtils::SetAxisRanges: Setting axis range %s=[%d,%d] ...", axis->GetName(), val[0], val[1]);
1177 axis->SetRange(val[0], val[1]);
1178 if (axis->IsAlphanumeric()) {
1180 title += TString::Format(
" %s[%s]", axis->GetName(), axis->GetBinLabel(val[0]));
1183 title += TString::Format(
" %s[%0.2f - %0.2f]", axis->GetName(), axis->GetBinLowEdge(val[0]),
1184 axis->GetBinUpEdge(val[1]));
1188 if (modifyTitle) sparse->SetTitle(title.Data());
1189 NLogTrace(
"NUtils::SetAxisRanges: New title: %s", sparse->GetTitle());
1199 NLogError(
"Error: Axis is nullptr ...");
1205 NLogTrace(
"Getting axis range in base for '%s' rebin=%d rebin_start=%d bin=%d...", a->GetName(), rebin, rebin_start,
1208 min = rebin * (bin - 1) + rebin_start;
1209 max = min + rebin - 1;
1210 NLogTrace(
"Axis '%s' min=%d max=%d", a->GetName(), min, max);
1213 NLogError(
"Error: Axis '%s' min=%d is lower then 1 ...", a->GetName(), min);
1219 if (max > a->GetNbins()) {
1220 NLogError(
"Error: Axis '%s' max=%d is higher then %d ...", a->GetName(), max, a->GetNbins());
1234 int rebin = base->GetNbins() / a->GetNbins();
1237 int rebin_start = (base->GetNbins() % a->GetNbins()) + 1;
1238 rebin_start = rebin != 1 ? rebin_start : 1;
1240 NLogTrace(
"Getting axis range in base for '%s' min=%d max=%d rebin=%d rebin_start=%d...", a->GetName(), min, max,
1241 rebin, rebin_start);
1246 NLogTrace(
"Axis '%s' minBase=%d maxBase=%d", a->GetName(), minBase, maxBase);
1252 const std::string & fileName,
const std::vector<std::string> & axesNames)
1254 if (paths.empty()) {
1255 NLogError(
"Error: No paths provided ...");
1259 std::map<std::string, std::set<std::string>> axes;
1260 for (
const auto & path : paths) {
1261 NLogInfo(
"Found file: %s", path.c_str());
1263 TString relativePath = path;
1264 relativePath.ReplaceAll(findPath.c_str(),
"");
1265 relativePath.ReplaceAll(fileName.c_str(),
"");
1268 relativePath.ReplaceAll(
"//",
"/");
1270 relativePath.Remove(0, relativePath.BeginsWith(
"/") ? 1 : 0);
1272 relativePath.Remove(relativePath.EndsWith(
"/") ? relativePath.Length() - 1 : relativePath.Length(), 1);
1280 if (tokens.size() != axesNames.size()) {
1284 for (
size_t i = 0; i < tokens.size(); ++i) {
1285 axes[axesNames[i]].insert(tokens[i]);
1289 TObjArray * axesArr =
new TObjArray();
1290 for (
const auto & axisName : axesNames) {
1303 if (j.is_string()) {
1304 return j.get<std::string>();
1306 else if (j.is_number_integer()) {
1307 return std::to_string(j.get<
int>());
1309 else if (j.is_number_float()) {
1310 return std::to_string(j.get<
double>());
1312 else if (j.is_boolean()) {
1313 return j.get<
bool>() ?
"true" :
"false";
1315 else if (j.is_null()) {
1328 if (j.is_number_integer()) {
1329 return j.get<
int>();
1331 else if (j.is_number_float()) {
1332 return static_cast<int>(j.get<
double>());
1334 else if (j.is_boolean()) {
1335 return j.get<
bool>() ? 1 : 0;
1337 else if (j.is_null()) {
1351 if (j.is_number_float()) {
1352 return j.get<
double>();
1354 else if (j.is_number_integer()) {
1355 return static_cast<double>(j.get<
int>());
1357 else if (j.is_boolean()) {
1358 return j.get<
bool>() ? 1.0 : 0.0;
1360 else if (j.is_null()) {
1374 if (j.is_boolean()) {
1375 return j.get<
bool>();
1377 else if (j.is_number_integer()) {
1378 return j.get<
int>() != 0;
1380 else if (j.is_number_float()) {
1381 return j.get<
double>() != 0.0;
1383 else if (j.is_null()) {
1397 std::vector<std::string> out;
1399 for (
auto & v : j) {
1412 std::vector<int> v2;
1413 for (
int i = 0; i < size; i++) {
1414 v2.push_back(v1[i]);
1425 for (
size_t i = 0; i < v1.size(); i++) {
1434 std::stringstream msg;
1435 if (index >= 0) msg <<
"[" << std::setw(3) << std::setfill(
'0') << index <<
"] ";
1437 for (
size_t i = 0; i < coords.size(); ++i) {
1438 msg << std::setw(width) << std::setfill(
' ') << coords[i] << (i == coords.size() - 1 ?
"" :
",");
1448 std::stringstream msg;
1449 if (index >= 0) msg <<
"[" << std::setw(3) << std::setfill(
'0') << index <<
"] ";
1451 for (
size_t i = 0; i < coords.size(); ++i) {
1452 msg << std::setw(width) << std::setfill(
' ') << coords[i] << (i == coords.size() - 1 ?
"" :
",");
1462 std::stringstream msg;
1463 if (index >= 0) msg <<
"[" << std::setw(3) << std::setfill(
'0') << index <<
"] ";
1465 for (
size_t i = 0; i < coords.size(); ++i) {
1466 msg << std::setw(width) << std::setfill(
' ') << coords[i] << (i == coords.size() - 1 ?
"" :
",");
1476 std::stringstream msg;
1477 if (index >= 0) msg <<
"[" << std::setw(3) << std::setfill(
'0') << index <<
"] ";
1479 for (
size_t i = 0; i < coords.size(); ++i) {
1480 msg << std::setw(width) << std::setfill(
' ') << coords[i] << (i == coords.size() - 1 ?
"" :
",");
1499 std::vector<std::vector<int>> result;
1500 std::vector<int> current = v;
1501 std::sort(current.begin(), current.end());
1503 result.push_back(current);
1504 }
while (std::next_permutation(current.begin(), current.end()));
1508 for (
const auto & perm : result) {
1517 long long hours = seconds / 3600;
1519 long long minutes = seconds / 60;
1522 std::stringstream ss;
1523 ss << std::setw(2) << std::setfill(
'0') << hours <<
":" << std::setw(2) << std::setfill(
'0') << minutes <<
":"
1524 << std::setw(2) << std::setfill(
'0') << seconds;
1534 if (total == 0)
return;
1539 float percentage =
static_cast<float>(current) / total;
1540 int numChars =
static_cast<int>(percentage * barWidth);
1543 if (!prefix.empty()) std::cout <<
"[" << prefix <<
"]";
1546 for (
int i = 0; i < numChars; ++i) {
1549 for (
int i = 0; i < barWidth - numChars; ++i) {
1552 std::cout <<
"] " <<
static_cast<int>(percentage * 100.0) <<
"%"
1553 <<
" (" << current <<
"/" << total <<
")";
1554 if (!suffix.empty()) std::cout <<
" [" << suffix <<
"]";
1555 if (current == total) std::cout << std::endl;
1556 std::cout << std::flush;
1560 std::string prefix, std::string suffix,
int barWidth)
1565 if (total == 0)
return;
1567 if (current > total) current = total;
1569 float percentage =
static_cast<float>(current) / total;
1570 int numChars =
static_cast<int>(percentage * barWidth);
1574 if (!prefix.empty()) std::cout << prefix <<
"][";
1575 for (
int i = 0; i < numChars; ++i) {
1578 for (
int i = 0; i < barWidth - numChars; ++i) {
1581 std::cout <<
"] " << std::setw(3) <<
static_cast<int>(percentage * 100.0) <<
"%";
1584 auto currentTime = std::chrono::high_resolution_clock::now();
1585 auto elapsedSeconds = std::chrono::duration_cast<std::chrono::seconds>(currentTime - startTime).count();
1588 long long estimatedRemainingSeconds = 0;
1589 if (current > 0 && percentage > 0) {
1591 long long totalEstimatedSeconds =
static_cast<long long>(elapsedSeconds / percentage);
1592 estimatedRemainingSeconds = totalEstimatedSeconds - elapsedSeconds;
1595 std::cout <<
" (" << current <<
"/" << total <<
") "
1596 <<
"Elapsed: " <<
FormatTime(elapsedSeconds) <<
" "
1597 <<
"ETA: " <<
FormatTime(estimatedRemainingSeconds);
1598 if (!suffix.empty()) std::cout <<
" [" << suffix <<
"]";
1599 if (current == total) std::cout << std::endl;
1600 std::cout << std::flush;
1610 TCanvas * c =
new TCanvas(
"", title.c_str(), width, height);
1611 gROOT->GetListOfCanvases()->Remove(c);
1612 c->ResetBit(kMustCleanup);
1613 c->SetBit(kCanDelete, kFALSE);
1614 c->SetName(name.c_str());
1627 if (hns ==
nullptr) {
1628 NLogError(
"NUtils::CreateSparseFromParquetTaxi: THnSparse 'hns' is nullptr ...");
1632 std::shared_ptr<arrow::io::ReadableFile> infile;
1633 arrow::Result<std::shared_ptr<arrow::io::ReadableFile>> infile_result = arrow::io::ReadableFile::Open(filename);
1634 if (!infile_result.ok()) {
1635 NLogError(
"NUtils::CreateSparseFromParquetTaxi: Error opening file %s: %s", filename.c_str(),
1636 infile_result.status().ToString().c_str());
1639 infile = infile_result.ValueUnsafe();
1642 std::unique_ptr<parquet::arrow::FileReader> reader;
1645 arrow::Result<std::unique_ptr<parquet::arrow::FileReader>> reader_result =
1646 parquet::arrow::OpenFile(infile, arrow::default_memory_pool());
1647 if (!reader_result.ok()) {
1648 NLogError(
"NUtils::CreateSparseFromParquetTaxi: Error opening Parquet file reader for file %s: %s",
1649 filename.c_str(), reader_result.status().ToString().c_str());
1650 arrow::Status status = infile->Close();
1653 reader = std::move(reader_result).ValueUnsafe();
1657 std::shared_ptr<parquet::FileMetaData> file_metadata = reader->parquet_reader()->metadata();
1658 NLogTrace(
"Parquet file '%s' opened successfully.", filename.c_str());
1659 NLogTrace(
"Parquet file version: %d", file_metadata->version());
1660 NLogTrace(
"Parquet created by: %s", file_metadata->created_by().c_str());
1661 NLogTrace(
"Parquet number of columns: %d", file_metadata->num_columns());
1662 NLogTrace(
"Parquet number of rows: %lld", file_metadata->num_rows());
1663 NLogTrace(
"Parquet number of row groups: %d", file_metadata->num_row_groups());
1668 std::shared_ptr<arrow::RecordBatchReader> batch_reader;
1669 arrow::Status status = reader->GetRecordBatchReader(&batch_reader);
1671 NLogError(
"NUtils::CreateSparseFromParquetTaxi: Error reading table from Parquet file %s: %s", filename.c_str(),
1672 status.ToString().c_str());
1673 status = infile->Close();
1678 status = infile->Close();
1680 NLogWarning(
"NUtils::CreateSparseFromParquetTaxi: Error closing input file %s: %s", filename.c_str(),
1681 status.ToString().c_str());
1686 NLogTrace(
"Parquet Table Schema:\n%s", batch_reader->schema()->ToString().c_str());
1688 const Int_t nDims = hns->GetNdimensions();
1689 std::vector<std::string> column_names;
1690 for (
int i = 0; i < nDims; ++i) {
1691 column_names.push_back(hns->GetAxis(i)->GetName());
1697 max_rows = nMaxRows > 0 ? std::min(max_rows, nMaxRows) : max_rows;
1698 int print_rows = std::min(max_rows, 5);
1700 auto table_batch_reader = batch_reader;
1701 std::shared_ptr<arrow::RecordBatch> batch;
1702 auto point = std::make_unique<Double_t[]>(nDims);
1705 if (print_rows > 0) {
1706 NLogTrace(
"Printing first %d rows of Parquet file '%s' ...", print_rows, filename.c_str());
1710 int batch_count = 0;
1711 while (table_batch_reader->ReadNext(&batch).ok() && batch) {
1713 NLogTrace(
"Processing batch with %d rows and %d columns ...", batch->num_rows(), batch->num_columns());
1714 for (
int i = 0; i < batch->num_rows(); ++i) {
1715 if (i >= max_rows)
break;
1717 bool isValid =
true;
1719 for (
int j = 0; j < batch->num_columns(); ++j) {
1720 if (std::find(column_names.begin(), column_names.end(), batch->column_name(j)) == column_names.end())
1725 const auto & array = batch->column(j);
1726 arrow::Result<std::shared_ptr<arrow::Scalar>> scalar_result = array->GetScalar(i);
1727 if (scalar_result.ok()) {
1729 if (scalar_result.ValueUnsafe()->is_valid) {
1730 TAxis * axis = hns->GetAxis(idx);
1731 if (scalar_result.ValueUnsafe()->type->id() == arrow::Type::STRING ||
1732 scalar_result.ValueUnsafe()->type->id() == arrow::Type::LARGE_STRING) {
1735 std::string value = scalar_result.ValueUnsafe()->ToString();
1739 point[idx] = axis->GetBinCenter(axis->FindBin(value.c_str()));
1741 else if (scalar_result.ValueUnsafe()->type->id() == arrow::Type::INT32) {
1742 auto int_scalar = std::static_pointer_cast<arrow::Int32Scalar>(scalar_result.ValueUnsafe());
1744 point[idx] =
static_cast<Double_t
>(int_scalar->value);
1746 else if (scalar_result.ValueUnsafe()->type->id() == arrow::Type::INT64) {
1747 auto int64_scalar = std::static_pointer_cast<arrow::Int64Scalar>(scalar_result.ValueUnsafe());
1748 point[idx] =
static_cast<Double_t
>(int64_scalar->value);
1750 else if (scalar_result.ValueUnsafe()->type->id() == arrow::Type::UINT32) {
1751 auto uint32_scalar = std::static_pointer_cast<arrow::UInt32Scalar>(scalar_result.ValueUnsafe());
1752 point[idx] =
static_cast<Double_t
>(uint32_scalar->value);
1754 else if (scalar_result.ValueUnsafe()->type->id() == arrow::Type::FLOAT) {
1755 auto float_scalar = std::static_pointer_cast<arrow::FloatScalar>(scalar_result.ValueUnsafe());
1756 point[idx] =
static_cast<Double_t
>(float_scalar->value);
1758 else if (scalar_result.ValueUnsafe()->type->id() == arrow::Type::DOUBLE) {
1759 auto double_scalar = std::static_pointer_cast<arrow::DoubleScalar>(scalar_result.ValueUnsafe());
1760 point[idx] = double_scalar->value;
1763 NLogError(
"NUtils::CreateSparseFromParquetTaxi: Unsupported data type for column '%s' ...",
1764 batch->column_name(j).c_str());
1778 NLogError(
"NUtils::CreateSparseFromParquetTaxi: Error getting scalar at (%d,%d): %s", i, j,
1779 scalar_result.status().ToString().c_str());
1790 hns->Fill(point.get());
1793 NLogWarning(
"Skipping row %d due to invalid data.", i);
1803 NLogError(
"Parquet support is not enabled. Please compile with Parquet support.");
1810 if (objects.empty())
return;
1822 Bool_t prevMustClean = gROOT->MustClean();
1823 gROOT->SetMustClean(kFALSE);
1826 std::vector<TPad *> pads;
1827 for (
auto * obj : objects) {
1828 if (obj && obj->InheritsFrom(TPad::Class()))
1829 pads.push_back(
static_cast<TPad *
>(obj));
1831 for (
size_t i = 0; i < pads.size(); ++i) {
1832 TList * prims = pads[i]->GetListOfPrimitives();
1833 if (!prims || prims->IsEmpty())
continue;
1834 for (TObjLink * lnk = prims->FirstLink(); lnk; lnk = lnk->Next()) {
1835 TObject * child = lnk->GetObject();
1836 if (child && child->InheritsFrom(TPad::Class()))
1837 pads.push_back(
static_cast<TPad *
>(child));
1842 std::set<TObject *> inputSet(objects.begin(), objects.end());
1843 inputSet.erase(
nullptr);
1846 std::set<TObject *> orphans;
1847 for (
auto it = pads.rbegin(); it != pads.rend(); ++it) {
1848 TList * prims = (*it)->GetListOfPrimitives();
1849 if (!prims)
continue;
1851 for (TObjLink * lnk = prims->FirstLink(); lnk; lnk = lnk->Next()) {
1852 TObject * child = lnk->GetObject();
1853 if (child && inputSet.find(child) == inputSet.end())
1854 orphans.insert(child);
1857 prims->UseRWLock(kFALSE);
1858 prims->SetOwner(kFALSE);
1859 prims->Clear(
"nodelete");
1863 for (
auto * obj : objects) {
1864 if (obj)
delete obj;
1869 for (
auto * obj : orphans) {
1873 gROOT->SetMustClean(prevMustClean);
1881 std::vector<TObject *> objects;
1882 for (TObjLink * lnk = lst->FirstLink(); lnk; lnk = lnk->Next()) {
1883 TObject * obj = lnk->GetObject();
1884 if (obj) objects.push_back(obj);
1888 lst->UseRWLock(kFALSE);
1889 lst->SetOwner(kFALSE);
1890 lst->Clear(
"nodelete");
1902 if (obj->InheritsFrom(TList::Class())) {
1903 TList * lst =
static_cast<TList *
>(obj);
1916 gSystem->GetProcInfo(&info);
1918 out[
"cpu_user"] = info.fCpuUser;
1919 out[
"cpu_sys"] = info.fCpuSys;
1920 out[
"cpu_total"] = info.fCpuUser + info.fCpuSys;
1921 out[
"mem_rss_kb"] = info.fMemResident;
1922 out[
"mem_vsize_kb"] = info.fMemVirtual;
1925 unsigned int hc = std::thread::hardware_concurrency();
1926 out[
"cpu_count"] = (hc == 0) ? 1 :
static_cast<int>(hc);
1934 out[
"totalRead"] = 0LL;
1935 out[
"totalWritten"] = 0LL;
1937 TList * files = (TList*)gROOT->GetListOfFiles();
1938 if (!files)
return out;
1940 Long64_t totalRead = 0;
1941 Long64_t totalWritten = 0;
1944 TObject * obj =
nullptr;
1945 while ((obj = next())) {
1946 TFile * f =
dynamic_cast<TFile *
>(obj);
1949 fi[
"name"] = f->GetName() ? f->GetName() :
"";
1950 fi[
"isZombie"] = (bool)f->IsZombie();
1951 fi[
"isOpen"] = (bool)f->IsOpen();
1954 Long64_t bytesRead = 0;
1955 Long64_t bytesWritten = 0;
1963 bytesRead = f->GetBytesRead();
1964 bytesWritten = f->GetBytesWritten();
1972 fi[
"bytesRead"] = bytesRead;
1973 fi[
"bytesWritten"] = bytesWritten;
1975 totalRead += bytesRead;
1976 totalWritten += bytesWritten;
1978 out[
"files"].push_back(fi);
1981 out[
"totalRead"] = totalRead;
1982 out[
"totalWritten"] = totalWritten;
1990 out[
"total_rx"] = 0ULL;
1991 out[
"total_tx"] = 0ULL;
1993 #if defined(__linux__)
1994 std::ifstream f(
"/proc/net/dev");
1995 if (!f.good())
return out;
1998 std::getline(f, line);
1999 std::getline(f, line);
2000 while (std::getline(f, line)) {
2001 if (line.empty())
continue;
2002 size_t colon = line.find(
':');
2003 if (colon == std::string::npos)
continue;
2004 std::string ifname = line.substr(0, colon);
2006 auto ltrim = [](std::string & s) {
2007 size_t start = s.find_first_not_of(
" \t");
2008 if (start != std::string::npos) s = s.substr(start);
2011 auto rtrim = [](std::string & s) {
2012 size_t end = s.find_last_not_of(
" \t");
2013 if (end != std::string::npos) s = s.substr(0, end + 1);
2018 std::string rest = line.substr(colon + 1);
2019 std::stringstream ss(rest);
2020 std::vector<unsigned long long> vals;
2024 vals.push_back(std::stoull(tok));
2027 vals.push_back(0ULL);
2030 if (vals.size() >= 9) {
2031 unsigned long long rx = vals[0];
2032 unsigned long long tx = vals[8];
2034 iface[
"name"] = ifname;
2037 out[
"interfaces"].push_back(iface);
2038 out[
"total_rx"] =
static_cast<unsigned long long>(out[
"total_rx"].is_null() ? 0ULL : out[
"total_rx"].get<
unsigned long long>()) + rx;
2039 out[
"total_tx"] =
static_cast<unsigned long long>(out[
"total_tx"].is_null() ? 0ULL : out[
"total_tx"].get<
unsigned long long>()) + tx;
2043 #elif defined(__APPLE__)
2044 struct ifaddrs *ifap =
nullptr;
2045 if (getifaddrs(&ifap) != 0)
return out;
2046 for (
struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) {
2047 if (!ifa->ifa_data)
continue;
2048 struct if_data *ifd = (
struct if_data *)ifa->ifa_data;
2050 unsigned long long rx = (
unsigned long long)ifd->ifi_ibytes;
2051 unsigned long long tx = (
unsigned long long)ifd->ifi_obytes;
2053 iface[
"name"] = ifa->ifa_name ? ifa->ifa_name : std::string();
2056 out[
"interfaces"].push_back(iface);
2057 out[
"total_rx"] =
static_cast<unsigned long long>(out[
"total_rx"].is_null() ? 0ULL : out[
"total_rx"].get<
unsigned long long>()) + rx;
2058 out[
"total_tx"] =
static_cast<unsigned long long>(out[
"total_tx"].is_null() ? 0ULL : out[
"total_tx"].get<
unsigned long long>()) + tx;
Provides HTTP request functionality using libcurl.
int head(const std::string &url, const std::string &cert_path="", const std::string &key_path="", const std::string &key_password_file="", bool insecure=false)
Performs an HTTP HEAD request.
static std::mutex & GetLoggerMutex()
Get logger mutex reference.
Utility class providing static helper functions for file operations, histogram manipulations,...
static void GetTrueHistogramMinMax(const TH1 *h, double &min_val, double &max_val, bool include_overflow_underflow=false)
Get minimum and maximum value of histogram bins.
static bool SetAxisRanges(THnSparse *sparse, std::vector< std::vector< int >> ranges={}, bool withOverflow=false, bool modifyTitle=false, bool reset=true)
Set axis ranges for THnSparse using vector of ranges.
static TFile * OpenFile(std::string filename, std::string mode="READ", bool createLocalDir=true)
Open a ROOT file.
static int Cp(std::string source, std::string destination)
Copy a file from source to destination.
static std::vector< std::string > Truncate(std::vector< std::string > values, std::string value)
Truncate vector of strings by a value.
static TH1 * ProjectTHnSparse(THnSparse *hns, const std::vector< int > &axes, Option_t *option="")
Project a THnSparse histogram onto specified axes.
static bool IsFileSupported(std::string filename)
Check if a file is supported.
static std::vector< std::string > FindEos(std::string path, std::string filename="")
Find EOS files in a path matching filename.
static bool LoadJsonFile(json &cfg, std::string filename)
Loads a JSON configuration file into the provided json object.
static json GetTFileIOStats()
Get TFile read/write statistics by inspecting ROOT's list of open files.
static bool SaveRawFile(std::string filename, std::string content)
Save content to a raw file.
static std::string OpenRawFile(std::string filename)
Open a raw file and return its content as string.
static std::vector< std::string > FindLocal(std::string path, std::string filename="")
Find local files in a path matching filename.
static void SafeDeleteTList(TList *&lst)
Safely delete a TList and all its contents, bypassing ROOT's GarbageCollect.
static void PrintPointSafe(const std::vector< int > &coords, int index=-1)
Print coordinates safely.
static TCanvas * CreateCanvas(const std::string &name, const std::string &title, int width=800, int height=600)
Create a ROOT TCanvas with specified name, title, and dimensions.
static THnSparse * ReshapeSparseAxes(THnSparse *hns, std::vector< int > order, std::vector< TAxis * > newAxes={}, std::vector< int > newPoint={}, Option_t *option="E")
Reshape axes of THnSparse.
static json GetNetDevStats()
Get system-wide network interface totals (RX/TX bytes) in a cross-platform way. On Linux reads /proc/...
static bool AccessPathName(std::string path)
Check if a path is accessible.
static std::vector< int > TokenizeInt(std::string_view input, const char delim)
Tokenize a string into integers by delimiter.
static THnSparse * Convert(TH1 *h1, std::vector< std::string > names={}, std::vector< std::string > titles={})
Convert TH1 to THnSparse.
static TMacro * OpenMacro(std::string filename)
Open a macro file.
static std::vector< std::string > Tokenize(std::string_view input, const char delim)
Tokenize a string by delimiter.
static std::string FormatTime(long long seconds)
Format time in seconds to human-readable string.
static TAxis * CreateAxisFromLabels(const std::string &name, const std::string &title, const std::vector< std::string > &labels)
Create a TAxis from a list of labels.
static bool GetAxisRangeInBase(TAxis *a, int rebin, int rebin_start, int bin, int &min, int &max)
Get axis range in base for rebinned axis.
static json GetSystemStats()
Get process CPU and RSS memory statistics using ROOT's gSystem::GetProcInfo.
static std::set< std::string > Unique(std::vector< std::string > &paths, int axis, std::string path, char token='/')
Get unique values from vector of strings at specified axis.
static std::vector< std::string > GetJsonStringArray(json j)
Get JSON value as array of strings.
static std::string GetJsonString(json j)
Get JSON value as string.
static bool EnableMT(Int_t numthreads=-1)
Enable multi-threading with specified number of threads.
static int GetJsonInt(json j)
Get JSON value as integer.
static std::string Join(const std::vector< std::string > &values, const char delim=',')
Join vector of strings into a single string with delimiter.
static void ProgressBar(int current, int total, std::string prefix="", std::string suffix="", int barWidth=50)
Display progress bar.
static std::string GetCoordsString(const std::vector< int > &coords, int index=-1, int width=0)
Get string representation of coordinates.
static void SafeDeleteObjects(std::vector< TObject * > &objects)
Safely delete a vector of ROOT objects, bypassing GarbageCollect.
static THnSparse * CreateSparseFromParquetTaxi(const std::string &filename, THnSparse *hns=nullptr, Int_t nMaxRows=-1)
Create THnSparse from Parquet Taxi file.
static void SafeDeleteObject(TObject *&obj)
Safely delete a TObject, handling TList contents and TCanvas/TPad cleanup.
static void VectorToArray(std::vector< int > v1, Int_t *v2)
Convert vector to array.
static std::vector< int > ArrayToVector(Int_t *v1, int size)
Convert array to vector.
static double GetJsonDouble(json j)
Get JSON value as double.
static bool GetJsonBool(json j)
Get JSON value as boolean.
static TObjArray * AxesFromDirectory(const std::vector< std::string > paths, const std::string &findPath, const std::string &fileName, const std::vector< std::string > &axesNames)
Creates an array of axes objects from files in specified directories.
static std::vector< std::string > Find(std::string path, std::string filename="")
Find files in a path matching filename.
static std::vector< std::vector< int > > Permutations(const std::vector< int > &v)
Generate all permutations of a vector.
static TAxis * CreateAxisFromLabelsSet(const std::string &name, const std::string &title, const std::set< std::string > &labels)
Create a TAxis from a set of labels.