f9columnar 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- f9columnar-0.1.0/PKG-INFO +347 -0
- f9columnar-0.1.0/README.md +330 -0
- f9columnar-0.1.0/f9columnar/__init__.py +0 -0
- f9columnar-0.1.0/f9columnar/analysis/.gitignore +2 -0
- f9columnar-0.1.0/f9columnar/arrays.py +286 -0
- f9columnar-0.1.0/f9columnar/collections.py +165 -0
- f9columnar-0.1.0/f9columnar/data/PMGxsecDB_mc16.txt +103645 -0
- f9columnar-0.1.0/f9columnar/data/PMGxsecDB_mc21.txt +815 -0
- f9columnar-0.1.0/f9columnar/data/campaigns.json +27 -0
- f9columnar-0.1.0/f9columnar/data/luminosity.json +18 -0
- f9columnar-0.1.0/f9columnar/data/periods.json +32 -0
- f9columnar-0.1.0/f9columnar/data/truth_classification.json +94 -0
- f9columnar-0.1.0/f9columnar/dataloader_monitor.py +301 -0
- f9columnar-0.1.0/f9columnar/dataset_builder.py +576 -0
- f9columnar-0.1.0/f9columnar/hdf5_writer.py +324 -0
- f9columnar-0.1.0/f9columnar/histograms.py +641 -0
- f9columnar-0.1.0/f9columnar/object_collections.py +165 -0
- f9columnar-0.1.0/f9columnar/plotting.py +321 -0
- f9columnar-0.1.0/f9columnar/processors.py +466 -0
- f9columnar-0.1.0/f9columnar/root_dataloader.py +718 -0
- f9columnar-0.1.0/f9columnar/run.py +285 -0
- f9columnar-0.1.0/f9columnar/submit/__init__.py +0 -0
- f9columnar-0.1.0/f9columnar/submit/act_get.py +193 -0
- f9columnar-0.1.0/f9columnar/submit/act_handler.py +321 -0
- f9columnar-0.1.0/f9columnar/submit/act_merge.py +84 -0
- f9columnar-0.1.0/f9columnar/submit/act_monitor.py +33 -0
- f9columnar-0.1.0/f9columnar/submit/act_submit.py +307 -0
- f9columnar-0.1.0/f9columnar/submit/config/act-client/config.yaml +16 -0
- f9columnar-0.1.0/f9columnar/utils/__init__.py +0 -0
- f9columnar-0.1.0/f9columnar/utils/ak_helpers.py +143 -0
- f9columnar-0.1.0/f9columnar/utils/helpers.py +240 -0
- f9columnar-0.1.0/f9columnar/utils/loggers.py +163 -0
- f9columnar-0.1.0/f9columnar/utils/regex_helpers.py +34 -0
- f9columnar-0.1.0/f9columnar/utils/rucio_utils.py +128 -0
- f9columnar-0.1.0/f9columnar/xsec_db.py +88 -0
- f9columnar-0.1.0/pyproject.toml +50 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: f9columnar
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: F9 columnar analysis utils.
|
|
5
|
+
Home-page: https://gitlab.cern.ch/ijs-f9-ljubljana/f9columnar
|
|
6
|
+
License: MIT
|
|
7
|
+
Author: Jan Gavranovic
|
|
8
|
+
Author-email: jan.gavranovic@cern.ch
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Project-URL: Repository, https://gitlab.cern.ch/ijs-f9-ljubljana/f9columnar
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# F9 Columnar
|
|
18
|
+
|
|
19
|
+
### 🚧 **Work in Progress** ⚠️
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
### User install
|
|
24
|
+
|
|
25
|
+
To install the package use `pip`:
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
pip install f9columnar
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Development install
|
|
32
|
+
|
|
33
|
+
Use [poetry](https://python-poetry.org/) to install the required packages:
|
|
34
|
+
|
|
35
|
+
```shell
|
|
36
|
+
poetry config cache-dir $PWD
|
|
37
|
+
poetry config virtualenvs.in-project true
|
|
38
|
+
poetry install
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
This environment is duplicated for batch processing on dCache using `batch_requirements.txt`.
|
|
42
|
+
|
|
43
|
+
### aCT
|
|
44
|
+
|
|
45
|
+
[ARC](https://doc.vega.izum.si/arc) Control Tower (aCT) is a system for submitting and managing payloads on ARC (and other) Computing Elements. It is used to submit jobs on sites in Slovenia.
|
|
46
|
+
|
|
47
|
+
#### Configuration
|
|
48
|
+
|
|
49
|
+
Common aCT config is provided in [`config/act-client/config.yaml`](columnar/submit/config/act-client/config.yaml). To use it, copy the file to `~/.config/act-client/config.yaml`.
|
|
50
|
+
|
|
51
|
+
#### Installation
|
|
52
|
+
|
|
53
|
+
First get the python binary path from the environment you use using `which python`.
|
|
54
|
+
|
|
55
|
+
Make the virtual environment using this binary:
|
|
56
|
+
|
|
57
|
+
```shell
|
|
58
|
+
/cvmfs/sft.cern.ch/lcg/views/LCG_104b/x86_64-el9-gcc13-opt/bin/python3 -m venv act_venv
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
In the newly created environment install [aCT](https://github.com/ARCControlTower/aCT):
|
|
62
|
+
|
|
63
|
+
```shell
|
|
64
|
+
source act_venv/bin/activate
|
|
65
|
+
pip install "git+https://github.com/ARCControlTower/aCT.git@test#subdirectory=src/act/client/aCT-client"
|
|
66
|
+
pip install pandas
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The command `act` is available in `PATH` as the virtual environment is activated.
|
|
70
|
+
|
|
71
|
+
#### Voms proxy setup
|
|
72
|
+
|
|
73
|
+
Note that it is recommended to be in `/atlas/si` group and make the proxy with it. Active it using (in a separate terminal):
|
|
74
|
+
|
|
75
|
+
```shell
|
|
76
|
+
setupATLAS
|
|
77
|
+
lsetup emi
|
|
78
|
+
voms-proxy-init --valid 96:0 --voms atlas:/atlas/si
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
To propagate the proxy to the system use
|
|
82
|
+
|
|
83
|
+
```shell
|
|
84
|
+
act proxy
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
At this point you are ready to use aCT.
|
|
88
|
+
|
|
89
|
+
#### Analysis specific setup
|
|
90
|
+
|
|
91
|
+
For job submission, the aCT environment must be setup. The following commands will activate the environment and alias `act_submit`, `act_get` and `act_monitor` python scripts:
|
|
92
|
+
|
|
93
|
+
```shell
|
|
94
|
+
source setup_act.sh
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- `act_submit` - submit jobs
|
|
98
|
+
- `--jobs_dir` (default: `batch/run_0`)
|
|
99
|
+
- `--cluster_lst` (default: everything in `config`)
|
|
100
|
+
- `--retry_failed` (default: `False`)
|
|
101
|
+
- `--retry_stuck` (default: `False`)
|
|
102
|
+
- `--retry_empty` (default: `False`)
|
|
103
|
+
- `--retry_missing` (default: `False`)
|
|
104
|
+
- `act_get` - download done jobs
|
|
105
|
+
- `--jobs_dir` (default: `batch/run_0`)
|
|
106
|
+
- `--retry_empty` (default: `True`)
|
|
107
|
+
- `--include_finishing` (default: `False`)
|
|
108
|
+
- `act_monitor` - monitor jobs
|
|
109
|
+
|
|
110
|
+
#### General commands
|
|
111
|
+
|
|
112
|
+
Most commands accept either job ID using `-i <ID>` or a full list is toggled using `-a` and can be filtered by job name using `-n <NAME>` (partial match is also available). Please consult the help for each command.
|
|
113
|
+
|
|
114
|
+
The following commands are useful (see `act --help` for more):
|
|
115
|
+
|
|
116
|
+
- `act stat` - list all jobs and their statuses
|
|
117
|
+
- `act cat` - show job log (works also while job is running)
|
|
118
|
+
- `act kill` - kill selected jobs
|
|
119
|
+
- `act clean` - clean selected jobs, mainly used after killing
|
|
120
|
+
- `act resub` - resubmit selected jobs if failed due to a glitch
|
|
121
|
+
- `act get --noclean` - get the output of selected jobs without cleaning the job
|
|
122
|
+
|
|
123
|
+
## Getting started example
|
|
124
|
+
|
|
125
|
+
### Basic example
|
|
126
|
+
|
|
127
|
+
The main idea is to have a columnar event loop that returns arrays of events. The code and usage is the same as in a standard torch training loop over epochs, but instead of having epochs we iterate over batches of events.
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from columnar.root_dataloader import get_root_dataloader
|
|
131
|
+
|
|
132
|
+
def filter_branch(branch):
|
|
133
|
+
# select only these two branches
|
|
134
|
+
return branch.name == "tau_p4" or branch.name == "lephad_p4"
|
|
135
|
+
|
|
136
|
+
# root_dataloader is an instance of a torch DataLoader that uses an IterableDataset
|
|
137
|
+
root_dataloader, total = get_root_dataloader(
|
|
138
|
+
ntuple_path, # path to the root file (file, list of paths or directory)
|
|
139
|
+
name="data", # name identifier
|
|
140
|
+
chunks="auto", # number of chunks to split the root file(s) into
|
|
141
|
+
setup_workers=4, # number of workers for initial setup
|
|
142
|
+
step_size="15 MB", # size of the step for the worker to read the root file
|
|
143
|
+
postifx="NOMINAL", # root file postfix
|
|
144
|
+
filter_branch=filter_branch, # filter branches
|
|
145
|
+
processors=None, # arbitrary calculations on arrays
|
|
146
|
+
num_workers=12, # number of workers for parallel processing
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
# loop over batches of events from .root file(s), each batch is an awkward array
|
|
150
|
+
for events in root_dataloader:
|
|
151
|
+
arrays, report = events
|
|
152
|
+
# ... do something with the arrays
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Doing calculations on arrays inside of workers can be done using a `Processor`. Many processors can be chained together into a `ProcessorsGraph` (DAG) to perform more complex calculations. Processors are applied to the arrays in the order given by the topological sort of the DAG. Note that each worker runs the same processor graph on batches of array events and returns the result to the event loop when done. So in the above example there would be 12 (`num_workers`) processor graphs running in parallel on small batches of events. An example of calculating tau visible mass and then applying a cut on this variable is shown below.
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from columnar.processor import ProcessorsGraph, CheckpointProcessor
|
|
159
|
+
from columnar.collections import Variable, VariableCollection, Cut, CutCollection
|
|
160
|
+
from columnar.histograms import HistogramProcessor
|
|
161
|
+
|
|
162
|
+
class VisibleMass(Variable): # Variable is a Processor
|
|
163
|
+
name = "vis_mass" # processor name
|
|
164
|
+
branch_name = "lephad_p4" # name of the branch in the .root file
|
|
165
|
+
|
|
166
|
+
def __init__(self):
|
|
167
|
+
super().__init__()
|
|
168
|
+
|
|
169
|
+
def run(self, arrays): # each processor must implement a run method
|
|
170
|
+
lephad_p4 = arrays[self.branch_name] # branch_name is the name of the field in the ak array
|
|
171
|
+
v = get_kinematics_vector(lephad_p4) # use vector with px, py, pz and E
|
|
172
|
+
|
|
173
|
+
arrays["tau_vis_mass"] = v.m # add a new field to the arrays
|
|
174
|
+
|
|
175
|
+
return {"arrays": arrays} # return the arrays (can also return None if no changes are made)
|
|
176
|
+
|
|
177
|
+
class CutVisibleMass(Cut): # Cut is a Processor
|
|
178
|
+
name = "vis_mass_cut"
|
|
179
|
+
branch_name = None # is not a branch in ntuples but was defined in the VisibleMass processor
|
|
180
|
+
|
|
181
|
+
def __init__(self, cut_lower, cut_upper): # argumnets of the processor
|
|
182
|
+
super().__init__()
|
|
183
|
+
self.cut_lower = cut_lower
|
|
184
|
+
self.cut_upper = cut_upper
|
|
185
|
+
|
|
186
|
+
def run(self, arrays):
|
|
187
|
+
mask = (arrays["tau_vis_mass"] > self.cut_lower) & (arrays["tau_vis_mass"] < self.cut_upper)
|
|
188
|
+
arrays = arrays[mask] # apply the cut
|
|
189
|
+
|
|
190
|
+
return {"arrays": arrays} # return must be a dictionary with key name for the argument of the next processor
|
|
191
|
+
|
|
192
|
+
class Histograms(HistogramProcessor):
|
|
193
|
+
def __init__(self, name="histograms"):
|
|
194
|
+
super().__init__(name)
|
|
195
|
+
|
|
196
|
+
self.make_hist1d("tau_vis_mass", 20, 80.0, 110.0) # make a histogram with 20 bins from 80 to 110 GeV
|
|
197
|
+
|
|
198
|
+
def run(self, arrays):
|
|
199
|
+
return super().run(arrays) # auto fills histograms if array names match histogram names
|
|
200
|
+
|
|
201
|
+
var_collection = VariableCollection(VisibleMass, init=False) # will initialize later
|
|
202
|
+
cut_collection = CutCollection(CutVisibleMass, init=False)
|
|
203
|
+
|
|
204
|
+
collection = var_collection + cut_collection # add collections of objects together
|
|
205
|
+
branch_filter = collection.branch_name_filter # defines the branches that the processors depend on
|
|
206
|
+
|
|
207
|
+
graph = ProcessorsGraph() # graph has a fit method that gets called inside the root_dataloader
|
|
208
|
+
|
|
209
|
+
# add nodes to the graph
|
|
210
|
+
graph.add(
|
|
211
|
+
CheckpointProcessor("input"), # input node
|
|
212
|
+
var_collection["vis_mass"](), # initialize the processor
|
|
213
|
+
cut_collection["vis_mass_cut"](cut_lower=90.0, cut_upper=100.0),
|
|
214
|
+
CheckpointProcessor("output", save_arrays=True), # saves final arrays
|
|
215
|
+
Histograms(),
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# build a processor graph
|
|
219
|
+
graph.connect(
|
|
220
|
+
[
|
|
221
|
+
("input", "vis_mass"),
|
|
222
|
+
("vis_mass", "vis_mass_cut"),
|
|
223
|
+
("vis_mass_cut", "output"),
|
|
224
|
+
("output", "histograms"),
|
|
225
|
+
]
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# plot the graph
|
|
229
|
+
graph.draw("graph.pdf")
|
|
230
|
+
|
|
231
|
+
# ... pass into the root_dataloader with the processors argument (e.g. processors=graph)
|
|
232
|
+
# in this case the dataloader will return a fitted graph
|
|
233
|
+
for processed_graph in dataloader:
|
|
234
|
+
histograms = processed_graph["histograms"].hists
|
|
235
|
+
arrays = processed_graph["output"].arrays
|
|
236
|
+
# ... do something with the histograms and arrays
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Ntuple analysis example
|
|
240
|
+
|
|
241
|
+
TODO
|
|
242
|
+
|
|
243
|
+
### ROOT DataLoader schema
|
|
244
|
+
|
|
245
|
+

|
|
246
|
+
|
|
247
|
+
## Development
|
|
248
|
+
|
|
249
|
+
### Making a portable venv with conda
|
|
250
|
+
|
|
251
|
+
Make sure you have [Miniconda](https://docs.anaconda.com/miniconda/) installed:
|
|
252
|
+
|
|
253
|
+
```shell
|
|
254
|
+
mkdir miniconda3
|
|
255
|
+
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3/miniconda.sh
|
|
256
|
+
bash miniconda3/miniconda.sh -b -u -p miniconda3
|
|
257
|
+
rm -rf miniconda3/miniconda.sh
|
|
258
|
+
miniconda3/bin/conda init bash
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
`init` command will add some path variables to your `~/.bashrc` that you can delete when done.
|
|
262
|
+
|
|
263
|
+
To test conda install use:
|
|
264
|
+
|
|
265
|
+
```shell
|
|
266
|
+
conda -V
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Next, make a virtual environment and install the required packages:
|
|
270
|
+
|
|
271
|
+
```shell
|
|
272
|
+
conda create -n batch_venv python=3.12.4
|
|
273
|
+
source activate batch_venv
|
|
274
|
+
pip install -r batch_requirements.txt
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
In order to make this environment portable use [conda-pack](https://conda.github.io/conda-pack/):
|
|
278
|
+
|
|
279
|
+
```shell
|
|
280
|
+
conda install conda-pack
|
|
281
|
+
conda pack
|
|
282
|
+
conda deactivate
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
On remote machine unpack the environment:
|
|
286
|
+
|
|
287
|
+
```shell
|
|
288
|
+
tar -xzf batch_venv.tar.gz
|
|
289
|
+
source batch_venv/bin/activate
|
|
290
|
+
conda-unpack
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
If there are problems with the `.gz` file, unpack it and tar it again without compression:
|
|
294
|
+
|
|
295
|
+
```shell
|
|
296
|
+
mkdir -p batch_venv
|
|
297
|
+
tar -xzf batch_venv.tar.gz -C batch_venv
|
|
298
|
+
tar -cvf batch_venv.tar batch_venv
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### dCache
|
|
302
|
+
|
|
303
|
+
Basic instructions can be found [here](https://doc.sling.si/en/navodila/podatki/).
|
|
304
|
+
|
|
305
|
+
To upload the above described venv to dCache use:
|
|
306
|
+
|
|
307
|
+
```shell
|
|
308
|
+
arccp batch_venv.tar davs://dcache.sling.si:2880/atlas/jang/
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
where you can make your own directory with `arcmkdir`.
|
|
312
|
+
|
|
313
|
+
### lxplus venv setup
|
|
314
|
+
|
|
315
|
+
Log into lxplus:
|
|
316
|
+
```shell
|
|
317
|
+
ssh <name>@lxplus.cern.ch
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Since we want custom python packages and installing on `afs` is not recommended, we will use `eos`:
|
|
321
|
+
```shell
|
|
322
|
+
cd /eos/user/j/jgavrano
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Source an LCG release to use as base:
|
|
326
|
+
```shell
|
|
327
|
+
setupATLAS
|
|
328
|
+
lsetup "views LCG_105b x86_64-el9-gcc13-opt"
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Setup `venv` and install required packages from `requirements`:
|
|
332
|
+
```shell
|
|
333
|
+
PYTHONUSERBASE=/eos/user/j/jgavrano/F9Columnar/ pip3 install --user --no-cache-dir -r requirements.txt
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Test with libraries in `eos`:
|
|
337
|
+
```shell
|
|
338
|
+
PYTHONPATH=/eos/user/j/jgavrano/F9Columnar/lib/python3.9/site-packages/:$PYTHONPATH python3 <script_name>.py
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
Setup python with custom `venv`:
|
|
342
|
+
```shell
|
|
343
|
+
export PYTHONPATH=/eos/user/j/jgavrano/F9Columnar/lib/python3.9/site-packages/:$PYTHONPATH
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
To make it public go to cernbox website and share it with `atlas-current-physicists`.
|
|
347
|
+
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# F9 Columnar
|
|
2
|
+
|
|
3
|
+
### 🚧 **Work in Progress** ⚠️
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
### User install
|
|
8
|
+
|
|
9
|
+
To install the package use `pip`:
|
|
10
|
+
|
|
11
|
+
```shell
|
|
12
|
+
pip install f9columnar
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Development install
|
|
16
|
+
|
|
17
|
+
Use [poetry](https://python-poetry.org/) to install the required packages:
|
|
18
|
+
|
|
19
|
+
```shell
|
|
20
|
+
poetry config cache-dir $PWD
|
|
21
|
+
poetry config virtualenvs.in-project true
|
|
22
|
+
poetry install
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This environment is duplicated for batch processing on dCache using `batch_requirements.txt`.
|
|
26
|
+
|
|
27
|
+
### aCT
|
|
28
|
+
|
|
29
|
+
[ARC](https://doc.vega.izum.si/arc) Control Tower (aCT) is a system for submitting and managing payloads on ARC (and other) Computing Elements. It is used to submit jobs on sites in Slovenia.
|
|
30
|
+
|
|
31
|
+
#### Configuration
|
|
32
|
+
|
|
33
|
+
Common aCT config is provided in [`config/act-client/config.yaml`](columnar/submit/config/act-client/config.yaml). To use it, copy the file to `~/.config/act-client/config.yaml`.
|
|
34
|
+
|
|
35
|
+
#### Installation
|
|
36
|
+
|
|
37
|
+
First get the python binary path from the environment you use using `which python`.
|
|
38
|
+
|
|
39
|
+
Make the virtual environment using this binary:
|
|
40
|
+
|
|
41
|
+
```shell
|
|
42
|
+
/cvmfs/sft.cern.ch/lcg/views/LCG_104b/x86_64-el9-gcc13-opt/bin/python3 -m venv act_venv
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
In the newly created environment install [aCT](https://github.com/ARCControlTower/aCT):
|
|
46
|
+
|
|
47
|
+
```shell
|
|
48
|
+
source act_venv/bin/activate
|
|
49
|
+
pip install "git+https://github.com/ARCControlTower/aCT.git@test#subdirectory=src/act/client/aCT-client"
|
|
50
|
+
pip install pandas
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The command `act` is available in `PATH` as the virtual environment is activated.
|
|
54
|
+
|
|
55
|
+
#### Voms proxy setup
|
|
56
|
+
|
|
57
|
+
Note that it is recommended to be in `/atlas/si` group and make the proxy with it. Active it using (in a separate terminal):
|
|
58
|
+
|
|
59
|
+
```shell
|
|
60
|
+
setupATLAS
|
|
61
|
+
lsetup emi
|
|
62
|
+
voms-proxy-init --valid 96:0 --voms atlas:/atlas/si
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
To propagate the proxy to the system use
|
|
66
|
+
|
|
67
|
+
```shell
|
|
68
|
+
act proxy
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
At this point you are ready to use aCT.
|
|
72
|
+
|
|
73
|
+
#### Analysis specific setup
|
|
74
|
+
|
|
75
|
+
For job submission, the aCT environment must be setup. The following commands will activate the environment and alias `act_submit`, `act_get` and `act_monitor` python scripts:
|
|
76
|
+
|
|
77
|
+
```shell
|
|
78
|
+
source setup_act.sh
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
- `act_submit` - submit jobs
|
|
82
|
+
- `--jobs_dir` (default: `batch/run_0`)
|
|
83
|
+
- `--cluster_lst` (default: everything in `config`)
|
|
84
|
+
- `--retry_failed` (default: `False`)
|
|
85
|
+
- `--retry_stuck` (default: `False`)
|
|
86
|
+
- `--retry_empty` (default: `False`)
|
|
87
|
+
- `--retry_missing` (default: `False`)
|
|
88
|
+
- `act_get` - download done jobs
|
|
89
|
+
- `--jobs_dir` (default: `batch/run_0`)
|
|
90
|
+
- `--retry_empty` (default: `True`)
|
|
91
|
+
- `--include_finishing` (default: `False`)
|
|
92
|
+
- `act_monitor` - monitor jobs
|
|
93
|
+
|
|
94
|
+
#### General commands
|
|
95
|
+
|
|
96
|
+
Most commands accept either job ID using `-i <ID>` or a full list is toggled using `-a` and can be filtered by job name using `-n <NAME>` (partial match is also available). Please consult the help for each command.
|
|
97
|
+
|
|
98
|
+
The following commands are useful (see `act --help` for more):
|
|
99
|
+
|
|
100
|
+
- `act stat` - list all jobs and their statuses
|
|
101
|
+
- `act cat` - show job log (works also while job is running)
|
|
102
|
+
- `act kill` - kill selected jobs
|
|
103
|
+
- `act clean` - clean selected jobs, mainly used after killing
|
|
104
|
+
- `act resub` - resubmit selected jobs if failed due to a glitch
|
|
105
|
+
- `act get --noclean` - get the output of selected jobs without cleaning the job
|
|
106
|
+
|
|
107
|
+
## Getting started example
|
|
108
|
+
|
|
109
|
+
### Basic example
|
|
110
|
+
|
|
111
|
+
The main idea is to have a columnar event loop that returns arrays of events. The code and usage is the same as in a standard torch training loop over epochs, but instead of having epochs we iterate over batches of events.
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from columnar.root_dataloader import get_root_dataloader
|
|
115
|
+
|
|
116
|
+
def filter_branch(branch):
|
|
117
|
+
# select only these two branches
|
|
118
|
+
return branch.name == "tau_p4" or branch.name == "lephad_p4"
|
|
119
|
+
|
|
120
|
+
# root_dataloader is an instance of a torch DataLoader that uses an IterableDataset
|
|
121
|
+
root_dataloader, total = get_root_dataloader(
|
|
122
|
+
ntuple_path, # path to the root file (file, list of paths or directory)
|
|
123
|
+
name="data", # name identifier
|
|
124
|
+
chunks="auto", # number of chunks to split the root file(s) into
|
|
125
|
+
setup_workers=4, # number of workers for initial setup
|
|
126
|
+
step_size="15 MB", # size of the step for the worker to read the root file
|
|
127
|
+
postifx="NOMINAL", # root file postfix
|
|
128
|
+
filter_branch=filter_branch, # filter branches
|
|
129
|
+
processors=None, # arbitrary calculations on arrays
|
|
130
|
+
num_workers=12, # number of workers for parallel processing
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# loop over batches of events from .root file(s), each batch is an awkward array
|
|
134
|
+
for events in root_dataloader:
|
|
135
|
+
arrays, report = events
|
|
136
|
+
# ... do something with the arrays
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Doing calculations on arrays inside of workers can be done using a `Processor`. Many processors can be chained together into a `ProcessorsGraph` (DAG) to perform more complex calculations. Processors are applied to the arrays in the order given by the topological sort of the DAG. Note that each worker runs the same processor graph on batches of array events and returns the result to the event loop when done. So in the above example there would be 12 (`num_workers`) processor graphs running in parallel on small batches of events. An example of calculating tau visible mass and then applying a cut on this variable is shown below.
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from columnar.processor import ProcessorsGraph, CheckpointProcessor
|
|
143
|
+
from columnar.collections import Variable, VariableCollection, Cut, CutCollection
|
|
144
|
+
from columnar.histograms import HistogramProcessor
|
|
145
|
+
|
|
146
|
+
class VisibleMass(Variable): # Variable is a Processor
|
|
147
|
+
name = "vis_mass" # processor name
|
|
148
|
+
branch_name = "lephad_p4" # name of the branch in the .root file
|
|
149
|
+
|
|
150
|
+
def __init__(self):
|
|
151
|
+
super().__init__()
|
|
152
|
+
|
|
153
|
+
def run(self, arrays): # each processor must implement a run method
|
|
154
|
+
lephad_p4 = arrays[self.branch_name] # branch_name is the name of the field in the ak array
|
|
155
|
+
v = get_kinematics_vector(lephad_p4) # use vector with px, py, pz and E
|
|
156
|
+
|
|
157
|
+
arrays["tau_vis_mass"] = v.m # add a new field to the arrays
|
|
158
|
+
|
|
159
|
+
return {"arrays": arrays} # return the arrays (can also return None if no changes are made)
|
|
160
|
+
|
|
161
|
+
class CutVisibleMass(Cut): # Cut is a Processor
|
|
162
|
+
name = "vis_mass_cut"
|
|
163
|
+
branch_name = None # is not a branch in ntuples but was defined in the VisibleMass processor
|
|
164
|
+
|
|
165
|
+
def __init__(self, cut_lower, cut_upper): # argumnets of the processor
|
|
166
|
+
super().__init__()
|
|
167
|
+
self.cut_lower = cut_lower
|
|
168
|
+
self.cut_upper = cut_upper
|
|
169
|
+
|
|
170
|
+
def run(self, arrays):
|
|
171
|
+
mask = (arrays["tau_vis_mass"] > self.cut_lower) & (arrays["tau_vis_mass"] < self.cut_upper)
|
|
172
|
+
arrays = arrays[mask] # apply the cut
|
|
173
|
+
|
|
174
|
+
return {"arrays": arrays} # return must be a dictionary with key name for the argument of the next processor
|
|
175
|
+
|
|
176
|
+
class Histograms(HistogramProcessor):
|
|
177
|
+
def __init__(self, name="histograms"):
|
|
178
|
+
super().__init__(name)
|
|
179
|
+
|
|
180
|
+
self.make_hist1d("tau_vis_mass", 20, 80.0, 110.0) # make a histogram with 20 bins from 80 to 110 GeV
|
|
181
|
+
|
|
182
|
+
def run(self, arrays):
|
|
183
|
+
return super().run(arrays) # auto fills histograms if array names match histogram names
|
|
184
|
+
|
|
185
|
+
var_collection = VariableCollection(VisibleMass, init=False) # will initialize later
|
|
186
|
+
cut_collection = CutCollection(CutVisibleMass, init=False)
|
|
187
|
+
|
|
188
|
+
collection = var_collection + cut_collection # add collections of objects together
|
|
189
|
+
branch_filter = collection.branch_name_filter # defines the branches that the processors depend on
|
|
190
|
+
|
|
191
|
+
graph = ProcessorsGraph() # graph has a fit method that gets called inside the root_dataloader
|
|
192
|
+
|
|
193
|
+
# add nodes to the graph
|
|
194
|
+
graph.add(
|
|
195
|
+
CheckpointProcessor("input"), # input node
|
|
196
|
+
var_collection["vis_mass"](), # initialize the processor
|
|
197
|
+
cut_collection["vis_mass_cut"](cut_lower=90.0, cut_upper=100.0),
|
|
198
|
+
CheckpointProcessor("output", save_arrays=True), # saves final arrays
|
|
199
|
+
Histograms(),
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# build a processor graph
|
|
203
|
+
graph.connect(
|
|
204
|
+
[
|
|
205
|
+
("input", "vis_mass"),
|
|
206
|
+
("vis_mass", "vis_mass_cut"),
|
|
207
|
+
("vis_mass_cut", "output"),
|
|
208
|
+
("output", "histograms"),
|
|
209
|
+
]
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# plot the graph
|
|
213
|
+
graph.draw("graph.pdf")
|
|
214
|
+
|
|
215
|
+
# ... pass into the root_dataloader with the processors argument (e.g. processors=graph)
|
|
216
|
+
# in this case the dataloader will return a fitted graph
|
|
217
|
+
for processed_graph in dataloader:
|
|
218
|
+
histograms = processed_graph["histograms"].hists
|
|
219
|
+
arrays = processed_graph["output"].arrays
|
|
220
|
+
# ... do something with the histograms and arrays
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Ntuple analysis example
|
|
224
|
+
|
|
225
|
+
TODO
|
|
226
|
+
|
|
227
|
+
### ROOT DataLoader schema
|
|
228
|
+
|
|
229
|
+

|
|
230
|
+
|
|
231
|
+
## Development
|
|
232
|
+
|
|
233
|
+
### Making a portable venv with conda
|
|
234
|
+
|
|
235
|
+
Make sure you have [Miniconda](https://docs.anaconda.com/miniconda/) installed:
|
|
236
|
+
|
|
237
|
+
```shell
|
|
238
|
+
mkdir miniconda3
|
|
239
|
+
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda3/miniconda.sh
|
|
240
|
+
bash miniconda3/miniconda.sh -b -u -p miniconda3
|
|
241
|
+
rm -rf miniconda3/miniconda.sh
|
|
242
|
+
miniconda3/bin/conda init bash
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`init` command will add some path variables to your `~/.bashrc` that you can delete when done.
|
|
246
|
+
|
|
247
|
+
To test conda install use:
|
|
248
|
+
|
|
249
|
+
```shell
|
|
250
|
+
conda -V
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Next, make a virtual environment and install the required packages:
|
|
254
|
+
|
|
255
|
+
```shell
|
|
256
|
+
conda create -n batch_venv python=3.12.4
|
|
257
|
+
source activate batch_venv
|
|
258
|
+
pip install -r batch_requirements.txt
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
In order to make this environment portable use [conda-pack](https://conda.github.io/conda-pack/):
|
|
262
|
+
|
|
263
|
+
```shell
|
|
264
|
+
conda install conda-pack
|
|
265
|
+
conda pack
|
|
266
|
+
conda deactivate
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
On remote machine unpack the environment:
|
|
270
|
+
|
|
271
|
+
```shell
|
|
272
|
+
tar -xzf batch_venv.tar.gz
|
|
273
|
+
source batch_venv/bin/activate
|
|
274
|
+
conda-unpack
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
If there are problems with the `.gz` file, unpack it and tar it again without compression:
|
|
278
|
+
|
|
279
|
+
```shell
|
|
280
|
+
mkdir -p batch_venv
|
|
281
|
+
tar -xzf batch_venv.tar.gz -C batch_venv
|
|
282
|
+
tar -cvf batch_venv.tar batch_venv
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### dCache
|
|
286
|
+
|
|
287
|
+
Basic instructions can be found [here](https://doc.sling.si/en/navodila/podatki/).
|
|
288
|
+
|
|
289
|
+
To upload the above described venv to dCache use:
|
|
290
|
+
|
|
291
|
+
```shell
|
|
292
|
+
arccp batch_venv.tar davs://dcache.sling.si:2880/atlas/jang/
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
where you can make your own directory with `arcmkdir`.
|
|
296
|
+
|
|
297
|
+
### lxplus venv setup
|
|
298
|
+
|
|
299
|
+
Log into lxplus:
|
|
300
|
+
```shell
|
|
301
|
+
ssh <name>@lxplus.cern.ch
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Since we want custom python packages and installing on `afs` is not recommended, we will use `eos`:
|
|
305
|
+
```shell
|
|
306
|
+
cd /eos/user/j/jgavrano
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Source an LCG release to use as base:
|
|
310
|
+
```shell
|
|
311
|
+
setupATLAS
|
|
312
|
+
lsetup "views LCG_105b x86_64-el9-gcc13-opt"
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Setup `venv` and install required packages from `requirements`:
|
|
316
|
+
```shell
|
|
317
|
+
PYTHONUSERBASE=/eos/user/j/jgavrano/F9Columnar/ pip3 install --user --no-cache-dir -r requirements.txt
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Test with libraries in `eos`:
|
|
321
|
+
```shell
|
|
322
|
+
PYTHONPATH=/eos/user/j/jgavrano/F9Columnar/lib/python3.9/site-packages/:$PYTHONPATH python3 <script_name>.py
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Setup python with custom `venv`:
|
|
326
|
+
```shell
|
|
327
|
+
export PYTHONPATH=/eos/user/j/jgavrano/F9Columnar/lib/python3.9/site-packages/:$PYTHONPATH
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
To make it public go to cernbox website and share it with `atlas-current-physicists`.
|
|
File without changes
|