Skip to content

Commit e699b8e

Browse files
author
miranov25
committed
Moving treeFastCache.C and treeFastCacheND.C from TPC gitlab to the O2DPG
1 parent 425be10 commit e699b8e

File tree

3 files changed

+410
-0
lines changed

3 files changed

+410
-0
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
Here's a combined `README.md` that covers both `treeFastCache1D.C` and `treeFastCacheND.C`. It provides an overview of both systems, explains their purpose and usage, and includes examples for each.
2+
3+
---
4+
5+
# 📦 ROOT Tree Fast Cache System
6+
7+
This repository contains ROOT macros for fast lookup and interpolation of values from TTrees, using:
8+
9+
- `treeFastCache1D.C`: 1D cache with nearest-neighbor lookup
10+
- `treeFastCacheND.C`: ND cache with exact match in N–1 dimensions and nearest-neighbor in 1 dimension
11+
12+
They are designed for interactive analysis with `TTree::Draw`, e.g., QA plots, calibration overlays, or smoothed time series.
13+
14+
---
15+
16+
## 🔹 `treeFastCache1D.C`
17+
18+
### ✅ Features
19+
20+
- Register 1D lookup maps from TTrees
21+
- Nearest-neighbor lookup from `std::map<double, float>`
22+
- Can register by ID or string name
23+
- Fast evaluation inside `TTree::Draw`
24+
- Alias integration for interactive sessions
25+
26+
### 🧪 Example
27+
28+
```cpp
29+
TTree* tree = ...;
30+
int mapID = registerMap1DByName("dcar_vs_time", "time", "dcar_value", tree, "subentry==127");
31+
32+
tree->SetAlias("dcar_smooth", ("getNearest1D(time," + std::to_string(mapID) + ")").c_str());
33+
tree->Draw("dcar_value:dcar_smooth", "indexType==1", "colz", 10000);
34+
```
35+
36+
---
37+
38+
## 🔷 `treeFastCacheND.C`
39+
40+
### ✅ Features
41+
42+
- ND caching with:
43+
- **Exact match** in N–1 dimensions
44+
- **Nearest-neighbor** lookup in 1 dimension (e.g. `time`)
45+
- Uses full `double` precision for all keys
46+
- Alias support for `TTree::Draw`
47+
- Registration by name with hashed map ID
48+
- Easy to integrate, extendable to class-based interface
49+
50+
### 🧪 Example: Time Series
51+
52+
```cpp
53+
TTree* tree = ...;
54+
int mapID = registerMapND("dcar_vs_time", tree, {"subentry"}, "time", "mTSITSTPC.mDCAr_A_NTracks_median", "1");
55+
setNearestNDAlias(tree, "dcar_smooth", "dcar_vs_time", "time", {"subentry"});
56+
57+
tree->Draw("mTSITSTPC.mDCAr_A_NTracks_median:dcar_smooth", "indexType==1", "colz", 10000);
58+
```
59+
60+
---
61+
62+
## 🧱 Internal Storage
63+
64+
### 1D:
65+
```cpp
66+
std::map<int, std::map<double, float>> registeredMaps;
67+
std::map<std::string, int> nameToMapID;
68+
```
69+
70+
### ND:
71+
```cpp
72+
std::map<int, std::map<std::vector<double>, std::map<double, double>>> ndCaches;
73+
std::map<std::string, int> ndNameToID;
74+
```
75+
76+
---
77+
78+
## 📌 Best Practices
79+
80+
- Use aliases to simplify and standardize plotting
81+
- Pre-register frequently used maps in init scripts
82+
- Use full double precision for input axes to ensure match stability
83+
- Prefer descriptive names for map registration
84+
85+
---
86+
87+
## 📤 Future Ideas
88+
89+
- Optional linear interpolation (vs. nearest)
90+
- Fallback behavior when no exact match is found
91+
- Statistics and diagnostics on caches
92+
- Class-based C++ wrapper with lifecycle management
93+
94+
---
95+
96+
## 📄 License
97+
98+
Intended for use in internal physics analyses. No warranty implied.
99+
100+
---
101+
102+
Let me know if you'd like me to create a markdown file or commit it alongside the `.C` macros.

