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.
Files changed (36) hide show
  1. f9columnar-0.1.0/PKG-INFO +347 -0
  2. f9columnar-0.1.0/README.md +330 -0
  3. f9columnar-0.1.0/f9columnar/__init__.py +0 -0
  4. f9columnar-0.1.0/f9columnar/analysis/.gitignore +2 -0
  5. f9columnar-0.1.0/f9columnar/arrays.py +286 -0
  6. f9columnar-0.1.0/f9columnar/collections.py +165 -0
  7. f9columnar-0.1.0/f9columnar/data/PMGxsecDB_mc16.txt +103645 -0
  8. f9columnar-0.1.0/f9columnar/data/PMGxsecDB_mc21.txt +815 -0
  9. f9columnar-0.1.0/f9columnar/data/campaigns.json +27 -0
  10. f9columnar-0.1.0/f9columnar/data/luminosity.json +18 -0
  11. f9columnar-0.1.0/f9columnar/data/periods.json +32 -0
  12. f9columnar-0.1.0/f9columnar/data/truth_classification.json +94 -0
  13. f9columnar-0.1.0/f9columnar/dataloader_monitor.py +301 -0
  14. f9columnar-0.1.0/f9columnar/dataset_builder.py +576 -0
  15. f9columnar-0.1.0/f9columnar/hdf5_writer.py +324 -0
  16. f9columnar-0.1.0/f9columnar/histograms.py +641 -0
  17. f9columnar-0.1.0/f9columnar/object_collections.py +165 -0
  18. f9columnar-0.1.0/f9columnar/plotting.py +321 -0
  19. f9columnar-0.1.0/f9columnar/processors.py +466 -0
  20. f9columnar-0.1.0/f9columnar/root_dataloader.py +718 -0
  21. f9columnar-0.1.0/f9columnar/run.py +285 -0
  22. f9columnar-0.1.0/f9columnar/submit/__init__.py +0 -0
  23. f9columnar-0.1.0/f9columnar/submit/act_get.py +193 -0
  24. f9columnar-0.1.0/f9columnar/submit/act_handler.py +321 -0
  25. f9columnar-0.1.0/f9columnar/submit/act_merge.py +84 -0
  26. f9columnar-0.1.0/f9columnar/submit/act_monitor.py +33 -0
  27. f9columnar-0.1.0/f9columnar/submit/act_submit.py +307 -0
  28. f9columnar-0.1.0/f9columnar/submit/config/act-client/config.yaml +16 -0
  29. f9columnar-0.1.0/f9columnar/utils/__init__.py +0 -0
  30. f9columnar-0.1.0/f9columnar/utils/ak_helpers.py +143 -0
  31. f9columnar-0.1.0/f9columnar/utils/helpers.py +240 -0
  32. f9columnar-0.1.0/f9columnar/utils/loggers.py +163 -0
  33. f9columnar-0.1.0/f9columnar/utils/regex_helpers.py +34 -0
  34. f9columnar-0.1.0/f9columnar/utils/rucio_utils.py +128 -0
  35. f9columnar-0.1.0/f9columnar/xsec_db.py +88 -0
  36. 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
+ ![ROOT_dl](https://i.imgur.com/dGU2xDL.png)
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
+ ![ROOT_dl](https://i.imgur.com/dGU2xDL.png)
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
@@ -0,0 +1,2 @@
1
+ *
2
+ !.gitignore