7 #include <TDirectory.h>
11 #include <THnSparse.h>
16 #include <TObjString.h>
18 #include <TBufferJSON.h>
20 #include "NParameters.h"
21 #include "NStorageTree.h"
23 #include "NBinningDef.h"
24 #include "NDimensionalExecutor.h"
25 #include "NGnThreadData.h"
27 #include "NTreeBranch.h"
29 #include "NStorageTree.h"
30 #include "NWsClient.h"
31 #include "NGnNavigator.h"
34 #include <nlohmann/json.hpp>
35 using json = nlohmann::json;
45 std::string objPath =
"";
46 if (objCfg.contains(
"prefix") && objCfg[
"prefix"].is_string()) {
47 objPath = objCfg[
"prefix"].get<std::string>();
50 std::string axisObjectDefaultFormat =
51 cfg[
"axisObjectDefaultFormat"].is_string() ? cfg[
"axisObjectDefaultFormat"].get<std::string>() :
"%.2f_%.2f";
52 std::string axisDefaultSeparator = cfg[
"axisDefaultSeparator"].is_string() ? cfg[
"axisDefaultSeparator"].get<std::string>() :
"/";
55 for (
auto & axisEntry : cfg[
"axes"]) {
60 if (axisEntry.is_string()) {
61 axisName = axisEntry.get<std::string>();
62 if (axisObjectDefaultFormat.empty()) {
67 format = axisObjectDefaultFormat;
70 else if (axisEntry.is_object()) {
71 if (axisEntry.contains(
"name") && axisEntry[
"name"].is_string()) {
72 axisName = axisEntry[
"name"].get<std::string>();
77 if (axisEntry.contains(
"mode") && axisEntry[
"mode"].is_string()) {
78 mode = axisEntry[
"mode"].get<std::string>();
80 if (axisEntry.contains(
"format") && axisEntry[
"format"].is_string()) {
81 format = axisEntry[
"format"].get<std::string>();
89 if (axisObjectDefaultFormat.empty())
96 format = axisObjectDefaultFormat.empty() ?
"%.2f_%.2f" : axisObjectDefaultFormat;
97 else if (mode ==
"bin")
103 if (mode ==
"minmax") {
106 objPath += TString::Format(format.c_str(), min, max).Data();
108 else if (mode ==
"min") {
110 objPath += TString::Format(format.c_str(), min).Data();
112 else if (mode ==
"max") {
114 objPath += TString::Format(format.c_str(), max).Data();
116 else if (mode ==
"center") {
118 objPath += TString::Format(format.c_str(), c).Data();
120 else if (mode ==
"label") {
124 else if (mode ==
"bin") {
125 objPath += std::to_string(point->
GetBin(axisName));
128 objPath += std::to_string(point->
GetBin(axisName));
131 std::string sep = axisDefaultSeparator;
132 if (axisEntry.is_object() && axisEntry.contains(
"sufix") && axisEntry[
"sufix"].is_string()) {
133 sep = axisEntry[
"sufix"].get<std::string>();
139 if (!lastSep.empty() && objPath.size() >= lastSep.size()) {
140 objPath = objPath.substr(0, objPath.size() - lastSep.size());
142 if (objCfg.contains(
"sufix") && objCfg[
"sufix"].is_string()) {
143 objPath += objCfg[
"sufix"].get<std::string>();
158 NGnTree::NGnTree(std::vector<TAxis *> axes, std::string filename, std::string treename) : TObject(), fInput(nullptr)
164 NLogError(
"NGnTree::NGnTree: No axes provided, binning is nullptr.");
175 NGnTree::NGnTree(TObjArray * axes, std::string filename, std::string treename) : TObject(), fInput(nullptr)
181 if (axes ==
nullptr) {
182 NLogError(
"NGnTree::NGnTree: Axes TObjArray is nullptr.");
187 if (axes ==
nullptr && axes->GetEntries() == 0) {
188 NLogError(
"NGnTree::NGnTree: No axes provided, binning is nullptr.");
204 if (ngnt ==
nullptr) {
205 NLogError(
"NGnTree::NGnTree: NGnTree is nullptr.");
211 NLogError(
"NGnTree::NGnTree: Binning in NGnTree is nullptr.");
230 NLogError(
"NGnTree::NGnTree: Binning is nullptr.");
239 NLogError(
"NGnTree::NGnTree: Storage tree is nullptr.");
251 NGnTree::NGnTree(THnSparse * hns, std::string parameterAxis,
const std::string & outFileName, json cfg)
252 : TObject(), fInput(nullptr)
258 std::map<std::string, std::vector<std::vector<int>>> b;
259 TObjArray * axes =
new TObjArray();
260 int parameterAxisIdx = -1;
261 std::vector<std::string> labels;
262 for (
int i = 0; i < hns->GetNdimensions(); i++) {
263 TAxis * axisIn = (TAxis *)hns->GetAxis(i);
264 TAxis * axis = (TAxis *)axisIn->Clone();
267 if (parameterAxis.compare(axis->GetName()) == 0) {
268 parameterAxisIdx = i;
269 TAxis * axis = hns->GetAxis(parameterAxisIdx);
270 for (
int bin = 1; bin <= axis->GetNbins(); bin++) {
272 labels.push_back(axis->GetBinLabel(bin));
278 if (axisIn->IsAlphanumeric()) {
279 NLogTrace(
"Setting axis '%s' labels from input THnSparse", axis->GetName());
280 for (
int bin = 1; bin <= axisIn->GetNbins(); bin++) {
281 std::string label = axisIn->GetBinLabel(bin);
282 if (!labels.empty()) axis->SetBinLabel(bin, axisIn->GetBinLabel(bin));
287 b[axis->GetName()] = {{1}};
291 cfg[
"_parameterAxis"] = parameterAxisIdx;
292 cfg[
"_labels"] = labels;
295 NLogDebug(
"Importing THnSparse as NGnTree with parameter axis '%s' (index %d) ...", parameterAxis.c_str(),
298 NLogDebug(
"Created NGnTree for THnSparse import ...");
299 if (ngnt->IsZombie()) {
300 NLogError(
"NGnTree::Import: Failed to create NGnTree !!!");
306 const char * tmpDirStr = gSystem->Getenv(
"NDMSPC_TMP_DIR");
310 if (!tmpDirStr || tmpDir.empty()) {
313 std::string tmpFilename = tmpDir +
"/ngnt_imported_input" + std::to_string(gSystem->GetPid()) +
".root";
315 if (ngntIn->IsZombie()) {
316 NLogError(
"NGnTree::Import: Failed to create NGnTree for input !!!");
322 ngntIn->
GetOutput(
"default")->Add(hns->Clone(
"test"));
333 ngnt->
InitParameters(cfg[
"_labels"].get<std::vector<std::string>>());
335 Ndmspc::NGnProcessFuncPtr processFunc = [](
Ndmspc::NBinningPoint * point, TList * , TList * outputPoint,
338 TH1::AddDirectory(kFALSE);
340 json cfg = point->
GetCfg();
345 NLogError(
"NGnTree::Import: Input NGnTree is nullptr !!!");
350 THnSparse * hns = (THnSparse *)ngntIn->
GetOutput(
"default")->At(0);
351 if (hns ==
nullptr) {
352 NLogError(
"NGnTree::Import: THnSparse 'hns' not found in storage tree !!!");
356 int axisIdx = cfg[
"_parameterAxis"].get<
int>();
357 std::vector<std::vector<int>> ranges;
360 for (
int i = 0; i < hns->GetNdimensions(); i++) {
361 if (i == axisIdx)
continue;
363 ranges.push_back({i, coord, coord});
368 TH1 * h = hns->Projection(axisIdx,
"O");
370 NLogError(
"NGnTree::Import: Projection of THnSparse failed !!!");
373 if (h->GetEntries() > 0) {
376 for (
int bin = 1; bin <= h->GetNbinsX(); bin++) {
377 params->
SetParameter(bin, h->GetBinContent(bin), h->GetBinError(bin));
383 std::string filename = cfg[
"filename"].get<std::string>();
385 if (!f || filename.compare(f->GetName()) != 0) {
387 NLogDebug(
"NGnTree::Import: Closing previously opened file '%s' ...", f->GetName());
390 NLogDebug(
"NGnTree::Import: Opening file '%s' ...", filename.c_str());
391 f = TFile::Open(filename.c_str());
392 if (!f || f->IsZombie()) {
393 NLogError(
"NGnTree::Import: Cannot open file '%s' !!!", filename.c_str());
399 std::string axisObjectDefaultFormat =
400 cfg[
"axisObjectDefaultFormat"].is_string() ? cfg[
"axisObjectDefaultFormat"].get<std::string>() :
"%.2f_%.2f";
401 std::string axisDefaultSeparator =
402 cfg[
"axisDefaultSeparator"].is_string() ? cfg[
"axisDefaultSeparator"].get<std::string>() :
"/";
404 if (cfg.contains(
"dryrun") && cfg[
"dryrun"].is_boolean()) {
405 dryrun = cfg[
"dryrun"].get<
bool>();
409 NLogInfo(
"NGnTree::Import (dryrun): '%s' ...", point->
GetString().c_str());
413 for (
auto & [objName, objCfg] : cfg[
"objects"].items()) {
417 NLogInfo(
"NGnTree::Import (dryrun): would retrieve object '%s'", objPath.c_str());
422 NLogInfo(
"NGnTree::Import: Retrieving object '%s' from file '%s' ...", objPath.c_str(),
423 cfg[
"filename"].get<std::string>().c_str());
425 TObject * obj = f->Get(objPath.c_str());
428 NLogWarning(
"NGnTree::Import: Cannot get object '%s' from file '%s' !!!", objPath.c_str(),
429 cfg[
"filename"].get<std::string>().c_str());
434 if (obj->InheritsFrom(TCanvas::Class())) {
435 TCanvas * cObj = (TCanvas *)obj;
436 cObj->SetName(objName.c_str());
438 outputPoint->Add(obj->Clone(objName.c_str()));
445 ngnt->
Process(processFunc, cfg);
448 gSystem->Exec(TString::Format(
"rm -f %s", tmpFilename.c_str()));
469 TString opt = option;
472 NLogInfo(
"NGnTree::Print: Printing NGnTree object [ALL] ...");
477 NLogError(
"Binning is not initialized in NGnTree !!!");
483 NLogError(
"Storage tree is not initialized in NGnTree !!!");
493 NLogInfo(
"NGnTree::Draw: Drawing NGnTree object [not implemented yet]...");
496 bool NGnTree::Process(NGnProcessFuncPtr func,
const json & cfg, std::string binningName, NGnBeginFuncPtr beginFunc,
497 NGnEndFuncPtr endFunc)
504 NLogError(
"Binning is not initialized in NGnTree !!!");
511 if (!binningName.empty()) {
513 if (std::find(defNames.begin(), defNames.end(), binningName) == defNames.end()) {
514 NLogError(
"Binning definition '%s' not found in NGnTree !!!", binningName.c_str());
518 defNames.push_back(binningName);
523 bool rc =
Process(func, defNames, cfg, binningIn, beginFunc, endFunc);
525 NLogError(
"NGnTree::Process: Processing failed !!!");
532 bool NGnTree::Process(NGnProcessFuncPtr func,
const std::vector<std::string> & defNames,
const json & cfg,
533 NBinning * binningIn, NGnBeginFuncPtr beginFunc, NGnEndFuncPtr endFunc)
539 NLogInfo(
"NGnTree::Process: Starting processing with %zu definitions ...", defNames.size());
540 bool batch = gROOT->IsBatch();
541 gROOT->SetBatch(kTRUE);
542 TH1::AddDirectory(kFALSE);
546 int nThreads = ROOT::GetThreadPoolSize();
547 if (nThreads < 1) nThreads = 1;
548 const char * wsUrl = gSystem->Getenv(
"NDMSPC_WS_URL");
552 NLogInfo(
"NGnTree::Process: Connected to WebSocket server at '%s'", wsUrl);
555 std::vector<Ndmspc::NGnThreadData> threadDataVector(nThreads);
557 const char * tmpDirEnv = gSystem->Getenv(
"NDMSPC_TMP_DIR");
558 std::string tmpDir = tmpDirEnv ? tmpDirEnv :
"/tmp";
561 if (!(tmpDirStr.BeginsWith(
"root://") || tmpDirStr.BeginsWith(
"http://") || tmpDirStr.BeginsWith(
"https://"))) {
562 tmpDir = tmpDirStr.Data();
565 std::string jobDir = tmpDir +
"/.ndmspc/tmp/" + std::to_string(gSystem->GetPid());
566 std::string filePrefix = jobDir;
567 for (
size_t i = 0; i < threadDataVector.size(); ++i) {
569 bool rc = threadDataVector[i].Init(i, func, beginFunc, endFunc,
this, binningIn,
fInput, filename,
572 NLogError(
"Failed to initialize thread data %zu, exiting ...", i);
575 threadDataVector[i].SetCfg(cfg);
577 size_t processedEntries = 0;
578 size_t totalEntries = 0;
579 auto start_par = std::chrono::high_resolution_clock::now();
585 progress[
"jobName"] = thread_obj.GetHnSparseBase()->GetBinning()->GetCurrentDefinitionName();
586 progress[
"status"] =
"R";
587 progress[
"task"] = coords[0];
588 NWsClient * wsClient = thread_obj.GetHnSparseBase()->GetWsClient();
589 if (wsClient) wsClient->
Send(progress.dump());
590 thread_obj.Process(coords);
592 progress[
"status"] =
"D";
593 if (wsClient) wsClient->
Send(progress.dump());
596 size_t nRunning = (totalEntries - processedEntries >= threadDataVector.size()) ? threadDataVector.size()
597 : totalEntries - processedEntries;
598 NUtils::ProgressBar(processedEntries, totalEntries, start_par, TString::Format(
"R%4zu", nRunning).Data());
604 for (
auto & name : defNames) {
607 NLogError(
"NGnTree::Process: Binning definition '%s' not found in NGnTree !!!", name.c_str());
610 std::vector<int> mins, maxs;
612 maxs.push_back(binningDef->GetIds().size() - 1);
613 NLogDebug(
"NGnTree::Process: Processing with binning definition '%s' with %zu entries", name.c_str(),
614 binningDef->GetIds().size());
617 NLogInfo(
"NGnTree::Process: Processing binning definition '%s' with %d tasks ...", name.c_str(), maxs[0] + 1);
620 Printf(
"Processing binning definition '%s' with %d tasks ...", name.c_str(), maxs[0] + 1);
622 totalEntries = maxs[0] + 1;
625 TString::Format(
"R%4d", (
int)threadDataVector.size()).Data());
627 for (
size_t i = 0; i < threadDataVector.size(); ++i) {
628 threadDataVector[i].GetHnSparseBase()->GetBinning()->SetCurrentDefinitionName(name);
631 jobMon[
"jobName"] = name;
634 jobMon[
"pid"] = gSystem->GetPid();
635 jobMon[
"status"] =
"I";
636 jobMon[
"ntasks"] = maxs[0] + 1;
638 NLogInfo(
"NGnTree::Process: Sending job monitor info to WebSocket server ...");
646 Bool_t prevMustClean = gROOT->MustClean();
647 gROOT->SetMustClean(kFALSE);
654 Bool_t prevBatch = gROOT->IsBatch();
655 gROOT->SetBatch(kTRUE);
661 Printf(
"Finished processing binning definition '%s'. Post-processing results ...", name.c_str());
668 gROOT->SetMustClean(prevMustClean);
669 gROOT->SetBatch(prevBatch);
672 for (
size_t i = 0; i < threadDataVector.size(); ++i) {
676 for (
size_t i = 0; i < threadDataVector.size(); ++i) {
677 threadDataVector[i].ExecuteEndFunction();
680 NLogDebug(
"NGnTree::Process: [BEGIN] ------------------------------------------------");
683 for (
size_t i = 0; i < threadDataVector.size(); ++i) {
684 NLogDebug(
"NGnTree::Process: -> Thread %zu processed %lld entries", i, threadDataVector[i].GetNProcessed());
688 threadDataVector[i].GetHnSparseBase()->GetBinning()->GetDefinition(name)->GetIds().begin(),
689 threadDataVector[i].GetHnSparseBase()->GetBinning()->GetDefinition(name)->GetIds().end());
694 for (
size_t i = 0; i < defNames.size(); i++) {
696 std::string other_name = defNames[i];
702 NLogError(
"NGnTree::Process: Binning definition '%s' not found in NGnTree !!!", other_name.c_str());
706 for (
auto it = otherDef->GetIds().begin(); it != otherDef->GetIds().end();) {
707 NLogDebug(
"NGnTree::Process: Checking entry %lld from definition '%s' against sumIds=%d", *it,
708 other_name.c_str(), sumIds);
710 NLogDebug(
"NGnTree::Process: Removing entry %lld from definition '%s'", *it, other_name.c_str());
711 it = otherDef->GetIds().erase(it);
723 NLogDebug(
"NGnTree::Process: [END] ------------------------------------------------");
724 auto end_par = std::chrono::high_resolution_clock::now();
725 std::chrono::duration<double, std::milli> par_duration = end_par - start_par;
727 NLogInfo(
"NGnTree::Process: Execution completed and it took %s .",
730 NLogInfo(
"NGnTree::Process: Post processing %zu results ...", threadDataVector.size());
731 for (
auto & data : threadDataVector) {
732 NLogTrace(
"NGnTree::Process: Closing file from thread %zu: ", data.GetAssignedIndex());
733 data.GetHnSparseBase()->GetStorageTree()->Close(
true);
736 NLogDebug(
"NGnTree::Process: Merging %zu results ...", threadDataVector.size());
737 TList * mergeList =
new TList();
739 outputData->
Init(0, func,
nullptr,
nullptr,
this, binningIn);
743 for (
auto & data : threadDataVector) {
744 NLogTrace(
"NGnTree::Process: Adding thread data %zu to merge list ...", data.GetAssignedIndex());
746 mergeList->Add(&data);
749 Long64_t nmerged = outputData->
Merge(mergeList);
751 NLogError(
"NGnTree::Process: Failed to merge thread data, exiting ...");
755 NLogInfo(
"NGnTree::Process: Merged %lld outputs successfully", nmerged);
770 NLogInfo(
"NGnTree::Process: Processing completed successfully. Output was stored in '%s'.",
777 jobMon[
"status"] =
"D";
792 gSystem->Exec(TString::Format(
"rm -fr %s", jobDir.c_str()));
793 gROOT->SetBatch(batch);
807 fOutputs[name]->SetName(name.c_str());
812 NGnTree *
NGnTree::Open(
const std::string & filename,
const std::string & branches,
const std::string & treename)
818 NLogDebug(
"Opening '%s' with branches='%s' and treename='%s' ...", filename.c_str(), branches.c_str(),
821 TFile * file = TFile::Open(filename.c_str());
823 NLogError(
"NGnTree::Open: Cannot open file '%s'", filename.c_str());
827 TTree * tree = (TTree *)file->Get(treename.c_str());
829 NLogError(
"NGnTree::Open: Cannot get tree '%s' from file '%s'", treename.c_str(), filename.c_str());
833 return Open(tree, branches, file);
844 NLogError(
"NGnTree::Open: Cannot get binning from tree '%s'", tree->GetName());
848 if (!hnstStorageTree) {
849 NLogError(
"NGnTree::Open: Cannot get tree storage info from tree '%s'", tree->GetName());
853 std::map<std::string, TList *> outputs;
854 TDirectory * dir =
nullptr;
856 dir = (TDirectory *)file->Get(
"outputs");
857 auto l = dir->GetListOfKeys();
859 TObject * obj = dir->Get(kv->GetName());
861 TList * l =
dynamic_cast<TList *
>(obj);
863 outputs[l->GetName()] = l;
864 NLogDebug(
"Imported output list for binning '%s' with %d object(s) from file '%s'", l->GetName(), l->GetEntries(),
875 if (!hnstStorageTree->
SetFileTree(file, tree))
return nullptr;
879 std::vector<std::string> enabledBranches;
880 if (!branches.empty()) {
888 NLogTrace(
"NGnTree::Open: Enabled branches: %s", kv.first.c_str());
909 NLogTrace(
"NGnTree::SetNavigator: Replacing existing navigator ...");
923 NLogError(
"NGnTree::Close: Storage tree is not initialized in NGnTree !!!");
936 NLogError(
"NGnTree::GetEntry: Storage tree is not initialized in NGnTree !!!");
951 return GetEntry(0, checkBinningDef);
954 void NGnTree::Play(
int timeout, std::string binning, std::vector<int> outputPointIds,
955 std::vector<std::vector<int>> ranges, Option_t * option, std::string ws)
960 TString opt = option;
963 std::string annimationTempDir =
964 TString::Format(
"%s/.ndmspc/animation/%d", gSystem->Getenv(
"HOME"), gSystem->GetPid()).Data();
965 gSystem->Exec(TString::Format(
"mkdir -p %s", annimationTempDir.c_str()));
972 NLogError(
"Failed to connect to '%s' !!!", ws.c_str());
975 NLogInfo(
"Connected to %s", ws.c_str());
978 if (binning.empty()) {
984 NLogError(
"NGnTree::Play: Binning definition '%s' not found in NGnTree !!!", binning.c_str());
985 NLogError(
"Available binning definitions:");
988 NLogError(
" [*] %s", name.c_str());
990 NLogError(
" [ ] %s", name.c_str());
995 THnSparse * bdContent = (THnSparse *)binningDef->
GetContent()->Clone();
997 std::string bdContentName = TString::Format(
"bdContent_%s", binning.c_str()).Data();
1001 Long64_t linBin = 0;
1002 std::unique_ptr<ROOT::Internal::THnBaseBinIter> iter{bdContent->CreateIter(
true )};
1003 std::vector<Long64_t> ids;
1005 while ((linBin = iter->Next()) >= 0) {
1007 ids.push_back(linBin);
1010 NLogWarning(
"NGnTree::Play: No entries found in binning definition '%s' !!!", binning.c_str());
1015 TCanvas * c1 =
nullptr;
1017 c1 = (TCanvas *)gROOT->GetListOfCanvases()->FindObject(
"c1");
1018 if (c1 ==
nullptr) c1 =
new TCanvas(
"c1",
"NGnTree::Play", 800, 600);
1021 c1->DivideSquare(outputPointIds.size() > 0 ? outputPointIds.size() + 1 : 1);
1022 gSystem->ProcessEvents();
1024 binningDef->
Print();
1028 for (
auto id : ids) {
1033 if (!l || l->IsEmpty()) {
1034 NLogWarning(
"NGnTree::Play: No 'outputPoint' for entry %lld !!!",
id);
1041 if (outputPointIds.empty()) {
1042 outputPointIds.resize(l->GetEntries());
1043 for (
int i = 0; i < l->GetEntries(); i++) {
1044 outputPointIds[i] = i;
1047 int n = outputPointIds.size();
1050 std::string msg = TBufferJSON::ConvertToJSON(l).Data();
1051 if (!client->
Send(msg)) {
1052 NLogError(
"Failed to send message `%s`", msg.c_str());
1055 NLogTrace(
"Sent: %s", msg.c_str());
1061 for (
int i = 0; i < n; i++) {
1065 TObject * obj = l->At(outputPointIds[i]);
1067 if (obj->InheritsFrom(TH1::Class())) {
1068 TH1 * h = (TH1 *)obj;
1069 h->SetDirectory(
nullptr);
1073 TH1 * hclone = (TH1 *)h->Clone();
1075 hclone->SetDirectory(
nullptr);
1081 if (obj->InheritsFrom(TH1::Class()) && i == 0) {
1082 TH1 * h = (TH1 *)obj;
1084 NLogDebug(
"Mean value from histogram [%s]: %f", h->GetName(), v);
1089 TH1 * bdProj = (TH1 *)gROOT->FindObjectAny(
"bdProj");
1094 if (bdContent->GetNdimensions() == 1) {
1095 bdProj = bdContent->Projection(0,
"O");
1097 else if (bdContent->GetNdimensions() == 2) {
1098 bdProj = bdContent->Projection(0, 1,
"O");
1100 else if (bdContent->GetNdimensions() == 3) {
1101 bdProj = bdContent->Projection(0, 1, 2,
"O");
1104 NLogError(
"NGnTree::Play: Cannot project THnSparse with %d dimensions", bdContent->GetNdimensions());
1107 bdProj->SetName(
"bdProj");
1108 bdProj->SetTitle(TString::Format(
"Binning '%s' content projection", binning.c_str()).Data());
1109 bdProj->SetMinimum(0);
1111 bdProj->Draw(
"colz");
1117 c1->ModifiedUpdate();
1118 c1->SaveAs(TString::Format(
"%s/ndmspc_play_%06lld.png", annimationTempDir.c_str(), bdContent->GetNbins()).Data());
1120 gSystem->ProcessEvents();
1121 if (timeout > 0) gSystem->Sleep(timeout);
1125 NLogInfo(
"Creating animation gif from %s/ndmspc_play_*.png ...", annimationTempDir.c_str());
1127 TString::Format(
"magick -delay 20 -loop 0 %s/ndmspc_play_*.png ndmspc_play.gif", annimationTempDir.c_str()));
1128 gSystem->Exec(TString::Format(
"rm -fr %s", annimationTempDir.c_str()));
1129 NLogInfo(
"Animation saved to ndmspc_play.gif");
1146 TH1::AddDirectory(kFALSE);
1148 json cfg = point->
GetCfg();
1150 Printf(
"Processing THnSparse projection with configuration: %s", cfg.dump().c_str());
1158 for (
auto & [objName, objCfg] : cfg[
"objects"].items()) {
1159 NLogInfo(
"Processing object '%s' ...", objName.c_str());
1162 if (hns ==
nullptr) {
1163 NLogError(
"NGnTree::Projection: THnSparse 'hns' not found in storage tree !!!");
1168 for (
size_t i = 0; i < objCfg.size(); i++) {
1170 NLogInfo(
"Processing projection %zu for object '%s' ...", i, objName.c_str());
1171 std::vector<int> dims;
1172 std::vector<std::string> dimNames = cfg[
"objects"][objName][i].get<std::vector<std::string>>();
1173 for (
const auto & dimName : dimNames) {
1174 NLogDebug(
"Looking for dimension name '%s' in THnSparse ...", dimName.c_str());
1176 for (
int i = 0; i < hns->GetNdimensions(); i++) {
1177 if (dimName == hns->GetAxis(i)->GetName()) {
1183 dims.push_back(dim);
1185 NLogError(
"NGnTree::Projection: Dimension name '%s' not found in THnSparse !!!", dimName.c_str());
1190 TH1 * hPrev = (TH1 *)output->At(i);
1192 hProj->SetName(TString::Format(
"%s_proj_%s", objName.c_str(),
NUtils::Join(dims,
'_').c_str()).Data());
1206 THnSparse * hnsIn = binningDef->
GetContent();
1208 std::vector<std::vector<int>> ranges = cfg[
"ranges"].get<std::vector<std::vector<int>>>();
1210 Long64_t linBin = 0;
1211 std::unique_ptr<ROOT::Internal::THnBaseBinIter> iter{hnsIn->CreateIter(
true )};
1212 std::vector<Long64_t> ids;
1214 while ((linBin = iter->Next()) >= 0) {
1215 ids.push_back(linBin);
1218 NLogWarning(
"NGnTree::Projection: No entries found in binning definition '%s' !!!", binningDef->GetName());
1223 binningDef->
GetIds() = ids;
1238 std::map<
int, std::vector<int>> ranges, std::map<
int, std::vector<int>> rangesBase)
1247 return navigator.
Reshape(binningName, levels, level, ranges, rangesBase);
1251 int level, std::map<
int, std::vector<int>> ranges,
1252 std::map<
int, std::vector<int>> rangesBase)
1258 if (binningName.empty()) {
1262 THnSparse * hns = (THnSparse *)
fOutputs[binningName]->FindObject(
"resource_monitor");
1264 NLogError(
"NGnTree::Draw: Resource monitor THnSparse not found in outputs !!!");
1270 auto ngnt =
new NGnTree(hns,
"stat",
"/tmp/hnst_imported_for_drawing.root");
1271 if (ngnt->IsZombie()) {
1272 NLogError(
"NGnTree::GetResourceStatisticsNavigator: Failed to import resource monitor THnSparse !!!");
1279 auto ngnt2 =
NGnTree::Open(
"/tmp/hnst_imported_for_drawing.root");
1280 auto nav = ngnt2->Reshape(
"default", levels, level, ranges, rangesBase);
1293 NLogTrace(
"NGnTree::InitParameters: Replacing existing parameters ...");
1297 if (paramNames.empty()) {
1298 NLogTrace(
"NGnTree::InitParameters: No parameter names provided, skipping ...");
1308 const std::vector<std::string> & headers,
const std::string & outputFile,
bool close)
1315 std::string findPathClean = findPath;
1316 if (!findPathClean.empty() && findPathClean.back() ==
'/') {
1317 findPathClean.pop_back();
1320 std::vector<std::string> paths =
NUtils::Find(findPathClean, fileName);
1321 NLogInfo(
"NGnTree::Import: Found %zu files to import ...", paths.size());
1324 int nDirAxes = ngntArray->GetEntries();
1329 ngntArray->Add(axis->Clone());
1331 ngntFirst->
Close(
false);
1333 std::map<std::string, std::vector<std::vector<int>>> b;
1335 for (
int i = 0; i < ngntArray->GetEntries(); i++) {
1336 TAxis * axis = (TAxis *)ngntArray->At(i);
1337 b[axis->GetName()].push_back({1});
1347 cfg[
"basedir"] = findPathClean;
1348 cfg[
"filename"] = fileName;
1349 cfg[
"nDirAxes"] = nDirAxes;
1350 cfg[
"headers"] = headers;
1352 Ndmspc::NGnProcessFuncPtr processFunc = [](
Ndmspc::NBinningPoint * point, TList * , TList * outputPoint,
1356 json cfg = point->
GetCfg();
1357 std::string filename = cfg[
"basedir"].get<std::string>();
1359 for (
auto & header : cfg[
"headers"]) {
1360 filename += point->
GetBinLabel(header.get<std::string>());
1367 filename += cfg[
"filename"].get<std::string>();
1369 if (!ngnt || filename.compare(ngnt->GetStorageTree()->GetFileName()) != 0) {
1370 NLogInfo(
"NGnTree::Import: Opening file '%s' ...", filename.c_str());
1372 NLogDebug(
"NGnTree::Import: Closing previously opened file '%s' ...",
1373 ngnt->GetStorageTree()->GetFileName().c_str());
1379 if (!ngnt || ngnt->IsZombie()) {
1380 NLogError(
"NGnTree::Import: Cannot open file '%s'", filename.c_str());
1386 int nDirAxes = cfg[
"nDirAxes"].get<
int>();
1389 NLogInfo(
"NGnTree::Import: Processing point with coords %s ...", coordsStr.c_str());
1391 Long64_t entryNumber =
1392 ngnt->GetBinning()->GetContent()->GetBin(&coords[3 * nDirAxes], kFALSE);
1393 NLogInfo(
"NGnTree::Import: Corresponding entry number in file '%s' is %lld", filename.c_str(), entryNumber);
1395 ngnt->GetEntry(entryNumber);
1404 for (
const auto & kv : ngnt->GetStorageTree()->GetBranchesMap()) {
1407 NLogTrace(
"NGnTree::Import: Adding branch '%s' to storage tree ...", kv.first.c_str());
1410 NLogTrace(
"NGnTree::Import: Setting branch address for branch '%s' ...", kv.first.c_str());
1413 outputPoint->Add(
new TNamed(
"source_file", filename));
1429 TH1::AddDirectory(kFALSE);
1442 ngnt->
Process(processFunc, cfg,
"", beginFunc, endFunc);
Defines binning mapping and content for NDMSPC histograms.
THnSparse * GetContent() const
Get the template content histogram.
virtual void Print(Option_t *option="") const
Print binning definition information.
void RefreshIdsFromContent()
Refresh bin IDs from content histogram.
std::vector< Long64_t > GetIds() const
Get list of bin IDs.
Represents a single point in multi-dimensional binning.
Double_t GetBinMax(std::string axis) const
Get the maximum value for a specific axis.
std::string GetString(const std::string &prefix="", bool all=false) const
Returns a string representation of the binning point.
void SetTreeStorage(NStorageTree *s)
Set storage tree object pointer.
std::string GetBinLabel(std::string axis) const
Get the label for a specific axis.
Long64_t GetEntryNumber() const
Get entry number for the point.
NParameters * GetParameters() const
Get the parameters associated with this binning point.
Int_t * GetStorageCoords() const
Get pointer to storage coordinates array.
Double_t GetBinCenter(std::string axis) const
Returns the center value of the bin along the specified axis.
NStorageTree * GetTreeStorage() const
Get pointer to storage tree object.
void SetTempObject(const std::string &name, TObject *obj)
Set a temporary object with the given name.
NStorageTree * GetStorageTree() const
Returns a pointer to the associated storage tree.
virtual void Print(Option_t *option="") const
Print binning point information.
TObject * GetTempObject(const std::string &name) const
Retrieve a temporary object by name.
NGnTree * GetInput() const
Get pointer to input NGnTree object.
Int_t GetBin(std::string axis) const
Returns the bin index for the specified axis.
Int_t * GetCoords() const
Get pointer to content coordinates array.
json & GetCfg()
Get reference to configuration JSON object.
Int_t GetNDimensionsContent() const
Get number of dimensions in content histogram.
Double_t GetBinMin(std::string axis) const
Get the minimum value for a specific axis.
NBinning object for managing multi-dimensional binning and axis definitions.
NBinningDef * GetDefinition(const std::string &name="")
Get binning definition by name.
std::vector< std::string > GetDefinitionNames() const
Get all definition names.
std::string GetCurrentDefinitionName() const
Get current definition name.
NBinningPoint * GetPoint()
Get the current binning point.
virtual void Print(Option_t *option="") const
Print binning information.
std::vector< TAxis * > GetAxes() const
Get vector of axis pointers.
bool SetCfg(const json &cfg)
Set configuration from JSON.
void AddBinningDefinition(std::string name, std::map< std::string, std::vector< std::vector< int >>> binning, bool forceDefault=false)
Add a binning definition.
void Reset()
Reset the binning object to initial state.
Executes a function over all points in an N-dimensional space, optionally in parallel.
void ExecuteParallel(const std::function< void(const std::vector< int > &coords, TObject &thread_object)> &func, std::vector< TObject > &thread_objects)
Execute a function in parallel over all coordinates, using thread-local objects.
Navigator object for managing hierarchical data structures and projections.
NGnNavigator * Reshape(std::string binningName, std::vector< std::vector< int >> levels, size_t level=0, std::map< int, std::vector< int >> ranges={}, std::map< int, std::vector< int >> rangesBase={})
Reshape navigator using binning name and levels.
void SetGnTree(NGnTree *tree)
Set NGnTree object pointer.
Thread-local data object for NDMSPC processing.
bool Init(size_t id, NGnProcessFuncPtr func, NGnBeginFuncPtr beginFunc, NGnEndFuncPtr endFunc, NGnTree *ngnt, NBinning *binningIn, NGnTree *input=nullptr, const std::string &filename="", const std::string &treename="ngnt")
Initialize thread data for processing.
NGnTree * GetHnSparseBase() const
Get pointer to base NGnTree object.
virtual Long64_t Merge(TCollection *list)
Merge thread data from a collection (virtual).
void FlushDeferredDeletes()
Delete deferred ROOT objects, skipping TCanvas/TPad (leaked safely).
void SetCfg(const json &cfg)
Set configuration JSON object.
NDMSPC tree object for managing multi-dimensional data storage and processing.
NBinning * GetBinning() const
Get pointer to binning object.
std::map< std::string, TList * > GetOutputs() const
Get outputs map.
virtual void Draw(Option_t *option="") override
Draws the tree object.
void SetIsPureCopy(bool val)
Sets the pure copy status of the tree.
bool Close(bool write=false)
Close the tree, optionally writing data.
virtual ~NGnTree()
Destructor.
Int_t GetEntry(Long64_t entry, bool checkBinningDef=true)
Get entry by index.
virtual void Print(Option_t *option="") const override
Print tree information.
void SetInput(NGnTree *input)
Set input NGnTree pointer.
NGnTree()
Default constructor.
static NGnTree * Import(const std::string &findPath, const std::string &fileName, const std::vector< std::string > &headers, const std::string &outFileName="/tmp/ngnt_imported.root", bool close=true)
Imports an NGnTree from a specified file.
NGnNavigator * Reshape(std::string binningName, std::vector< std::vector< int >> levels, int level=0, std::map< int, std::vector< int >> ranges={}, std::map< int, std::vector< int >> rangesBase={})
Reshape navigator using binning name and levels.
NBinning * fBinning
Binning object.
NWsClient * fWsClient
! WebSocket client for communication
TList * GetOutput(std::string name="")
Get output list by name.
NParameters * GetParameters() const
Returns the parameters associated with this tree.
NGnTree * fInput
Input NGnTree for processing.
NStorageTree * GetStorageTree() const
Get pointer to storage tree object.
NGnTree * GetInput() const
Get pointer to input NGnTree.
void SetOutputs(std::map< std::string, TList * > outputs)
Set outputs map.
bool InitParameters(const std::vector< std::string > ¶mNames)
Initializes the parameters for the tree using the provided parameter names.
std::map< std::string, TList * > fOutputs
Outputs.
NGnNavigator * fNavigator
! Navigator object
NParameters * fParameters
Parameters object.
TList * Projection(const json &cfg, std::string binningName="")
Project tree data using configuration and binning name.
NGnNavigator * GetResourceStatisticsNavigator(std::string binningName, std::vector< std::vector< int >> levels, int level=0, std::map< int, std::vector< int >> ranges={}, std::map< int, std::vector< int >> rangesBase={})
Returns a navigator for resource statistics based on binning and levels.
NStorageTree * fTreeStorage
Tree storage.
static std::string BuildObjectPath(const json &cfg, const json &objCfg, const NBinningPoint *point)
Helper: build object path string from configuration and a binning point.
void SetNavigator(NGnNavigator *navigator)
Sets the navigator for this tree.
static NGnTree * Open(const std::string &filename, const std::string &branches="", const std::string &treename="ngnt")
Open NGnTree from file.
bool Process(NGnProcessFuncPtr func, const json &cfg=json::object(), std::string binningName="", NGnBeginFuncPtr beginFunc=nullptr, NGnEndFuncPtr endFunc=nullptr)
Process tree data using a function pointer and configuration.
void Play(int timeout=0, std::string binning="", std::vector< int > outputPointIds={0}, std::vector< std::vector< int >> ranges={}, Option_t *option="", std::string ws="")
Play tree data with optional binning and output point IDs.
static bool GetConsoleOutput()
Get console output flag.
bool SetParameter(int bin, Double_t value, Double_t error=0.)
Set the value and error of a parameter by bin index.
NDMSPC storage tree object for managing ROOT TTree-based data storage.
void SetBranchAddresses()
Set addresses for all branches.
void SetEnabledBranches(std::vector< std::string > branches, int status=1)
Set enabled/disabled status for branches.
bool SetFileTree(TFile *file, TTree *tree)
Tree handling.
std::string GetFileName() const
Get file name.
bool AddBranch(const std::string &name, void *address, const std::string &className)
Add a branch to the tree.
Long64_t GetEntry(Long64_t entry, NBinningPoint *point=nullptr, bool checkBinningDef=false)
Get entry by index and fill NBinningPoint.
std::string GetPrefix() const
Get prefix path.
TObject * GetBranchObject(const std::string &name)
Get pointer to branch object by name.
NTreeBranch * GetBranch(const std::string &name)
Get pointer to NTreeBranch by name.
bool InitTree(const std::string &filename="", const std::string &treename="ngnt")
Initialize tree from file and tree name.
std::string GetPostfix() const
Get postfix path.
bool Close(bool write=false, std::map< std::string, TList * > outputs={})
Close the storage tree, optionally writing outputs.
TTree * GetTree() const
Get pointer to TTree object.
virtual void Print(Option_t *option="") const
Print storage tree information.
void SetBinning(NBinning *binning)
Set binning object pointer.
std::map< std::string, NTreeBranch > GetBranchesMap() const
Get map of branch names to NTreeBranch objects.
void SetAddress(void *address, bool deleteExisting=false)
Set address for branch data.
TObject * GetObject() const
Get object pointer.
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 TH1 * ProjectTHnSparse(THnSparse *hns, const std::vector< int > &axes, Option_t *option="")
Project a THnSparse histogram onto specified axes.
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 bool EnableMT(Int_t numthreads=-1)
Enable multi-threading with specified number of threads.
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 std::vector< int > ArrayToVector(Int_t *v1, int size)
Convert array to vector.
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.
WebSocket client for asynchronous communication using libwebsockets.
bool Connect(const std::string &uriString)
Connect to a WebSocket server.
void Disconnect()
Disconnect from the WebSocket server.
bool Send(const std::string &message)
Send a message to the server.