UTILS/Parsers/treeFastCache.C

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/*
2+
.L $O2DPG/UTILS/Parsers/treeFastCache.C
3+
*/
4+
5+
/*
6+
treeFastCache.C
7+
Simple caching system for fast lookup of 1D values from a TTree, using nearest-neighbor interpolation.
8+
This utility allows registration of (X, Y) pairs from a TTree into a std::map,
9+
indexed by a user-defined mapID or map name. The lookup function `getNearest1D(x, mapID)`
10+
retrieves the Y value for the X closest to the query.
11+
Features:
12+
- Register maps via string name or numeric ID
13+
- Query nearest-neighbor value for any X
14+
- Graceful error handling and range checking
15+
- Base for future ND extension
16+
*/
17+
18+
#include <TTree.h>
19+
#include <TTreeFormula.h>
20+
#include <map>
21+
#include <string>
22+
#include <cmath>
23+
#include <iostream>
24+
#include <functional>
25+
26+
using namespace std;
27+
28+
// Map: mapID -> map<X, Y>
29+
std::map<int, std::map<double, float>> registeredMaps;
30+
std::map<std::string, int> nameToMapID;
31+
32+
/// Hash a string to create a deterministic mapID
33+
int hashMapName(const std::string& name) {
34+
std::hash<std::string> hasher;
35+
return static_cast<int>(hasher(name));
36+
}
37+
38+
/// Register a 1D lookup map from TTree (X -> Y)
39+
/// @param valX Name of the X-axis variable (lookup key)
40+
/// @param valY Name of the Y-axis variable (value to retrieve)
41+
/// @param tree Pointer to TTree to extract data from
42+
/// @param selection Selection string (TTree::Draw-compatible)
43+
/// @param mapID Integer ID to associate with this map
44+
void registerMap1D(const std::string& valX, const std::string& valY, TTree* tree, const std::string& selection, int mapID) {
45+
if (!tree) {
46+
std::cerr << "[registerMap1D] Null TTree pointer." << std::endl;
47+
return;
48+
}
49+
50+
int entries = tree->Draw((valY + ":" + valX).c_str(), selection.c_str(), "goff");
51+
if (entries <= 0) {
52+
std::cerr << "[registerMap1D] No entries matched for mapID=" << mapID << std::endl;
53+
return;
54+
}
55+
56+
if (!tree->GetV1() || !tree->GetV2()) {
57+
std::cerr << "[registerMap1D] Internal Draw buffer pointers are null." << std::endl;
58+
return;
59+
}
60+
61+
std::map<double, float> newMap;
62+
for (int i = 0; i < entries; ++i) {
63+
if (i >= tree->GetSelectedRows()) {
64+
std::cerr << "[registerMap1D] Index out of range at i=" << i << std::endl;
65+
break;
66+
}
67+
double x = tree->GetV2()[i]; // valX
68+
float y = tree->GetV1()[i]; // valY
69+
newMap[x] = y;
70+
}
71+
72+
registeredMaps[mapID] = std::move(newMap);
73+
std::cout << "[registerMap1D] Registered map " << mapID << " with " << entries << " entries." << std::endl;
74+
}
75+
76+
/// Register by name; returns mapID computed from name
77+
int registerMap1DByName(const std::string& mapName, const std::string& valX, const std::string& valY, TTree* tree, const std::string& selection) {
78+
int mapID = hashMapName(mapName);
79+
nameToMapID[mapName] = mapID;
80+
registerMap1D(valX, valY, tree, selection, mapID);
81+
return mapID;
82+
}
83+
84+
/// Get the nearest Y for a given X from the map registered with mapID
85+
/// @param x Query value along X axis
86+
/// @param mapID Map identifier used in registration
87+
/// @return Y value corresponding to nearest X in the map
88+
float getNearest1D(float x, int mapID) {
89+
const auto itMap = registeredMaps.find(mapID);
90+
if (itMap == registeredMaps.end()) {
91+
std::cerr << "[getNearest1D] Map ID " << mapID << " not found." << std::endl;
92+
return NAN;
93+
}
94+
95+
const auto& map = itMap->second;
96+
if (map.empty()) {
97+
std::cerr << "[getNearest1D] Map ID " << mapID << " is empty." << std::endl;
98+
return NAN;
99+
}
100+
101+
auto it = map.lower_bound(x);
102+
if (it == map.begin()) return it->second;
103+
if (it == map.end()) return std::prev(it)->second;
104+
105+
auto prev = std::prev(it);
106+
return (std::abs(prev->first - x) < std::abs(it->first - x)) ? prev->second : it->second;
107+
}
108+
109+
/// Convenience version: lookup by name
110+
float getNearest1DByName(float x, const std::string& mapName) {
111+
auto it = nameToMapID.find(mapName);
112+
if (it == nameToMapID.end()) {
113+
std::cerr << "[getNearest1DByName] Map name \"" << mapName << "\" not found." << std::endl;
114+
return NAN;
115+
}
116+
return getNearest1D(x, it->second);
117+
}
118+
119+
/// Example usage
120+
void example1D() {
121+
TFile *f = TFile::Open("timeSeries10000_apass5.root");
122+
TTree * tree0=(TTree*)f->Get("timeSeries");
123+
// Fill tree here or load from file
124+
int mapID = registerMap1DByName("dcar_vs_time", "time", "mTSITSTPC.mDCAr_A_NTracks_median", tree0, "subentry==127");
125+
tree0->SetAlias("mDCAr_A_NTracks_median_All" ,("getNearest1D(time, " + std::to_string(mapID) + ")").data());
126+
tree0->Draw("mTSITSTPC.mDCAr_A_NTracks_median:mDCAr_A_NTracks_median_All","indexType==1","",10000);
127+
}

0 commit comments

Comments
 (0)