Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • staider/DaVinci
  • oozcelik/DaVinci
  • yoyang/DaVinci
  • jonrob/DaVinci
  • lhcb/DaVinci
5 results
Show changes
Commits on Source (4)
Showing
with 791 additions and 45 deletions
# backup files
*~
.*.swp
*.root
# build products
InstallArea/
......
......@@ -28,6 +28,7 @@ include(DaVinciDependencies)
# -- Subdirectories
lhcb_add_subdirectories(
DaVinciExamples
DaVinciTutorials
DaVinciSys
DaVinciTests
Phys/DaVinci
......
......@@ -312,8 +312,7 @@ def alg_config():
#
# Sprucing filter
#
my_filter = add_filter("HDRFilter_B0DsK",
f"HLT_PASS('{bd2dsk_line}Decision')")
my_filter = add_filter("HDRFilter_B0DsK", f"HLT_PASS('{bd2dsk_line}')")
#
# FunTuple
......
......@@ -59,7 +59,7 @@ variables_ds = FunctorCollection({
#associate FunctorCollection to field (branch) name
variables = {'ALL': variables_all, 'Ds': variables_ds}
filter_data = add_filter("SpruceFilter", f"HLT_PASS('{spruce_line}Decision')")
filter_data = add_filter("SpruceFilter", f"HLT_PASS('{spruce_line}')")
#Configure Funtuple algorithm
tuple_data = Funtuple(
......
......@@ -12,7 +12,7 @@
Option file for testing the ParticleTaggerAlg algorithm and the related ThOr functors MAP_ARRAY and MAP_RANGE.
The job runs over a spruced sample and retrieves a set of B0 -> Ds K+ candidates. For each candidate the ParticleTaggerAlg
looks at the TES location defined via the 'make_long_pions_from_spruce' function and creates a 'one-to-many' relation map
relating all the available tracks to the B candidate of the events.
relating all the available tracks to the B candidate of the events.
Then the MAP_ARRAY functor takes in input this relation map and for each entry stores the output of an external functor (i.e F.P, F.PT)
in a vector via the MAP_RANGE functor.
......@@ -81,8 +81,7 @@ tuple_B0DsK = Funtuple(
variables=variables,
inputs=bd2dsk_data)
filter_B0DsK = add_filter("HDRFilter_B0DsK",
f"HLT_PASS('{bd2dsk_line}Decision')")
filter_B0DsK = add_filter("HDRFilter_B0DsK", f"HLT_PASS('{bd2dsk_line}')")
options.annsvc_config = 'root://eoslhcb.cern.ch//eos/lhcb/wg/dpa/wp3/tests/spruce_all_lines_realtime_newPacking.tck.json'
options.histo_file = 'DV-example-tagger-his.root'
......
......@@ -20,7 +20,8 @@ from DaVinci import options
from DaVinci.truth_matching import configured_MCTruthAndBkgCatAlg
from DaVinci.algorithms import get_odin, get_decreports
d02kpi_data = force_location("/Event/HLT2/Hlt2CharmD0ToKmPipLine/Particles")
line_name = 'Hlt2CharmD0ToKmPipLine'
d02kpi_data = force_location(f"/Event/HLT2/{line_name}/Particles")
#get configured "MCTruthAndBkgCatAlg" algorithm for HLT2 output
mctruth = configured_MCTruthAndBkgCatAlg(
......@@ -40,10 +41,9 @@ collections = [
functorcollections.MCVertexInfo(mctruth)
]
hlt2_line_names = ['Hlt2CharmD0ToKmPipLineDecision']
evt_collections = [
functorcollections.EventInfo(odin),
functorcollections.SelectionInfo("Hlt2", dec, hlt2_line_names)
functorcollections.SelectionInfo("Hlt2", dec, [line_name])
]
assert len(collections) + len(evt_collections) == len(
......@@ -84,7 +84,6 @@ my_tuple = Funtuple(
def main():
my_filter = add_filter("HDRFilter_D0Kpi",
"HLT_PASS('Hlt2CharmD0ToKmPipLineDecision')")
my_filter = add_filter("HDRFilter_D0Kpi", f"HLT_PASS('{line_name}')")
return {"UserAlgs": [my_filter, my_tuple]}, []
......@@ -20,6 +20,7 @@ from DaVinci.algorithms import add_filter
from DaVinci import options
from DaVinci.truth_matching import configured_MCTruthAndBkgCatAlg
from DaVinci.algorithms import get_odin, get_decreports
from FunTuple.functorcollections import SelectionInfo
options.process = 'Hlt2'
......@@ -66,11 +67,10 @@ variables = {
def main():
d02kpi_data = force_location(
"/Event/HLT2/Hlt2CharmD0ToKmPipLine/Particles")
line_name = 'Hlt2CharmD0ToKmPipLine'
d02kpi_data = force_location(f"/Event/HLT2/{line_name}/Particles")
my_filter = add_filter("HDRFilter_D0Kpi",
"HLT_PASS('Hlt2CharmD0ToKmPipLineDecision')")
my_filter = add_filter("HDRFilter_D0Kpi", f"HLT_PASS('{line_name}')")
#get configured "MCTruthAndBkgCatAlg" algorithm for HLT2 output
mctruth = configured_MCTruthAndBkgCatAlg(
......@@ -105,23 +105,15 @@ def main():
odin = get_odin(options)
hlt2_dec = get_decreports("Hlt2", options)
#Since input is from this line should return 1 for decisions
hlt2_lines = ['Hlt2CharmD0ToKmPipLineDecision']
#define event level variables
evt_variables = FunctorCollection({
"RUNNUMBER":
F.RUNNUMBER(odin),
"EVENTNUMBER":
F.EVENTNUMBER(odin),
"Hlt2_TCK":
F.TCK(hlt2_dec),
"Sel":
F.DECISIONS(Lines=hlt2_lines, DecReports=hlt2_dec),
"RUNNUMBER": F.RUNNUMBER(odin),
"EVENTNUMBER": F.EVENTNUMBER(odin)
})
evt_variables += SelectionInfo("Hlt2", hlt2_dec, [line_name])
#For now remove: The 'Hlt2' line decision tuples fine but breaks unit test with an error. (Why?)
#see linked issue here: https://gitlab.cern.ch/lhcb/DaVinci/-/merge_requests/654#note_5320732
evt_variables.pop('Sel')
evt_variables.pop('Hlt2')
#define FunTuple instance
my_tuple = Funtuple(
......
......@@ -50,11 +50,10 @@ variables = {
def main():
d02kpi_data = force_location(
"/Event/HLT2/Hlt2CharmD0ToKmPipLine/Particles")
line_name = 'Hlt2CharmD0ToKmPipLine'
d02kpi_data = force_location(f"/Event/HLT2/{line_name}/Particles")
my_filter = add_filter("HDRFilter_D0Kpi",
"HLT_PASS('Hlt2CharmD0ToKmPipLineDecision')")
my_filter = add_filter("HDRFilter_D0Kpi", f"HLT_PASS('{line_name}')")
my_tuple = Funtuple(
name="Tuple",
tuple_name="DecayTree",
......
......@@ -34,7 +34,7 @@ variables = {
def main():
filter_bs = add_filter("HDRFilter_Bs2JpsiPhi",
f"HLT_PASS('{bs2jpsiphi_line}Decision')")
f"HLT_PASS('{bs2jpsiphi_line}')")
tuple_bs = Funtuple(
name="Bs2JpsiPhi_Tuple",
......
......@@ -18,10 +18,10 @@ from PyConf.components import force_location
from DaVinci.algorithms import add_filter
from DaVinci import options
bd2dsk_line = force_location(
"/Event/Spruce/SpruceB2OC_BdToDsmK_DsmToHHH_FEST_Line/Particles")
bd2dspi_line = force_location(
"/Event/Spruce/SpruceB2OC_BdToDsmPi_DsmToKpKmPim_Line/Particles")
line_B0DsK = 'SpruceB2OC_BdToDsmK_DsmToHHH_FEST_Line'
line_B0Dspi = 'SpruceB2OC_BdToDsmPi_DsmToKpKmPim_Line'
bd2dsk_line = force_location(f"/Event/Spruce/{line_B0DsK}/Particles")
bd2dspi_line = force_location(f"/Event/Spruce/{line_B0Dspi}/Particles")
fields_dsk = {
'B0': "[B0 -> D_s- K+]CC",
......@@ -91,12 +91,9 @@ def main():
options.ntuple_file = "DV_example_sprucing_ntp.root"
options.histo_file = "DV_example_sprucing_his.root"
filter_B0DsK = add_filter(
"HDRFilter_B0DsK",
"HLT_PASS('SpruceB2OC_BdToDsmK_DsmToHHH_FEST_LineDecision')")
filter_B0Dspi = add_filter(
"HDRFilter_B0Dspi",
"HLT_PASS('SpruceB2OC_BdToDsmPi_DsmToKpKmPim_LineDecision')")
filter_B0DsK = add_filter("HDRFilter_B0DsK", f"HLT_PASS('{line_B0DsK}')")
filter_B0Dspi = add_filter("HDRFilter_B0Dspi",
f"HLT_PASS('{line_B0Dspi}')")
tools = []
algs = {
......
......@@ -34,10 +34,10 @@ variables = {
def main():
B_data = force_location("/Event/Spruce/Spruce_Test_line/Particles")
line_name = 'Spruce_Test_line'
B_data = force_location(f"/Event/Spruce/{line_name}/Particles")
my_filter = add_filter("HDRFilter_B",
"HLT_PASS('Spruce_Test_lineDecision')")
my_filter = add_filter("HDRFilter_B", f"HLT_PASS('{line_name}')")
#get configured "MCTruthAndBkgCatAlg" algorithm for HLT2 output
mctruth = configured_MCTruthAndBkgCatAlg(inputs=B_data)
......
###############################################################################
# (c) Copyright 2001-2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
#[=======================================================================[.rst:
DaVinciTutorials
----------------
#]=======================================================================]
gaudi_install(PYTHON)
gaudi_add_tests(QMTest)
# About
The tutorials have originally been developed for the LHCb [starter-kit](https://indico.cern.ch/event/1124730/timetable/#20220316) that took place in March 2022.
The tutorials are accompanied by [slides](https://indico.cern.ch/event/1124730/timetable/#20220316) and [recordings](https://videos.cern.ch/record/2295643).
Note that in the slides and recordings, the tutorials have been labelled differently to what is present here (the slides and recordings will be updated for the next `starterkit` lesson).
# Setup
To setup, either build your own [stack](https://gitlab.cern.ch/rmatev/lb-stack-setup) for DaVinci (WARNING: Takes a very long time to build. Only recommended if you are doing development work)
```bash
#Go to home or any directory of your choice
cd $HOME
#set up the stack
curl https://gitlab.cern.ch/rmatev/lb-stack-setup/raw/master/setup.py | python3 - stack
#compile DaVinci (DV) master
cd stack && make DaVinci
```
or use the `lb-dev` command i.e.
```bash
#Go to home or any directory of your choice
cd $HOME
#Note that you might run into trouble if DaVinci hasn't yet been built in the latest lhcb-head slot.
# You can check if it has been built or not here: https://lhcb-nightlies.web.cern.ch/nightly/
# In which case you can simply use the previous slot number e.g. "--nightly lhcb-head/3270".
lb-dev -c x86_64_v2-centos7-gcc11-opt --nightly lhcb-head DaVinci/HEAD --name DV
cd DV
git lb-use DaVinci
git lb-checkout DaVinci/master DaVinciTutorials
make
```
Let us setup the required paths to the DaVinci tutorials directory using the `stack` method (for `lb-dev` method change `DVPATH` accordingly)
```bash
#path to DaVinci (using stack method, for lb-dev method DVPATH="$HOME/DV")
DVPATH="$HOME/stack/DaVinci"
#path to starterkit examples
TUTORIALSPATH="$DVPATH/DaVinciTutorials/python"
```
In the lesson, we will be using the `Turbo` upgrade simulation sample analysing the decays of `Bs0->J/psi (-> mu+ mu-) phi (-> K+ K-)`.
The simulation samples can either be in the local directory or at CERN EOS.
Here our example DST file (`hlt2_passthrough_thor_lines.dst`) and accompanying configuration file (`hlt2_passthrough_thor_lines.tck.json`) are both at CERN EOS (see `jobopts.yaml` file).
<!--For the hands-on session, we will be using a 'Spruce' upgrade simulation sample analysing the decays of `Bc -> Bs0 pi+`. Simulation sample obtained from Spruce line output (`spruce_exclusive_BcToBspi.dst`) and configuration file (`spruce_exclusive.tck.json`) are also at CERN EOS (see `jobopts_spruce.yaml` file).-->
# Tutorial0: Running a simple DaVinci job
Objectives:
- Running the basic example using the [`click`](https://click.palletsprojects.com/en/8.0.x/) based DaVinci configuration.
- Creating templates for `jobopts.yaml` and `dataprops.yaml`.
- Configuring DV job with `jobopts.yaml` and data properties using `dataprops.yaml`.
- Function that returns a sequence of user defined algorithms.
Command to run the tutorial:
```bash
cd $TUTORIALSPATH
$DVPATH/run davinci run-mc -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial0_basic_DVjob:main
```
# Tutorial1: FunTuple basic ThOr functors and special field name
Objectives:
- Basic configuration of `FunTuple`.
- Defining a collection of `ThOr` functors (`FunctorCollection`).
- Configuring the `fields` attribute of `FunTuple`.
- Usage of special field name `ALL`.
- Inspecting C++ string representation of `ThOr` functors.
- Loading particles in the event from `.dst` onto Transient Event Store (TES) location.
- Usage of event filter (mainly to get over a technical hurdle).
Command to run the tutorial:
```bash
cd $TUTORIALSPATH
#see particle properties (for names, properties, etc)
$DVPATH/run dump_ParticleProperties -t Upgrade | tee ParticleTable.txt
#run example
$DVPATH/run davinci -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial1_functors_specialfield:main
```
External links:
- Decay descriptors: https://twiki.cern.ch/twiki/bin/view/LHCb/FAQ/LoKiNewDecayFinders
- `ThOr` documentation: https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors.html
- [List](https://gitlab.cern.ch/lhcb/Rec/-/blob/master/Phys/FunctorCore/python/Functors/__init__.py) of available `ThOr` functors.
# Tutorial2: LoKi functors
Objectives:
- Defining a collection of `LoKi` functors together with `ThOr` functors.
- Defining a LoKi preamble for a complex LoKi functor to be used in `FunctorCollection`.
Command to run the tutorial:
```bash
#run example
$DVPATH/run davinci -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial2_LoKi:main
```
External links:
- `LoKi` official page: http://lhcb-comp.web.cern.ch/Analysis/Loki/index.html
- `LoKi` starter-kit page: https://lhcb.github.io/starterkit-lessons/first-analysis-steps/loki-functors.html
# Tutorial3: ThOr functors (Data dependence, arguments and return types)
Objectives:
- Loading primary vertices (PVs) onto TES, which is passed to data dependent `ThOr` functors in `FunTuple` e.g. `F.BPVIPCHI2(pvs)`.
- Functors returning three and four vectors e.g. `F.BPVFDVEC(pvs)` that returns `3-vector`.
- Usage of functors taking other arguments such as other functors `func` e.g. `F.CHILD(1,func)`, `F.SUM(func)`, `F.SUMCOMB(func,Indices)`, `F.MASSWITHHYPOTHESES(('K+', 'K-')`.
- Basic maths operators with functor returning scalars e.g. `CHILD_2(F.END_VZ) - F.END_VZ`, which returns difference in end vertex of child and mother.
Command to run the tutorial:
```bash
#run example
$DVPATH/run davinci -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial3_ThOrfunctors:main
```
# Tutorial4: Usage of pre-defined `functorcollections`, storing trigger and event-level information
Objectives:
- Usage of pre-defined `functorcollections`, inspecting and manipulating them before loading it onto `FunTuple`.
- Exploring few simple methods of `FunctorCollection` class.
- Storing event-level information with `functorcollection` e.g. RunNumber, EventNumber, etc.
- Storing trigger (`Hlt1`, `Hlt2` and `Sprucing`) information with `functorcollection` e.g. line decisions, Trigger Configuration Key (TCK).
Command to run the tutorial:
```bash
#run example
$DVPATH/run davinci -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial4_trigger_eventinfo:main
```
External links:
- The `Hlt1` decisions can be stored in similar way to `Hlt2` and `Spruce` (see example `option_trigger_decisions` in `DaVinciExamples` folder). For details, can also refer to the [talk](https://indico.cern.ch/event/1164051/#5-accessing-hlt1-decisions-usi) (The talk mentions that to persist Hlt1 decisions, one needs to add few options to the Moore script).
- List of currently available `functorcollections` are [here](https://gitlab.cern.ch/lhcb/Analysis/-/blob/master/Phys/FunTuple/python/FunTuple/functorcollections.py) and the planned ones are [here](https://gitlab.cern.ch/lhcb-dpa/project/-/issues/178).
# Tutorial5: MC truth association and background category algorithm
Objectives:
- Configuring the MC association and background category algorithm (`MCTruthAndBkgCatAlg`) to build a relation table. For MC association, the table is essentially a map between reconstructed particles and "truth" particles (MCParticle).
- Usage of the relations table and `ThOr` functor handling such table (e.g. `F.MAP_INPUT(func, RelTable`) to get truth information and background category.
- Also explore `functorcollections` such as `MCKinematics`, `MCHierarchy`, etc.
Command to run the tutorial:
```bash
#run example
$DVPATH/run davinci -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial5_MCTruth:main
```
# Tutorial6: Decay Tree Fitter (DTF) algorithm
Objectives:
- Configuring the Decay Tree Fitter algorithm (`DecayTreeFitterAlg`) to build a relation table i.e. map between the candidate and the refitted candidate.
- Usage of the relations table and `ThOr` functor (e.g. `F.MAP_INPUT(func, RelTable`) to get refitted information of the candidate.
- Defining different instances of DTF algorithm with mass constraints, primary vertex constraint.
Command to run the tutorial:
```bash
#run example
$DVPATH/run davinci -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial6_DecayTreeFit:main
```
External links on decay tree fitter:
- Paper: https://inspirehep.net/literature/679286
- Twiki : https://twiki.cern.ch/twiki/bin/view/LHCb/DecayTreeFitter
- Starter-kit: https://lhcb.github.io/starterkit-lessons/first-analysis-steps/decay-tree-fitter.html
- Slides by Wouter: https://www.nikhef.nl/~wouterh/topicallectures/TrackingAndVertexing/part6.pdf
# Tutorial7: Defining different instances of FunTuple when analysing outputs of multiple selection lines
Objectives:
- Defining different instances of FunTuple to return different `TDirectory` in the output ROOT file.
- Changes to the function returning user algorithm "sequence" to allow for this.
Command to run the tutorial:
```bash
#run example Turbo but with two decays
$DVPATH/run davinci -i bs2jpsiphi_turbo dataprops.yaml -j jobopts_turbo.yaml --user_algorithms tutorial7_multiple_sel_lines:main
```
\ No newline at end of file
###############################################################################
# (c) Copyright 2021-2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
bs2jpsiphi_turbo:
filenames:
- 'root://eoslhcb.cern.ch//eos/lhcb/wg/dpa/wp3/tests/hlt2_passthrough_thor_lines.dst'
qualifiers:
data_type: Upgrade
input_type: DST
simulation: true
conddb_tag: sim-20180530-vc-md100
dddb_tag: dddb-20180815
\ No newline at end of file
###############################################################################
# (c) Copyright 2021-2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
# Template job option YAML file.
# Best guesses are provided below for various options. Please adapt as per your needs.
annsvc_config: 'root://eoslhcb.cern.ch//eos/lhcb/wg/dpa/wp3/tests/hlt2_passthrough_thor_lines.tck.json'
evt_max: -1
ntuple_file: 'ntuple_turbo.root'
enable_unpack: True
process: 'Turbo'
print_freq: 1
\ No newline at end of file
###############################################################################
# (c) Copyright 2021-2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
####
# tutorial0_basic_DVjob: Running simple example of a DaVinci job.
#
# Run this with (assumes TUTORIALSPATH and DVPATH are already set, see README.md):
# - cd $TUTORIALSPATH
# - $DVPATH/run davinci run-mc -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial0_basic_DVjob:main
#####
from PyConf.Algorithms import PrintDecayTree
from PyConf.components import force_location
from DaVinci.algorithms import add_filter
#Import davinci options and overwrite "ntuple_file" option in "jobopts.yaml"
from DaVinci import options
options.ntuple_file = '' #no tuple written out
options.evt_max = 100
#Load data from dst onto a "temporary" TES (Transient Event Store) location for a given event cycle.
# We loop over the algorithms event-by-event, so for given event cycle, TES maps "path" to an "object".
# For the TES path checkout spruce_passthrough.tck.json or you can do a dst dump
# (see https://lhcb.github.io/starterkit-lessons/first-analysis-steps/interactive-dst.html)
#
# The TES location input to the algorithms must of type "PyConf.DataHandle" and not pure strings.
# Therefore we wrap the TES location string below with "force_location" wrapper class.
turbo_line = "Hlt2BsToJpsiPhi_JPsi2MuMu_PhiToKK_Line"
input_data = force_location(f"/Event/HLT2/{turbo_line}/Particles")
#Add a filter: We are not really filtering over particles, we are getting over a technical hurdle here.
# The hurdle being that if the event hasn't fired a HLT2 line then no TES location exists
# and therefore if any algorithm tries to look for this location, we run into a problem.
# Side step this issue with a filter, where:
# - 1st argument is a user defined name.
# - 2nd argument is the line decision (simply append "Decision" to your HLT2 line name (or inspect hlt2_starterkit.tck.json))
my_filter = add_filter("HDRFilter_SeeNoEvil", f"HLT_PASS('{turbo_line}')")
# Defining an algorithm. The alorithm here prints the decaytree
pdt = PrintDecayTree(name="PrintBsToJpsiPhi", Input=input_data)
def main():
#Define tools (no tools used here)
tools = []
#Define dictionary of algorithms: "algorithm sequence name" -> list of algorithms run sequentially. By default an algorithm is only run if the previous in sequence finds something.
algs = {"Alg": [my_filter, pdt]}
#Return them
return algs, tools
###############################################################################
# (c) Copyright 2021-2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
#####
# tutorial1_functors_specialfield: Tupling with LoKi and ThOr functors
#
# Run this with (assumes TUTORIALSPATH and DVPATH are already set, see README.md):
# - cd $TUTORIALSPATH
# - $DVPATH/run davinci run-mc -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial1_functors_specialfield:main
#####
#Import necessary packages and functions
from FunTuple import FunTuple_Particles as Funtuple
from FunTuple import FunctorCollection as FC
import Functors as F
from DaVinci.algorithms import add_filter
from PyConf.application import force_location
#Import davinci options and overwrite "ntuple_file" option in "jobopts.yaml"
from DaVinci import options
options.ntuple_file = 'tutorial1_functors_specialfield.root'
options.evt_max = 100
#Define a dictionary of "field name" -> "decay descriptor component".
# - For particle properties, names, etc checkout "ParticleTable.txt"
# that can be obtained via command "$DVPATH/run dump_ParticleProperties -t Upgrade | tee ParticleTable.txt".
# - For decay descriptor info see for example https://twiki.cern.ch/twiki/bin/view/LHCb/FAQ/LoKiNewDecayFinders
# If your decay is self-tagged (which is the most common case) then you will need "[<decay-descriptor>]CC"
fields = {
"Bs": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ K-)",
"Jpsi": "B_s0 -> ^(J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ K-)",
"Phi": "B_s0 -> (J/psi(1S) -> mu+ mu-) ^(phi(1020) ->K+ K-)",
"Mup": "B_s0 -> (J/psi(1S) ->^mu+ mu-) (phi(1020) ->K+ K-)",
"Mum": "B_s0 -> (J/psi(1S) -> mu+ ^mu-) (phi(1020) ->K+ K-)",
"Kp": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->^K+ K-)",
"Km": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ ^K-)",
}
#Define a collection of functors called FunctorCollection, which takes dictionary of "variable name" -> "ThOr" functor
# (Can also be a "LoKi" functor see next tutorial).
# For more info on ThOr see https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors.html#functor-cache
# For list of ThOr functors see https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors_reference.html
# Here we define functor collection to be added to "ALL" fields (Bs, Jpsi, Phi, etc)
all_vars = FC({
"THOR_P": F.P, #ThOr momentum functor
"ID": F.
PARTICLE_ID, #Refer to "ParticleTable.txt" for particle ID (see above on how to get this file)
})
#define functors to be added only to Bs and Jpsi fields
bs_jpsi_fun = FC({"PT_THOR": F.PT, "PX": F.PX, "PY": F.PY})
#Define variables dictionary "field name" -> Collections of functor.
# "ALL" is a special field name that adds PT to all the fields defined above (i.e. Bs,Jpsi,Mup,Mum,Kp,Km)
variables = {
"ALL": all_vars,
"Bs": bs_jpsi_fun,
"Jpsi": bs_jpsi_fun,
}
#Inspect string representation of ThOr Functor
# This string representation is converted to C++ object
# using gcc or FunctorCache see https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors.html#functors-in-a-selection-framework
print(F.PT.code())
#print(F.PT.headers())
print(F.PT.code_repr())
#Define the TES location (see previous example for explanation)
turbo_line = "Hlt2BsToJpsiPhi_JPsi2MuMu_PhiToKK_Line"
input_data = force_location(f"/Event/HLT2/{turbo_line}/Particles")
#Define a filter (see previous example for explaination)
my_filter = add_filter("HDRFilter_SeeNoEvil", f"HLT_PASS('{turbo_line}')")
#Define instance of FunTuple
mytuple = Funtuple(
"TDirectoryName", # name of directory in ROOT file
"TTreeName", # name of TTree
fields=fields, # dictionary of particle : decay descriptor
variables=variables, # dictionary of particle : variables to insert in TTree
inputs=input_data) # input data
def main():
#Define tools (no tools used here)
tools = []
#Define dictionary of algorithms: "algorithm sequence name" -> list of algorithms run sequentially
algs = {"Alg": [my_filter, mytuple]}
#Return them
return algs, tools
###############################################################################
# (c) Copyright 2021-2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
#####
# tutorial2_LoKi: Usage of LoKi functors together with ThOr
#
# Run this with (assumes TUTORIALSPATH and DVPATH are already set, see README.md):
# - cd $TUTORIALSPATH
# - $DVPATH/run davinci run-mc -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial2_LoKi:main
#####
from FunTuple import FunTuple_Particles as Funtuple
from FunTuple import FunctorCollection as FC
import Functors as F
from DaVinci.algorithms import add_filter
from PyConf.application import force_location
#Import davinci options and overwrite "ntuple_file" option in "jobopts.yaml"
from DaVinci import options
options.ntuple_file = 'tutorial2_LoKi.root'
options.evt_max = 100
#Define a dictionary of "field name" -> "decay descriptor component".
fields = {
"Bs": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ K-)",
"Jpsi": "B_s0 -> ^(J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ K-)",
"Phi": "B_s0 -> (J/psi(1S) -> mu+ mu-) ^(phi(1020) ->K+ K-)",
"Mup": "B_s0 -> (J/psi(1S) ->^mu+ mu-) (phi(1020) ->K+ K-)",
"Mum": "B_s0 -> (J/psi(1S) -> mu+ ^mu-) (phi(1020) ->K+ K-)",
"Kp": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->^K+ K-)",
"Km": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ ^K-)",
}
#Define a collection of functors called FunctorCollection, which takes dictionary of "variable name" -> "LoKi" or "ThOr" functor
# For more info on ThOr see https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors.html#functor-cache
# For list of ThOr functors see https://lhcbdoc.web.cern.ch/lhcbdoc/moore/master/selection/thor_functors_reference.html
# For information on LoKi functor see https://lhcb.github.io/starterkit-lessons/first-analysis-steps/loki-functors.html
mom_fun = FC({
"THOR_PT": F.PT,
"THOR_PX": F.PX,
"THOR_PY": F.PY,
"LOKI_PT": 'PT', #LoKi functor code is represented in a string
"LOKI_PX": 'PX',
"LOKI_PY": 'PY'
})
#Define a LoKi preamble (Note that one can define preambles in ThOr using python lambda function see next tutorial or via FunctorComposition)
# i.e. rename a complex LoKi functor to a user deinfed name (e.g. TRACK_MAX_PT)
# This helps us to use "TRACK_MAX_PT" when constructing FunctorCollection
loki_preamble = ['TRACK_MAX_PT = MAXTREE(ISBASIC & HASTRACK, PT, -1)']
#define collections to be added to fields
max_pt_fun = FC({
"MAX_PT_LOKI": "TRACK_MAX_PT", #LoKi
"MAX_PT_THOR": F.MAX(
F.PT
) #ThOr (not equivalent, sum of pT of composites not basic). MAXTREE ThOr doesn't exist yet.
})
#Define variables dictionary "field name" -> Collections of functor.
variables = {
"ALL": mom_fun,
"Bs": max_pt_fun,
"Jpsi": max_pt_fun,
"Phi": max_pt_fun,
}
#Load data from dst onto a TES
turbo_line = "Hlt2BsToJpsiPhi_JPsi2MuMu_PhiToKK_Line"
input_data = force_location(f"/Event/HLT2/{turbo_line}/Particles")
#Add a filter
my_filter = add_filter("HDRFilter_SeeNoEvil", f"HLT_PASS('{turbo_line}')")
#Define instance of FunTuple
mytuple = Funtuple(
"TDirectoryName",
"TTreeName",
fields=fields,
variables=variables,
loki_preamble=loki_preamble, #optional argument
inputs=input_data)
def main():
#Define tools (no tools used here)
tools = []
#Define dictionary of algorithms: "algorithm sequence name" -> list of algorithms run sequentially
algs = {"Alg": [my_filter, mytuple]}
#Return them
return algs, tools
###############################################################################
# (c) Copyright 2021-2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
#####
# tutorial3_ThOrfunctors: Usange of data dependent ThOr functors, arguments to ThOr functors and vector functors
#
# Run this with (assumes TUTORIALSPATH and DVPATH are already set, see README.md):
# - cd $TUTORIALSPATH
# - $DVPATH/run davinci run-mc -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial3_ThOrfunctors:main
#####
from FunTuple import FunTuple_Particles as Funtuple
from FunTuple import FunctorCollection as FC
import Functors as F
from DaVinci.algorithms import add_filter
from PyConf.application import force_location
from DaVinci.reco_objects import make_pvs_v2
#Import davinci options and overwrite "ntuple_file" option in "jobopts.yaml"
from DaVinci import options
options.ntuple_file = 'tutorial3_ThOrfunctors.root'
options.evt_max = 100
#Define a dictionary of "field name" -> "decay descriptor component".
# Can get daughter information from the head of the decay using F.CHILD functors see below.
fields = {
"Bs": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ K-)",
"Phi": "B_s0 -> (J/psi(1S) -> mu+ mu-) ^(phi(1020) ->K+ K-)",
"Kp": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->^K+ K-)",
"Km": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ ^K-)",
}
#Load PVs onto TES from data, like we did with input_data below
# Creating v2 reconstructed vertices to be used in the following functor
# For the time being there's a mix of legacy and v2 event classes. That will eventually be cleaned once the
# event model is fixed. In the meantime there are helper functions in DaVinci.
pvs = make_pvs_v2(process=options.process)
#Evaluate the impact parameter
all_vars = {}
#The ThOr functor F.BPVIPCHI2 is data dependent. It takes as input list of pvs.
#It calculates impact parameter chisq wrt best PV.
# - best PV is the PV which fits best the FD of the B candidate.
# - impact parameter chisq is the difference in the vertex-fit chisq of a given PV reconstructed with and w/o the track under consideration.
all_vars['BPVIPCHI2'] = F.BPVIPCHI2(pvs)
#define dictionary
bs_vars = {}
#Tupling vector functors
# Some functors could also return std::map<std::string, std::any> (e.g. F.DECISIONS(Lines=line_names, DecReports=dec_report))
bs_vars['BPVFDVEC_'] = F.BPVFDVEC(pvs) #Returns 3-vector
bs_vars['FOURMOM_P'] = F.FOURMOMENTUM #Returns 4-vector
#define some helpful lambda function to simplify syntax
# This is bit like LoKi preamble of renaming functors that we encountred in previous tutorial.
CHILD_1 = lambda func: F.CHILD(1, func)
CHILD_2 = lambda func: F.CHILD(2, func)
SUBCOMB_12 = lambda func: F.SUBCOMB(Functor=func, Indices=(1, 2))
#Store the ID of the two daughters of B_s0
bs_vars['jpsi_ID'] = CHILD_1(F.PARTICLE_ID)
bs_vars['phi_ID'] = CHILD_2(F.PARTICLE_ID)
bs_vars['Kp_ID'] = CHILD_2(CHILD_1(F.PARTICLE_ID))
#Calculate sum of pT of jpsi daughter tracks
bs_vars['jpsi_TRACKSUMPT'] = CHILD_1(F.SUM(F.PT))
#Calculate impact parameter of K+
bs_vars['Kp_BPVIP'] = CHILD_2(CHILD_1(F.BPVIP(pvs)))
#Calculate invariant mass of K+ and K- combination
bs_vars['phi_M_comb'] = CHILD_2(SUBCOMB_12(F.MASS))
#Calculate the difference in end vertex between phi and Bs
bs_vars['Delta_END_VZ_PhiBs0'] = CHILD_2(F.END_VZ) - F.END_VZ
#Calculate inv mass of K+pi- where the K- is given the mass hypothesis of pi-
bs_vars['phi_mass_kpi'] = CHILD_2(F.MASSWITHHYPOTHESES(('K+', 'pi-')))
#Calculate inv mass of K+K-
# There three functors for computing this i.e. F.MASS, CHILD_2(SUBCOMB_12(F.MASS)) and CHILD_2(F.MASSWITHHYPOTHESES(('K+', 'K-'))) but why?
# (see issue: https://gitlab.cern.ch/lhcb/Rec/-/issues/307)
bs_vars['phi_mass_kk'] = CHILD_2(F.MASSWITHHYPOTHESES(('K+', 'K-')))
all_vars['M'] = F.MASS
#Define variables dictionary "field name" -> Collections of functor
variables = {
"ALL": FC(all_vars),
"Bs": FC(bs_vars),
}
#Load data from dst onto a TES
turbo_line = "Hlt2BsToJpsiPhi_JPsi2MuMu_PhiToKK_Line"
input_data = force_location(f"/Event/HLT2/{turbo_line}/Particles")
#Add a filter
my_filter = add_filter("HDRFilter_SeeNoEvil", f"HLT_PASS('{turbo_line}')")
#Define instance of FunTuple
mytuple = Funtuple(
"TDirectoryName",
"TTreeName",
fields=fields,
variables=variables,
inputs=input_data)
def main():
#Define tools (no tools used here)
tools = []
#Define dictionary of algorithms: "algorithm sequence name" -> list of algorithms run sequentially
algs = {"Alg": [my_filter, mytuple]}
#Return them
return algs, tools
###############################################################################
# (c) Copyright 2021-2022 CERN for the benefit of the LHCb Collaboration #
# #
# This software is distributed under the terms of the GNU General Public #
# Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". #
# #
# In applying this licence, CERN does not waive the privileges and immunities #
# granted to it by virtue of its status as an Intergovernmental Organization #
# or submit itself to any jurisdiction. #
###############################################################################
#####
# tutorial4_trigger_eventinfo: Usage of pre-defined FunctorCollection, storing trigger and event level information
#
# Run this with (assumes TUTORIALSPATH and DVPATH are already set, see README.md):
# - cd $TUTORIALSPATH
# - $DVPATH/run davinci run-mc -i bs2jpsiphi_turbo dataprops.yaml -j jobopts.yaml --user_algorithms tutorial4_trigger_eventinfo:main
#####
from FunTuple import FunTuple_Particles as Funtuple
from FunTuple import FunctorCollection as FC
import Functors as F
from DaVinci.algorithms import add_filter
from PyConf.application import force_location
#Import davinci options and overwrite "ntuple_file" option in "jobopts.yaml"
from DaVinci import options
options.ntuple_file = 'tutorial4_trigger_eventinfo.root'
options.evt_max = 100
#Define a dictionary of "field name" -> "decay descriptor component".
fields = {"Bs": "B_s0 -> (J/psi(1S) -> mu+ mu-) (phi(1020) ->K+ K-)"}
#To help users, there are pre-defined FunctorCollections (Tuple-tool like objects for Run1/2 veterans) that you can import and inspect.
# Here we import a pre-defined FunctorCollection "Kinematics".
# One can call "print(help(Kinematics))" (you have to press "q" to exit after calling) to check the usage and their arguments.
# Functors that have data dependency will naturally induce data dependency on the functorcollections.
#
# To see what functor collections are available see: https://gitlab.cern.ch/lhcb/Analysis/-/blob/master/Phys/FunTuple/python/FunTuple/functorcollections.py
from FunTuple.functorcollections import Kinematics
#Inspect whats in the collection by printing
kin = Kinematics()
print(kin)
#Define new collection
coll = FC({"ID": F.PARTICLE_ID})
#Add to existing collections (can also subtract two collections)
kin += coll
#Remove from collections
kin.pop(['PX', 'PT', 'PZ', 'PY', 'ENERGY'])
print(kin)
#Can also obtain a pure dictionary from collections via
# - kin.functor_dict (Contains both LoKi and ThOr)
# - kin.get_thor_functors()
# - kin.get_loki_functors()
print(kin.functor_dict)
print(kin.get_thor_functors())
print(kin.get_loki_functors()
) #empty dictionary since we have no LoKi functors in the collection
#Now import two other pre-defined FunctorCollections: SelectionInfo and EventInfo
# - SelectionInfo: Contains functors related to storing Hlt1, Hlt2 or Sprucing trigger line decision and Trigger Configuration Key (TCK).
# - EventInfo: Contains functors related to storing event information EVENTNUMBER, RUNNUMBER, GPSTIME, etc.
#
#As before you can call help with "print(help(EventInfo))" or "print(help(SelectionInfo))" (you have to press "q" to exit after calling)
from FunTuple.functorcollections import SelectionInfo, EventInfo
#Get event information like RUNNUMBER, EVENTNUMBER.
# These are stored in "LHCb::ODIN" C++ object which the ThOr functors take as input (like PVs in Example7), load it onto TES using "get_odin".
# The attribute extra_info is False by default, if set to "True" you get info on
# bunchcrossing id, ODIN TCK, GPS Time, etc
from DaVinci.algorithms import get_odin
odin = get_odin(options)
evtinfo = EventInfo(odin, extra_info=False)
print(evtinfo)
#Get selection line decision and HlT2 TCK.
# These decisions are stored in "LHCb::HltDecReports" object, which the ThOr functors take as input (like PVs in Example7), load it onto TES using "get_decreports".
# The function "get_decreports" takes as input:
# - sel_type: Type of selection "Hlt2" or "Spruce"
# - line_names: list of line decision in this instance HLT2 line. Should return True for all since we are using the output of this line.
#
# The `Hlt1` decisions can be stored in similar way to `Hlt2` and `Spruce`
# (see example `option_trigger_decisions` in `DaVinciExamples` folder).
# For details, can also refer to the [talk](https://indico.cern.ch/event/1164051/#5-accessing-hlt1-decisions-usi)
# (The talk mentions that to persist Hlt1 decisions, one needs to add few options to the Moore script).
from DaVinci.algorithms import get_decreports
sel_type = "Hlt2" #User defined and will be used as prefix for TBranch in the root file
dec_report = get_decreports(sel_type, options)
turbo_line = "Hlt2BsToJpsiPhi_JPsi2MuMu_PhiToKK_Line"
turbo_line2 = "Hlt2BsToJpsiPhi_JPsi2ee_PhiToKK_Line"
line_names = [f'{turbo_line}Decision', f'{turbo_line2}']
selinfo = SelectionInfo(sel_type, dec_report, line_names)
print(selinfo)
#Define variables dictionary "field name" -> Collections of functor
variables = {"ALL": kin}
#Load data from dst onto a TES
input_data = force_location(f"/Event/HLT2/{turbo_line}/Particles")
#Add a filter
my_filter = add_filter("HDRFilter_SeeNoEvil", f"HLT_PASS('{turbo_line}')")
#Define instance of FunTuple
mytuple = Funtuple(
"TDirectoryName",
"TTreeName",
fields=fields,
variables=variables,
event_variables=evtinfo + selinfo,
inputs=input_data)
def main():
#Define tools (no tools used here)
tools = []
#Define dictionary of algorithms: "algorithm sequence name" -> list of algorithms run sequentially
algs = {"Alg": [my_filter, mytuple]}
#Return them
return algs, tools