This page will be populated with Frequently Asked Questions concerning
LoKi.
Add your own Question
Did you not find the answer you were looking for? If not please submit your question here.
Current user-submitted FAQ's can be found
here
What/Who is LoKi
- LoKi is C++ ToolKit for Smart and Simple Physics Analysis. All available documentation is linked from the LoKi pages
and/or LoKi portal
- Loki is a god of wit and mischief in Norse mythology
- LoKi could be interpreted as Loops&Kinematics
Where could I find the proper documentation?
What LoKi functors are recommended for usage withing CombineParticles/FilterDesktop framework?
The list
LoKi functors which are recommended for usage withing
CombineParticles/FilterDesktop framework can be inspected
here.
How to use MC-truth matching inside CombineParticles/FilterDesktop framework?
The usage of MC-truth inside
CombineParticles/FilterDesktop framwork is fairly trivial, e.g.
1000MyAlg = CombineParticles ( ... ... DaughterCuts = { 'K+' : " ( PT > 1 * GeV ) & mcMatch ( ' phi(1020) => ^K+ ^K-' ) " , 'mu+' : " (PT > 1 * GeV) & mcMatch ( 'J/psi(1S) => ^mu+ ^mu-' ) " } ,
1010
1020Preambulo = [ "from LoKiPhysMC.decorators import *" , "from LoKiPhysMC.functions import mcMatch" ]
1030
1040)
For the exampe above , only the recontructed kaons, matched with true MC-kaons from decays of

, and the recontructed muons, matched with true MC-muons form the decay

will be selected. (Note: The indefinite amount of soft photons from the internal bremstrahlung, produced by
PHOTOS
generator is allowed. For more detaild about the decay descripor see
here)
The "selector" of MC-particles (the first argument of
mcMatch
function) can be defined in many different ways:
- it can be string decay descriptor, see here and here
- it can be tree or node object, see here
- it can be predicate acting on Monte Carlo particles
For the actual details of MC-truth matching algorithm in
LoKi please consult
LoKi User Guide The defaulmatching is done using the protoparticles. To customize the MC-matching one can specif the TES-locations of relation tables as helper arguments of
mcMatch
functions. The following relation table typoes are supported ( see
$LOKIPHYSMCROOT/LoKi/PhysMCTypes.h
file):
-
LoKi::Types::TableP2MC
-
LoKi::Types::TableP2MCW
-
LoKi::Types::TablePP2MC
-
LoKi::Types::TableT2MC
-
LoKi::Types::TableT2MCW
More detailed example is available
here
How to study the background composition with LoKi?
LoKi offers many suitabel ways to study the background compostion. One of the most powerful tool is algorithm
LoKi::DecayTruth
(known as
LoKiDecayTruth
in DC04 branch of software). The algorithm has been adapted to DC06 software line by
Lesya SHCHUTSKA.
The algorithm has been adapted to DC06 software line by Lesya SHCHUTSKA.
LoKi::DecayTruth
algorithm
This algorithm allows to study the MC-truth for the selected signal candidates through rather intensive printout. For the channels with no photons, one can inspect up to O(50) events, while for channels with photons the inspection of more than 20 events is rather painful. The usage of the algorithm is rather trivial, one just need to specify the TES location with the selected signal candidates and the list of "interesting" PIDs:
// add the algorithm into the list of top-level algorithm for Gaudi: ApplicationMgr.TopAlg += { "LoKi::DecayTruth/MCTruth" } ;
// define the location of signal candidates: MCTruth.Desktop.InputLocations = { "Phys/MySignalBCandidates" } ;
// define the "interesting" PIDs: MCTruth.Particles = { "B_s0" , "B_s~0"} ;
If the decay channel under the interest does not contain photons, to speedup the program a bit one can disable the MC-mathching for the photons:
// OPTIONALLY, if decay does not contains PHOTONS: MCTruth.PP2MCPs = { "Relations/Rec/ProtoP/Charged" };
The algorithm is rather simple. E.g. for the selected candidates

-candidates from the file which contains

followed by

,

algorithm prints the information about all recontructed

-candidates (in our case only one candidate is found):
MCTruth SUCCESS Reconstructed B_s0 #1/1 (key:4)
0 |->B_s0 E/PX/PY/PZ: 107.7 / 4.726 / -6.533 / 107.3 [GeV] # 4
1 |->J/psi(1S) E/PX/PY/PZ: 58.19 / 1.094 / -3.776 / 57.97 [GeV] # 0
2 |->mu+ E/PX/PY/PZ: 46.18 / 1.057 / -4.239 / 45.97 [GeV] # 1
2 |->mu- E/PX/PY/PZ: 12 / 0.01673 / 0.4615 / 11.99 [GeV] # 0
1 |->phi(1020) E/PX/PY/PZ: 49.52 / 3.632 / -2.749 / 49.3 [GeV] # 1
2 |->K+ E/PX/PY/PZ: 20.08 / 1.49 / -1.17 / 19.98 [GeV] # 0
2 |->K- E/PX/PY/PZ: 29.43 / 2.141 / -1.579 / 29.3 [GeV] # 1
Than, for each reconstructed particle in the decay tree (including the

-candidate as "the head" of the tree, it try to find the Monte Carlo particles which makes the direct or indirect contribution to this reconstructed particle. The algorithm prints the overall number of such Monte Carlo Paerticles, as well as the total number of independent Monte Carlo trees, whcih makes the contribution. And each independent Monte Carlo tree is printed, and the tree components, which make the direct or indirect contribution are "marked" with an asterisk in the first position. E.g. fot the recontructed negative kaon, one finds three Monte Carlo particles, which comes from only one independent Monte Carlo tree:
MCTruth SUCCESS Inspect reconstructed daughter particle 'K-' 7/7 (key:0): #'matched' MC trees 1 (#'matched' MC particles 3)
*0 |->B_s0 E/PX/PY/PZ: 70.01 / -1.844 / -8.547 / 69.25 [GeV] #2338
*1 |->phi(1020) E/PX/PY/PZ: 27.63 / 0.8406 / -3.374 / 27.39 [GeV] #2339
*2 |->K- E/PX/PY/PZ: 17.15 / 0.5602 / -2.154 / 17 [GeV] #2340
2 |->K+ E/PX/PY/PZ: 10.48 / 0.2804 / -1.22 / 10.39 [GeV] #2341
1 |->J/psi(1S) E/PX/PY/PZ: 42.38 / -2.685 / -5.173 / 41.86 [GeV] #2342
2 |->mu- E/PX/PY/PZ: 35.45 / -2.758 / -5.342 / 34.93 [GeV] #2343
2 |->mu+ E/PX/PY/PZ: 6.934 / 0.07358 / 0.1693 / 6.93 [GeV] #2344
One clearly see that this reconstructed Kaon comes from true Monte Carlo kaon from the true Monte Carlo decay

followed by

,

. And one see that three Monte Calro particles (

with the key 2340,

with the key 2339 and

with the key 2338) make the contribution to this reconstructed kaon. In a similar way the MC-mathching information for all other particles from the reconstructed

-candidate is printed:
MCTruth SUCCESS Inspect reconstructed daughter particle 'B_s0' 1/7 (key:4): #'matched' MC trees 1 (#'matched' MC particles 1)
*0 |->B_s0 E/PX/PY/PZ: 107.5 / 4.726 / -6.507 / 107.1 [GeV] #2271
1 |->phi(1020) E/PX/PY/PZ: 49.66 / 3.64 / -2.761 / 49.44 [GeV] #2272
2 |->K- E/PX/PY/PZ: 29.7 / 2.164 / -1.595 / 29.57 [GeV] #2273
2 |->K+ E/PX/PY/PZ: 19.96 / 1.476 / -1.165 / 19.87 [GeV] #2274
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2275
4 |->pi+ E/PX/PY/PZ: 0.6881 / 0.3765 / -0.03625/ 0.5576 [GeV] #2276
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2277
4 |->e+ E/PX/PY/PZ: 0.2595 / 0.04696 / -0.2055 / 0.1514 [GeV] #2278
1 |->J/psi(1S) E/PX/PY/PZ: 57.83 / 1.086 / -3.746 / 57.62 [GeV] #2279
2 |->mu- E/PX/PY/PZ: 12.04 / 0.03374 / 0.4577 / 12.03 [GeV] #2280
2 |->mu+ E/PX/PY/PZ: 45.8 / 1.052 / -4.204 / 45.59 [GeV] #2281
MCTruth SUCCESS Inspect reconstructed daughter particle 'J/psi(1S)' 2/7 (key:0): #'matched' MC trees 1 (#'matched' MC particles 2)
*0 |->B_s0 E/PX/PY/PZ: 107.5 / 4.726 / -6.507 / 107.1 [GeV] #2271
1 |->phi(1020) E/PX/PY/PZ: 49.66 / 3.64 / -2.761 / 49.44 [GeV] #2272
2 |->K- E/PX/PY/PZ: 29.7 / 2.164 / -1.595 / 29.57 [GeV] #2273
2 |->K+ E/PX/PY/PZ: 19.96 / 1.476 / -1.165 / 19.87 [GeV] #2274
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2275
4 |->pi+ E/PX/PY/PZ: 0.6881 / 0.3765 / -0.03625/ 0.5576 [GeV] #2276
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2277
4 |->e+ E/PX/PY/PZ: 0.2595 / 0.04696 / -0.2055 / 0.1514 [GeV] #2278
*1 |->J/psi(1S) E/PX/PY/PZ: 57.83 / 1.086 / -3.746 / 57.62 [GeV] #2279
2 |->mu- E/PX/PY/PZ: 12.04 / 0.03374 / 0.4577 / 12.03 [GeV] #2280
2 |->mu+ E/PX/PY/PZ: 45.8 / 1.052 / -4.204 / 45.59 [GeV] #2281
MCTruth SUCCESS Inspect reconstructed daughter particle 'mu+' 3/7 (key:1): #'matched' MC trees 1 (#'matched' MC particles 3)
*0 |->B_s0 E/PX/PY/PZ: 107.5 / 4.726 / -6.507 / 107.1 [GeV] #2271
1 |->phi(1020) E/PX/PY/PZ: 49.66 / 3.64 / -2.761 / 49.44 [GeV] #2272
2 |->K- E/PX/PY/PZ: 29.7 / 2.164 / -1.595 / 29.57 [GeV] #2273
2 |->K+ E/PX/PY/PZ: 19.96 / 1.476 / -1.165 / 19.87 [GeV] #2274
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2275
4 |->pi+ E/PX/PY/PZ: 0.6881 / 0.3765 / -0.03625/ 0.5576 [GeV] #2276
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2277
4 |->e+ E/PX/PY/PZ: 0.2595 / 0.04696 / -0.2055 / 0.1514 [GeV] #2278
*1 |->J/psi(1S) E/PX/PY/PZ: 57.83 / 1.086 / -3.746 / 57.62 [GeV] #2279
2 |->mu- E/PX/PY/PZ: 12.04 / 0.03374 / 0.4577 / 12.03 [GeV] #2280
*2 |->mu+ E/PX/PY/PZ: 45.8 / 1.052 / -4.204 / 45.59 [GeV] #2281
MCTruth SUCCESS Inspect reconstructed daughter particle 'mu-' 4/7 (key:0): #'matched' MC trees 1 (#'matched' MC particles 3)
*0 |->B_s0 E/PX/PY/PZ: 107.5 / 4.726 / -6.507 / 107.1 [GeV] #2271
1 |->phi(1020) E/PX/PY/PZ: 49.66 / 3.64 / -2.761 / 49.44 [GeV] #2272
2 |->K- E/PX/PY/PZ: 29.7 / 2.164 / -1.595 / 29.57 [GeV] #2273
2 |->K+ E/PX/PY/PZ: 19.96 / 1.476 / -1.165 / 19.87 [GeV] #2274
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2275
4 |->pi+ E/PX/PY/PZ: 0.6881 / 0.3765 / -0.03625/ 0.5576 [GeV] #2276
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2277
4 |->e+ E/PX/PY/PZ: 0.2595 / 0.04696 / -0.2055 / 0.1514 [GeV] #2278
*1 |->J/psi(1S) E/PX/PY/PZ: 57.83 / 1.086 / -3.746 / 57.62 [GeV] #2279
*2 |->mu- E/PX/PY/PZ: 12.04 / 0.03374 / 0.4577 / 12.03 [GeV] #2280
2 |->mu+ E/PX/PY/PZ: 45.8 / 1.052 / -4.204 / 45.59 [GeV] #2281
MCTruth SUCCESS Inspect reconstructed daughter particle 'phi(1020)' 5/7 (key:1): #'matched' MC trees 1 (#'matched' MC particles 2)
*0 |->B_s0 E/PX/PY/PZ: 107.5 / 4.726 / -6.507 / 107.1 [GeV] #2271
*1 |->phi(1020) E/PX/PY/PZ: 49.66 / 3.64 / -2.761 / 49.44 [GeV] #2272
2 |->K- E/PX/PY/PZ: 29.7 / 2.164 / -1.595 / 29.57 [GeV] #2273
2 |->K+ E/PX/PY/PZ: 19.96 / 1.476 / -1.165 / 19.87 [GeV] #2274
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2275
4 |->pi+ E/PX/PY/PZ: 0.6881 / 0.3765 / -0.03625/ 0.5576 [GeV] #2276
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2277
4 |->e+ E/PX/PY/PZ: 0.2595 / 0.04696 / -0.2055 / 0.1514 [GeV] #2278
1 |->J/psi(1S) E/PX/PY/PZ: 57.83 / 1.086 / -3.746 / 57.62 [GeV] #2279
2 |->mu- E/PX/PY/PZ: 12.04 / 0.03374 / 0.4577 / 12.03 [GeV] #2280
2 |->mu+ E/PX/PY/PZ: 45.8 / 1.052 / -4.204 / 45.59 [GeV] #2281
MCTruth SUCCESS Inspect reconstructed daughter particle 'K+' 6/7 (key:0): #'matched' MC trees 1 (#'matched' MC particles 3)
*0 |->B_s0 E/PX/PY/PZ: 107.5 / 4.726 / -6.507 / 107.1 [GeV] #2271
*1 |->phi(1020) E/PX/PY/PZ: 49.66 / 3.64 / -2.761 / 49.44 [GeV] #2272
2 |->K- E/PX/PY/PZ: 29.7 / 2.164 / -1.595 / 29.57 [GeV] #2273
*2 |->K+ E/PX/PY/PZ: 19.96 / 1.476 / -1.165 / 19.87 [GeV] #2274
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2275
4 |->pi+ E/PX/PY/PZ: 0.6881 / 0.3765 / -0.03625/ 0.5576 [GeV] #2276
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2277
4 |->e+ E/PX/PY/PZ: 0.2595 / 0.04696 / -0.2055 / 0.1514 [GeV] #2278
1 |->J/psi(1S) E/PX/PY/PZ: 57.83 / 1.086 / -3.746 / 57.62 [GeV] #2279
2 |->mu- E/PX/PY/PZ: 12.04 / 0.03374 / 0.4577 / 12.03 [GeV] #2280
2 |->mu+ E/PX/PY/PZ: 45.8 / 1.052 / -4.204 / 45.59 [GeV] #2281
MCTruth SUCCESS Inspect reconstructed daughter particle 'K-' 7/7 (key:1): #'matched' MC trees 1 (#'matched' MC particles 3)
*0 |->B_s0 E/PX/PY/PZ: 107.5 / 4.726 / -6.507 / 107.1 [GeV] #2271
*1 |->phi(1020) E/PX/PY/PZ: 49.66 / 3.64 / -2.761 / 49.44 [GeV] #2272
*2 |->K- E/PX/PY/PZ: 29.7 / 2.164 / -1.595 / 29.57 [GeV] #2273
2 |->K+ E/PX/PY/PZ: 19.96 / 1.476 / -1.165 / 19.87 [GeV] #2274
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2275
4 |->pi+ E/PX/PY/PZ: 0.6881 / 0.3765 / -0.03625/ 0.5576 [GeV] #2276
3 |->Intermediate E/PX/PY/PZ: 0 / 0 / 0 / 0 [GeV] #2277
4 |->e+ E/PX/PY/PZ: 0.2595 / 0.04696 / -0.2055 / 0.1514 [GeV] #2278
1 |->J/psi(1S) E/PX/PY/PZ: 57.83 / 1.086 / -3.746 / 57.62 [GeV] #2279
2 |->mu- E/PX/PY/PZ: 12.04 / 0.03374 / 0.4577 / 12.03 [GeV] #2280
2 |->mu+ E/PX/PY/PZ: 45.8 / 1.052 / -4.204 / 45.59 [GeV] #2281
On Linux platform, the lines marked by asterisk in the first column also are colored, making the analysis of these tables much easier:
If one needs some information about the vertices, one can configure the algorithm properly:
-
RCVertex
- Print the information about the vertices (if available) for the recontructed particles
-
MCVertex
- Print the information about the origin-vertices for the Monte Carlo particles
-
MCVertexE
- If the previous flag activated, it allows to print the information about the end-vertices for Monte Carlo particles
-
MCVertexD
- If activated flag activated, only Monte Carlo particles from decay tree will be considered. All Monte Carlo particles from the secondary intteractions in the detector will be ignored
How to use the various "decay-finders" in LoKi?
There are few ways to find the certain decay patterns in
LoKi:
- The brilliant
(MC)DecayFinder
tools, written by Olivier Dormond and few functors based on them
- New "tree/node" utilities, which allow to describe/construct the decay descriptions of the arbitrary complexity
- New (re)-implementation of "decay-finder"-tools by Alexander Mazurov, based on "tree/node" utilities
Some examples are available
here and
here.
How to "monitor" various LoKi functors, used in CombineParticles/FilterDesktop framework?
There are few basic monitoring tool:
- Simple printout to
std::cout
, useful for simple debugging & fast checks
- Histograms
- Counters
Monitoring using the printout to std::cout
To perform the printout of functor value one just needs to "decorate" the functor using the helper function
monitor
:
1000# monitor the functor M
1010MyAlg.XXXCut = "monitor( M ) > 1000"
1020
1030# monitor the predicate M > 1000
1040MyAlg.XXXCut = "monitor( M > 1000 )"
1050
1060# monitor everything
1070MyAlg.XXXCut = "monitor( monitor( M ) > 1000 )"
Clearly this mointoring is not acceptable for any offiical code and shodul be used
only for private checks & debugging
Monitoring using the automatically booked histograms
Here again the function
monitor
is in the game:
1000# monitor the functor M using 'local' histogram of GaudiHistoAlg, available through IAlgContextSvc
1010MyAlg.XXXCut = "monitor( M , Gaudi.Histo1DDef( 'histo title', 0 , 5000) , 'histoID' ) > 1000"
1020
1030# monitor the functor M using 'global' histogram, booked directly through IHistogramSvc
1040MyAlg.XXXCut = "monitor( M , 'histo/directory', 'histoID' , Gaudi.Histo1DDef( 'histo title', 0 , 5000) ) > 1000"
To avoid the overcomplication of the lines, one can predefine the histograms using the property
Preambulo
:
1000MyAlg.Preambulo += [
1010 "h1 = Gaudi.Histo1DDef( 'histo title 1 ', 0 , 5000 , 100 )" ,
1020 "h2 = Gaudi.Histo1DDef( 'histo title 2 ' , 0 , 5000 , 100 )",
1030]
1040
1050# monitor the functor M using 'local' histogram of GaudiHistoAlg, available through IAlgContextSvc
1060MyAlg.XXXCut = "monitor( M , h1 , 'histoID' ) > 1000"
1070
1080# monitor the functor M using 'global' histogram, booked directly through IHistogramSvc
1090MyAlg.XXXCut = "monitor( M , 'histo/directory', 'histoID' , h2 ) > 1000"
Also the histograms can be predefined using the property
Lines
for the corresponding Python/Hybrid factory.
Please note, that thistogramming is available only for functions, the predicates can't be monitored in this way.
Monitoring using the explicitly booked histograms
The histograms can be booked also expliclitly using
IHistogramDataSvc
and utilities from
GaudiPython.HistoUtils
module
1000MyAlg.Preambulo += [
1010 "from GaudiPython.HistoUtils import book " , # import helper function
1020 "histo = book('/stat/this/is/a/path/in/histogram/data/store', 'ID' , 'title' , 100 , 0 , 10000 )", # book the histogram
1030]
And finally one canuse the booked histogram for monitoring:
1000# monitor the functor M using explicitly booked histogram:
1010MyAlg.XXXCut = "monitor( M , histo ) > 1000"
Monitoring using the automatically booked counters
The functors (both functions & predicates) can be monitored using the counters, see
StatEntity
class.
The counters can be "local" (managed by the corresponding
GaudiAlgorithm
class, or "global" (managed by
IStatSvc
or
ICounterSvc
).
1000# monitor the functor M using 'local' counter of corresponding GaudiAlgorithm
1010MyAlg.XXXCut = "monitor( M , 'mass' , LoKi.Monitoring.IContextSvc ) > 1000 "
1020
1030# monitor the functor M using 'global' counter of IStatSvc
1040MyAlg.XXXCut = "monitor( M , 'mass' , LoKi.Monitoring.IStatSvc ) > 1000"
1050
1060# monitor the functor M using 'global' counter of ICounterSvc
1070MyAlg.XXXCut = "monitor( M , 'mass' , LoKi.Monitoring.ICounterSvc ) > 1000"
1080
1090# monitor the functor M using 'global' counter of ICounterSvc
1100MyAlg.XXXCut = "monitor( M , 'group' , 'mass' , LoKi.Monitoring.ICounterSvc ) > 1000"
(Instead of long enums
LoKi.Monitoring.IContextSvc/IStatSvc/ICounterSvc
one can use their short numerical values:
0
,
1
and
2
correspondingly). Please note that for monitoring of predicates it is advisable to ensure the counter name contains one of the following case-insensitive substrings:
eff
,
acc
,
filt
,
fltr
,
pass
, see
here
. For these cases the special printout format is activated, suitable for monitoring of boolean values..
Advanced monitoring using VoidFilter
and streamers
There is nice utility for monitoring using so called
LoKi::VoidFilter
. Thus technique is applicable to
any objects, eg. tracks, vertices, (mc)particles, etc, and it allows to monitor also quantities like "maximal transverse momentum" or even "momentum of the particle with maximal transverse momentum". The idea is based on the genious idea of
streamers by Gerhard The Great. The stremers represent the overall data flow, and using the helper functions the dat aflow can be modifies, and controlled. Finally for usage with
VoidFilter
one need to construct th eobject with the signature
void->bool
, The simplest example is:
1000from Configurables import LoKi__VoidFilter as MonFilter
1010
1020moni = MonFilter( 'I_am_Monitor', Code = "SOURCE('HLT/Hlt2Muons') >> ~EMPTY" )
And a top of the functors , one can add monitoring:
1000from Configurables import LoKi__VoidFilter as MonFilter
1010
1020moni = MonFilter( 'I_am_Monitor' )
1030
1040# 0. filter good container
1050moni.Code = " SOURCE('HLT/Hlt2Muons') >> SIZE > -1"
1060
1070# 1. printout
1080## a. print PT for all particles
1090moni.Code = "SOURCE('HLT/Hlt2Muons') >> ( monitor(PT) > 100 ) >> ( SIZE > -1 )"
1100## b. print PT for all particles
1110moni.Code = "SOURCE('HLT/Hlt2Muons') >> process(monitor( PT )) >> ( SIZE > -1 )"
1120## c. print max(PT)
1130moni.Code = "SOURCE('HLT/Hlt2Muons') >> tee(monitor(max_value( PT ))) >> ( SIZE > -1 ) "
1140
1150# 2. histograms
1160## a. plot PT for all particles
1170moni.Code = """
1180SOURCE('HLT/Hlt2Muons')
1190>> process( monitor( PT ) > 100 )
1200 >> tee ( monitor( max_value ( PT ) ) > 100 )
1210 >> tee ( monitor( min_value ( PT ) ) > 100 )
1220>> process( monitor( PT , 'pt' , LoKi.Monitoring.StatSvc ) > 100 )
1230 >> tee ( monitor( max_value ( PT ), 'maxpt', LoKi.Monitoring.StatSvc ) > 100 )
1240 >> tee ( monitor( min_value ( PT ), 'minpt', LoKi.Monitoring.StatSvc ) > 100 )
1250>> process( monitor( PT , histo1 ) > 100 )
1260 >> tee ( monitor( max_value ( PT ), histo2 ) > 100 )
1270 >> tee ( monitor( min_value ( PT ), histo3 ) > 100 )
1280>> process( monitor( PT , '/stat/Moni/h1', h1 ) > 100 )
1290 >> tee ( monitor( max_value ( PT ), '/stat/Moni/h2', h2 ) > 100 )
1300 >> tee ( monitor( min_value ( PT ), '/stat/Moni/h3', h3 ) > 100 )
1310>> process( monitor( PT , h1 , 'localH1' ) > 100 )
1320 >> tee ( monitor( max_value ( PT ), h2 , 'localH2' ) > 100 )
1330 >> tee ( monitor( min_value ( PT ), h3 , 'localH3' ) > 100 )
1340>> ( SIZE > -1 )
1350"""
1360
1370moni.Preambulo = """
1380from LoKiCore.functions import *
1390from LoKiPhys.decorators import *
1400from GaudiPython.HistoUtils import book
1410histo1 = book( '/stat/filter/PT', 'pt1' , 'title: PT' , 100, 0.0, 10000.0)
1420histo2 = book( '/stat/filter/PT', 'ptmax', 'title: PTMAX', 100, 0.0, 10000.0)
1430histo3 = book( '/stat/filter/PT', 'ptmin', 'title: PTMIN', 100, 0.0, 10000.0)
1440h1 = Gaudi.Histo1DDef('my PT-histo' , 0, 10000)
1450h2 = Gaudi.Histo1DDef('my PTMAX-histo', 0, 10000)
1460h3 = Gaudi.Histo1DDef('my PTMIN-histo', 0, 10000)
1470""".split('\n')
1480
Helper streamer functions
-
process
, accept container, apply the functor to each element of container and return the initial container (unmodified)
-
tee
, accept container, branch the data flow, and return the initial container (unmodified)
-
min_value
, accept the container and return the minimal value of certain functor
-
max_value
, accept the container and return the maximal value of certain functor
-
min_abs_value
, accept the container and return the abs-minimal value of certain functor
-
max_abs_value
, accept the container and return the abs-maximal value of certain functor
-
min_element
, accept the container, and return element which minimizes the certain functor
-
max_element
, accept the container, and return element which maximizes the certain functor
-
min_abs_element
, accept the container, and return element which abs-minimizes the certain functor
-
max_abs_element
, accept the container, and return element which abs-maximizes the certain functor
-
yields
, accept container and return the container with values of certain functor
-
has
, accept container and check the scalar predicate
-
count
, accept container and count the sing the scalar predicate
-
select
, accept container and select the elemenets which satisfy the scalar predicate
Note that often one can avout the explicit appearence of control functions, e..g the follwoing expressions are equivalent:
1000MyAlg.Code = "SOURCE('HLT/Hlt2Muons', PT > 1000 ) >> ~EMPTY "
1010
1020MyAlg.Code = "SOURCE('HLT/Hlt2Muons') >> select( PT > 1000 ) >> ~EMPTY "
1030
1040MyAlg.Code = "SOURCE('HLT/Hlt2Muons') >> ( PT > 1000 ) >> ~EMPTY "
1050
1060MyAlg.Code = "SOURCE('HLT/Hlt2Muons') >> count( PT > 1000 ) != 0 "
1070
1080MyAlg.Code = "SOURCE('HLT/Hlt2Muons') >> yields( PT ) >> count( X > 1000 ) != 0 "
1090
1100MyAlg.Code = "SOURCE('HLT/Hlt2Muons') >> yields( PT ) >> ( X > 1000 ) >> ~XEMPTY "
1110
1120MyAlg.Code = "SOURCE('HLT/Hlt2Muons') >> yields( PT ) >> select( X > 1000 ) >> ~XEMPTY "
1130
1140MyAlg.Code = "SOURCE('HLT/Hlt2Muons') >> PT >> count( X > 1000 ) != 0 "
1150
1160MyAlg.Code = "SOURCE('HLT/Hlt2Muons') >> PT >> ( X > 1000 ) >> ~XEMPTY "
1170
1180MyAlg.Code = "SOURCE('HLT/Hlt2Muons') >> PT >> select( X > 1000 ) >> ~XEMPTY "
Monitoring using "fake" functors
One also can perform moniring using "fake" functors, e.g.
1000# monitor the functor M using 'local' counter of corresponding GaudiAlgorithm
1010MyAlg.XXXCut = "PT > 1000"
1020
1030# redefine the meaning of PT !
1040MyAlg.Preambulo = [ "PT = monitor( PT , ... ) " ]
Examples
All monitoring utilities listed above are illustrated for the following code fragment (using Hlt2 framework and
FilterDesktop
algorithm:
1000algo = Hlt2Member( FilterDesktop , "Filter" , InputLocations = [Muons] )
1010
1020# 0. Original `Code` snippet. Can be replaces by examples below
1030algo.Code = "PT > 2.8*GeV"
1040
1050# 1. use std::cout
1060## a. monitor the function
1070Code = "monitor(PT) > 2.8*GeV"
1080## b. monitor the predicate
1090Code = "monitor(PT > 2.8*GeV)"
1100
1110# 2. use "local" counters
1120## a. monitor the function
1130Code = "monitor(PT, 'PT-counter', LoKi.Monitoring.ContextSvc) > 2.8*GeV"
1140## b. monitor the predicate
1150Code = "monitor(PT > 2.8*GeV, 'PT-cut-eff', LoKi.Monitoring.ContextSvc)"
1160
1170# 3. use "global" counters: StatSvc
1180## a. monitor the function
1190Code = "monitor(PT, 'PT-counter', LoKi.Monitoring.StatSvc) > 2.8*GeV"
1200## b. monitor the predicate
1210Code = "monitor(PT > 2.8*GeV, 'PT-cut-eff', LoKi.Monitoring.StatSvc)"
1220
1230# 4. use "global" counters: CounterSvc
1240## a. monitor the function
1250Code = "monitor(PT, 'PT-counter', LoKi.Monitoring.CounterSvc) > 2.8*GeV"
1260## b. monitor the predicate
1270Code = "monitor(PT > 2.8*GeV, 'PT-cut-eff', LoKi.Monitoring.CounterSvc)"
1280
1290# 5. use "global" counters with 'Group'-attribute CounterSvc
1300## a. monitor the function
1310Code = "monitor(PT, 'MUON', 'PT-counter', LoKi.Monitoring.CounterSvc) > 2.8*GeV"
1320## b. monitor the predicate
1330Code = "monitor(PT > 2.8*GeV, 'MUON', 'PT-cut-eff', LoKi.Monitoring.CounterSvc)"
1340
1350# 6. Use local histograms [check that historamming is not disabled!!!]
1360## a. monitor the function, literal ID
1370Code = "monitor(PT, h1, 'my-histo') > 2.8*GeV"
1380## a. monitor the function, numerical ID
1390Code = "monitor(PT, h1, 10) > 2.8*GeV"
1400
1410# 7. Use global histograms:
1420# a. monitor the function, full path in HDS
1430Code = "monitor(PT, '/stat/MUONS/pt', h1) > 2.8*GeV"
1440# b. monitor the function, full path in HDS + literal ID
1450Code = "monitor(PT, '/stat/MUONS/pt', 'Pt', h1) > 2.8*GeV"
1460## c. monitor the function, full path in HDS + integer ID
1470Code = "monitor(PT, '/stat/MUONS/pt', 15, h1) > 2.8*GeV"
1480
1490# 8. use prebooked histograms
1500## a. monitor the function
1510algo.Code = "monitor(PT,histo) > 2.8*GeV"
1520algo.HistoProduce = True
1530algo.Preambulo = """
1540# needed for groups 6 & 7
1550h1 = Gaudi.Histo1DDef('my PT-histo', 0, 10000)
1560# definition of the histogram parameters,
1570# needed from group 8
1580from GaudiPython.HistoUtils import book
1590histo = book( '/stat/path_in_HTS/MUON/pt', 'ID', 'title', 100, 0.0, 10000.0 )
1600""".split('\n')
1610
Another example is available
here
An
example, monitoring the
LoKi filters in the
Hlt2InclusivePhi alley.
How to code own LoKi functor?
From pure formal point of view the implementation of own
LoKi functors is just a trivial task. In short one shoudl follow the instructions from
here or
here.
In a nutshell
Each
LoKi functor inherits from the base class
LoKi::Functor
, where
TYPE1
defines the (single) argument type and
TYPE2
defines the return value. The formal actual argument type (which in general is different from
TYPE1
is provided by the typedef
argument
, and the actual type of result is defined as
result_type
.
According to the type of
TYPE2
all existing
LoKi functors can be classified as:
- function:
TYPE2=double
- predicate:
TYPE2=bool
- streamers:
TYPE2=std::vector< TYPE3 >
for some TYPE3
According to the type of
TYPE1
all existing
LoKi functors can be classified as:
- particle functors :
TYPE1=const LHCb::Particle*
- vertex functors :
TYPE1=const LHCb::VertexBase*
- Monte Carlo particle functors :
TYPE1=const LHCb::MCParticle*
- Monte Carlo vertex functors :
TYPE1=const LHCb::MCVertex*
- Generator particle functors :
TYPE1=const HepMC::GenParticle*
- Generator vertex functors :
TYPE1=const HepMC::GenVertex*
- Array particle functors :
TYPE1=LoKi::Range_
- track functors :
TYPE1=LHCb::Track
- rec-vertex functors :
TYPE1=LHCb::RecVertex
- track-track bi-functors:
TYPE1=LoKi::TrackTypes::TrackPair
- track-rec-vertex bi-functors:
TYPE1=LoKi::TrackTypes::TrackVertexPair
- rec-vertex-rec-vertex bi-functors:
TYPE1=LoKi::TrackTypes::VertexPair
- streamers :
TYPE1=std::vector< TYPE3 >
for some TYPE3
- numbers :
TYPE1=double
If new functor falls into one of the category, the subsequent
decoration for interactive usage in Python,Bender or
CombineParticles is trivial and automatic. Otherwise the
decoration is not a trivial task, please contact me in this case and we'll try to find the appropriate solution.
The coding is especially simple for the certain combinations of
TYPE1
and
TYPE2
, whcih are available through
LoKi::BasicFunctors
template, which defines the
reasonable functor signatures for various purposes.
-
Function
-
LoKi::Functor
-
Predicate
-
LoKi::Functor
-
Map
-
LoKi::Functor,std::vector< double > >
-
Pipe
-
LoKi::Functor,std::vector< TYPE > >
-
FunVal
-
LoKi::Functor , double>
-
CutVal
-
LoKi::Functor,bool>
-
Element
-
LoKi::Functor,TYPE>
-
Source
-
LoKi::Functor >
Choose the base
Lets start wit very simple functor, e.g.
transverse momentum of particle. Clearly here both
TYPE1
and
TYPE2
are well defined:
TYPE1=const LHCb::Particle*
and
TYPE2=double
, and the functor signature corresponds to
LoKi::BasicFunctors::Function
:
1000class MyFunctor : public LoKi::BasicFuctors<const LHCb::Particle>::Function { ... } ;
To simplify the subsequent generation of Reflex dictionaries, it is highly recommended to put the functor into some namespace:
1000namespace LoKi {
1010
1020namespace XXX {
1030
1040class MyFunctor : ... } // end of namespace LoKi::XXX
1050
1060} // end of namespace LoKi
1070
Mandatory methods
Each funtor must implement three mandatory methods:
- virtual destructor:
virtual ~MyFunctor()
- cloning:
virtual MyFunctor* clone() const
-
virtual result_type operator()( argument a ) const
1000class MyFunctor : public LoKi::BasicFuctors<const LHCb::Particle>::Function {
1010
1020public:
1030
1040// MANDATORY: virtual destructor:
1050
1060virtual ~MyFunctor();
1070
1080// MANDATORY: clone method ("virtual constructor")
1090
1100virtual MyFunctor* clone() const ;
1110
1120// MANDATORY: the only one essential method
1130
1140virtual result_type operator () ( argument a ) const ;
1150
1160} ;
Please note the usage of
result_type
and
argument
.
The typical implementation of destructor and clone mehtod applicable for almost all cases is
1000// destructor:
1010LoKi::XXX::MyFunctor::~MyFunctor(){};
1020
1030// clone method ("virtual constructor")
1040LoKi::XXX::MyFunctor* LoKi::XXX::MyFunctor::clone() const { return new LoKi::XXX::MyFunctor(*this); }
The implementation of the major method could be e.g.
1000// the major method LoKi::XXX::MyFunctor::result_type LoKi::XXX::MyFunctor::operator() ( LoKi::XXX::MyFunctor::argument a ) const {
1010
1020// check the argument: if ( 0 == a ) { Error ("Invalid argument, return 'InvalidMomentum'") ; return LoKi::Constants::InvalidMomentum ; }
1030
1040// calculate the result:
1050
1060double result = a -> pt() ;
1070
1080return result ; }
Please note again the usage of
result_type
and
argument
. Also note the usage of helper member-function
Error
from base class
LoKi::AuxFunBase
.
This minimal setup is already enough touse the function in
C++
, e.g. with bare
LoKi:
1000// make the instance:
1010
1020const LoKi::XXX::MyFunctor fun = LoKi::XXX::MyFunctor() ;
1030
1040// get the particle
1050
1060const LHCb::Particle* B = ... ;
1070
1080// use the functor:
1090
1100const double result = fun ( B ) ;
Optional method
One can redefine the self-printout of the functor:
1000namespace LoKi { namespace XXX { class MyFunctor : public LoKi::BasicFuctors<const LHCb::Particle>::Function {
1010
1020public: ... /// OPTIONAL: nice printout virtual std::ostream& fillStream( std::ostream& s ) const ; ... } ; } }
1030
The typical implementation is
1000std::ostream& LoKi::XXX::MyFunctor::fillStream ( std::ostream& ) const { return s << "MYFUN" ; }
It is convinient to define proper type inside the the
namespace LoKi::Cuts

to be in agreement with self-printout:
1000namespace LoKi { namespace Cuts { /** @var MYFUN * put some reasonable comment here and example of the code * @code * ... * @endcode * @see LoKi::XXX::MyFunctor * @date 2009-04-07 * @author Xxx Yyyy ZZZ@aaa.bbb */ const LoKi::XXX::MyFunctor MYFUN ; } }
For this case one can use in C++ a bit simple expressions:
1000// get the particle
1010
1020const LHCb::Particle* B = ... ;
1030
1040// use the functor:
1050
1060const double result = MYFUN ( B ) ;
Generating Reflex dictionaries
To produce Reflex dictionaries it is enough to include (directly or indirectly) the corresponding header file into corresponding
$LOKIXXXROOT/dict/LoKiXXXDict.h
file and to ensure that the corresponding
$LOKIXXXROOT/dict/LoKiXXX.xml
file contains the line:
1000<class name="LoKi::XXX::MyFunctor" />
XXX
shodul be defined as the most appropriate location, e.g. here it could be the package
Phys/LoKiPhys
.
Python decoration
To activate the useful functionality in python one needs to perform the proper decoration. The standard decoration is activated automatically if one declares the objects inside corresponding
$LOKIXXXROOT/python/LoKiXXX/functions.py
file:
1000## @see LoKi::Cuts::MYFUN MYFUN = LoKi.XXX.MyFunctor ()
1010
From here the functor is "ready" and one can use it both in C++ (
LoKi) and Python (Bender) and
CombineParticles framework in a coherent way:
1000from Configurables import CombineParticles
1010
1020myAlgorithm = CombineParticles ( .... )
1030
1040myAlgorithm.MotherCuts = " MYFUN > 1000 "
What to do if functor has no default constructor?
For the functors whithout defautl constructor, of fro functors which require to be configured during the instantiation, the described procedure need to be modified, since we can neither define the instances in
LoKi::Cuts
namespace
nor in
$LOKIXXXROOT/python/LoKiXXX/functions.py
module.
For this case instead of instances one needs to defien the types:
1000namespace LoKi { namespace Cuts { /** @typedef MYFUN2 * put some reasonable comment here and example of the code * @code * ... * @endcode * @see LoKi::XXX::MyFunctor2 * @date 2009-04-07 * @author Xxx Yyyy ZZZ@aaa.bbb */ typedef LoKi::XXX::MyFunctor2 MYFUN2 ; } }
And
1000## @see LoKi::Cuts::MYFUN2 MYFUN2 = LoKi.XXX.MyFunctor2
1010
The usage of symbols in this case is:
1000from Configurables import CombineParticles
1010
1020myAlgorithm = CombineParticles ( .... )
1030
1040myAlgorithm.MotherCuts = " MYFUN2 ( ... the constructor arguments are here ... ) > 1000 "
How to evaluate various polarization angles?
There are few basic functors for evaluation of polarizaton angles.
Polarization of particles in laboratory frame
For evaluation of polarization angles in laboratory frame one can use the functor
LV0
(the type)
-
LV01
- evaluates the cosine of the angle of between the momentum direction of the first daughter particle in the rest frame of the mother particle with respect to the direction of the boost form the laboratory frame to the rest-frame of mother particle
-
LV02
- evaluates the cosine of the angle of between the momentum direction of the second daughter particle in the rest frame of the mother particle with respect to the direction of the boost form the laboratory frame to the rest-frame of mother particle
-
LV03
- evaluates the cosine of the angle of between the momentum direction of the third daughter particle in the rest frame of the mother particle with respect to the direction of the boost form the laboratory frame to the rest-frame of mother particle
-
LV04
- evaluates the cosine of the angle of between the momentum direction of the fourth daughter particle in the rest frame of the mother particle with respect to the direction of the boost form the laboratory frame to the rest-frame of mother particle
C++ example
1000// get the particle const LHCb::Particle* particle = .... ;
1010
1020// get the cosine of decay angle const double cosTheta = LV01( particle ) ;
1030
Python example
1000## get the particle particle = ...
1010
1020## get the cosine of decay angle cosTheta = LV01( particle )
1030
LoKi::Hybrid::TupleTool
example
1000## add the variable myTool.Variables = {
1010
1020'cosTheta' : "LV01"
1030
1040}
Polarization of daughter particles in the frame of mother particles
The functor
COSPOL
(
MCCOSPOL
for Monte Carlo particles,
GENCOSPOL
for generator/HepMC particles) allows to evaluate the cosine of the angle between the momentum direction of one of the particle in the decya tree, in the rest frame of another particle in the decay tree with respect the direction of the boost from the head of the decay frame to the rest-frame of the second particle. E.g. it can be used for evaluation of
-
/
for such decays as
,
,
;
-
for decays
,
,
,
;
-
for decays
, etc..
To use this functors one needs to specify children particles, used for evaluation of angles, e.g.
C++
1000// create the functors const COSPOL cosTheta_K = COSPOL ( "B0 --> ( K*(892)0 -> ^K- \pi^+ ) ( J/psi(1S) \to \mu+ \mu- ) ", "B0 --> ^( K*(892)0 -> K- \pi^+ ) ( J/psi(1S) \to \mu+ -\mu- ) " ) ; const COSPOL cosTheta_L = COSPOL ( "B0 --> ( K*(892)0 -> K- \pi^+ ) ( J/psi(1S) \to ^\mu+ \mu- ) ","B0 --> ( K*(892)0 -> K- \pi^+ ) ^( J/psi(1S) \to \mu+ -\mu- ) '") ;
1010
1020// get B-candidate const LHCb::Particle* B = ... ;
1030
1040// use the functor const double value_K = cosTheta_K ( B ) ; const double value_L = cosTheta_L ( B ) ;
1050
Python:
1000## create the functors cosTheta_K = COSPOL ( 'B0 --> ( K*(892)0 -> ^K- \pi^+ ) ( J/psi(1S) \to \mu+ \mu- ) ', 'B0 --> ^( K*(892)0 -> K- \pi^+ ) ( J/psi(1S) \to \mu+ -\mu- ) ' ) cosTheta_L = COSPOL ( 'B0 --> ( K*(892)0 -> K- \pi^+ ) ( J/psi(1S) \to ^\mu+ \mu- ) ', 'B0 --> ( K*(892)0 -> K- \pi^+ ) ^( J/psi(1S) \to \mu+ -\mu- ) ' )
1010
1020## get B-candidate B = ...
1030
1040## use the functor value_K = cosTheta_K ( B ) value_L = cosTheta_L ( B )
1050
For some cases, e.g. for evaluation of

for decay

, oen can't speify the intermediate particle
"dimuon", in this case one should specify the optional parameter, to indicate that effective
"dimuon" is effectively constructed ftom the first and the second specified arguments:
C++:
1000// create the functors const double COSPOL cosTheta_L = COSPOL ( "B0 --> ( K*(892)0 -> K- \pi^+ ) ^\mu+ \mu- ", "B0 --> ( K*(892)0 -> K- \pi^+ ) \mu+ ^\mu- " , false ) ;
1010
1020// get B-candidate const LHCb::Particle* B = ... ;
1030
1040// use the functor const double value_L = cosTheta_L ( B ) ;
1050
Python:
1000## create the functors cosTheta_L = COSPOL ( 'B0 --> ( K*(892)0 -> K- \pi^+ ) ^\mu+ \mu- ', 'B0 --> ( K*(892)0 -> K- \pi^+ ) \mu+ ^\mu- ' , False )
1010
1020## get B-candidate B = ...
1030
1040## use the functor value_L = cosTheta_L ( B )
1050
The child particles coudl be specified also using decay nodes or particle functors:
1000// create the functors using ``decay nodes'' from PartProp.Nodes module const COSPOL cosTheta_L = COSPOL ( EllPlus , EllMinus , False )
1010
1020// create the functors using ``decay nodes'' from PartProp.Nodes module const COSPOL cosTheta_K = COSPOL ( Hadron & Positive & Strange , Pid("K*(892)0") )
1030
1040// create the functors using particle cuts const COSPOL cosTheta_L = COSPOL ( "mu+" <span>= ID , "mu-" =</span> ID , False )
1050
1060// create the functors using particle cuts const COSPOL cosTheta_K = COSPOL ( "K+" <span>= ID , "K*(892)*" =</span> ID )
1070
1000## create the functors using ``decay nodes'' from PartProp.Nodes module cosTheta_L = COSPOL ( EllPlus , EllMinus , False )
1010
1020## create the functors using ``decay nodes'' from PartProp.Nodes module cosTheta_K = COSPOL ( Hadron & Positive & Strange , Pid('K*(892)0') )
1030
1040## create the functors using particle cuts cosTheta_L = COSPOL ( 'mu+' <span>= ID , 'mu-' =</span> ID , False )
1050
1060## create the functors using particle cuts cosTheta_K = COSPOL ( 'K+' <span>= ID , 'K*(892)*' =</span> ID )
1070
The actual computations are perfomed in function
LoKi::Kinematics::decayAngle
using the explicit Lorentz-invariant expression
The angle between decay planes
For study of

decays such as

or

it is important to evaluat the angle

between the decay planes. The functors
SINCHI
,
COSCHI
and
ANGLECHI
allows to calculate

,

and angle

iself respectively. One needs to specify four child particles for evaluation of the angles:
C++
1000// create the functors const SINCHI sinChi = SINCHI ( "B0 --> ( K*(892)0 -> ^K- \pi+ ) \mu+ \mu- ", "B0 --> ( K*(892)0 -> K- ^\pi+ ) \mu+ \mu- " , "B0 --> ( K*(892)0 -> K- \pi+ ) ^\mu+ \mu- ", "B0 --> ( K*(892)0 -> K- \pi+ ) \mu+ ^\mu- " ) ;
1010
Python:
1000## create the functors sinChi = SINCHI ( "B0 --> ( K*(892)0 -> ^K- \pi+ ) \mu+ \mu- ", "B0 --> ( K*(892)0 -> K- ^\pi+ ) \mu+ \mu- " , "B0 --> ( K*(892)0 -> K- \pi+ ) ^\mu+ \mu- ", "B0 --> ( K*(892)0 -> K- \pi+ ) \mu+ ^\mu- " )
1010
Again decay nodes and particle functors can be used to select proper children particles:
C++
1000// create the functors const SINCHI sinChi = SINCHI ( EllPlus , ElMinus , Meson & Stranage & Positive , Meson & Strange & Negative ) ; const COSCHI cosChi = COSCHI ( "mu+" <span>= ID , "mu-" =</span> ID , "K+" <span>= ID , "K-" =</span> ID ) ;
1010
Python:
1000## create the functors sinChi = SINCHI ( EllPlus , ElMinus , Meson & Stranage & Positive , Meson & Strange & Negative ) cosChi = COSCHI ( 'mu+' <span>= ID , 'mu-' =</span> ID , 'K+' == ID , 'K-' = ID )
1010
The actual computation are perfromed in functions
-
LoKi::Kinematics::sinDecayAngleChi
,
-
LoKi::Kinematics::cosDecayAngleChi
-
LoKi::Kinematics::decayAngleChi
The explicit Lorentz-invariant expressions are used:
-
-
,
where "4-normales" are defined as:
The 4-momenta of two compounds are:
-
-
;
And the overall 4-momenta of decay head is

.
The angles in transversity frame
For study of

often
transversity frame is used. For evaluation of angle

(polarization angle of

-meson) one can use the functor
COSPOL( "B_s0 -> J/psi(1S) ( phi(1020) -> ^K+ K-) " , "B_s0 -> J/psi(1S) ^( phi(1020) -> K+ K-) " )
as described in previos chapter. For evaluation of

one need to use the symbol
COSTHETATR
:
1000// create the functor const COSTHETATR cosThetaTr = COSTHETATR ( "B_s0 --> ( J/psi(1S) -> ^mu+ mu- ) ( phi(1020) -> K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ ^mu- ) ( phi(1020) -> K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ mu- ) ( phi(1020) -> ^K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ mu- ) ( phi(1020) -> K+ ^K- ) " ) ;
1010
The computation is performed using the explicit Lorentz-invarinat expression:

, where ``4-normal''

is defined as

, and

.
In a similar way for evaluation of

,

and

one can use the symbols
SINPHITR
,
COSPHITR
and
ANGLEPHITR
1000// create the functor(s)
1010
1020const SINPHITR sinPhiTr = SINPHITR ( "B_s0 --> ( J/psi(1S) -> ^mu+ mu- ) ( phi(1020) -> K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ ^mu- ) ( phi(1020) -> K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ mu- ) ( phi(1020) -> ^K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ mu- ) ( phi(1020) -> K+ ^K- ) " ) ;
1030
1040const COSTHETATR cosPhiTr = COSPHITR ( "B_s0 --> ( J/psi(1S) -> ^mu+ mu- ) ( phi(1020) -> K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ ^mu- ) ( phi(1020) -> K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ mu- ) ( phi(1020) -> ^K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ mu- ) ( phi(1020) -> K+ ^K- ) " ) ;
1050
1060const ANGLEPHITR anglePhiTr = ANGLEPHITR ( "B_s0 --> ( J/psi(1S) -> ^mu+ mu- ) ( phi(1020) -> K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ ^mu- ) ( phi(1020) -> K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ mu- ) ( phi(1020) -> ^K+ K- ) ", "B_s0 --> ( J/psi(1S) -> mu+ mu- ) ( phi(1020) -> K+ ^K- ) " ) ;
The evaluation of

is performed using the explicit Lorentz-invariant expression:

, where 4-normal

is defined as

,

,

,

and ``in-plane'' 4-vector

is defined as

.
The evaluation of

is performed using the explicit Lorentz-invariant expression as angle between the ``in-plane'' vector

and vector

in rest frame of

, where

and the ``4-normal'' is defiend as

,

,

.
How to use LoKi algorithm-filters
?
LoKi-algorothms-filters allows to filter events on the basic of some event properties, e.g. properties of
LHCb::ODIN
,
LHCb::L0DUReport
,
LHCb::HltDecReports
and many others. The basic filters are:
-
LoKi::ODINFilter
-
LoKi::L0Filter
-
LoKi::HDRFilter
-
LoKi::VoidFilter
All filters are used in the same way:
1000from Configurables import LoKi __XXXFilter as Filter
1010
1020fltr = Filter ( 'Myfilter' , Code = ' here a python strion with loki-functors comes ' )
All of them have the major proeprty
Code
, that shoudl be valid python expression that evaluates to the
LoKi-functor woth following signatures:
-
const LHCb::ODIN*
bool
in case of LoKi::ODINFilter
-
const LHCb::L0DUReport*
bool
in case of LoKi::L0Filter
-
const LHCb::HltDecReports*
bool
in case of LoKi::HDRFilter
-
void
bool
in case of LoKi::VoidFilter
All of them have property
Premambulo
, where one can add addiiton python lines to be used durong the evaluation of
Code
, e.g.
1000from Confiigurables import LoKi __XXXFilter as Filter
1010
1020fltr = Filter ( 'Myfilter' , .. Preambulo = [ "from LoKiCore.math import *" , "from LoKiNumbers.decorators import *" ] ... )
All but
LoKi::VoidFilter
, have property
Location
, where one can specify non-default location of the coprrespoonidg objects in TES, e.g. it cvan be useful for reading of stripping reports:
1000from Configurables import LoKi __HDRFilter as StripFilter
1010
1020fltr = StripFilter ( 'StripFilter' , .. Location = "/Event/Strip/Phys/DecReports" ... )
How to select the certain HLT -line ?
1000from Configurables import LoKi __HDRFilter as Filter
1010
1020fltr = Filter ( 'MicroBias' , .. Code = " HLT_PASS_RE( 'Hlt1MBMicro.*Decision' ) " ... )
How to select the certain stripping -line ?
1000from Configurables import LoKi __HDRFilter as StripFilter
1010
1020fltr = StripFilter ( 'StrippedDstars' , .. Code = " HLT_PASS( 'StrippingDstarPromptWithD02HHNoPtDecision' ) " ,
1030
1040Location = "/Event/Strip/Phys/DecReports" ... )
How to select MC-events with no pileup?
Here one can use
LoKi::VoidFilter
and check number of proton-proton collisions from
LHCb::GenCollisioons
container:
1000from Configurables import LoKi __VoidFilter as Filter
1010
1020fltr = Filter ( 'No-pileup' , .. Code = " 1 == CONTAINS ( 'Gen/Collisions') " , ## get from TES the container "Gen/Collision" and check its size... ... )
1030
How to select MC-events with interesting particles/decays?
Here one can use
LoKi::VoidFilter
:
1000from Configurables import LoKi __VoidFilter as Filter
1010
1020fltr = Filter ( 'No-pileup' , .. Code = " MCSOURCE('MC/Particles', ' J/psi(1S) => l+ l-' ) >> ( MCPT > 500 * MeV ) >> ( MCY > 2.5 ) >> ~MCEMPTY " , Preambulo = [ "from LoKiMC.decorators import *" ] )
In this example we select events where there is at least one

, that decays into a lepton pair (with possible emission of soft radiative photons) with certain cuts on the transverse momentum and rapidity of

particle.
We also can select the

particles fomr B-decays:
1000from Configurables import LoKi __VoidFilter as Filter
1010
1020fltr = Filter ( 'No-pileup' , .. Code = " MCSOURCE('MC/Particles', ' Xb --> ( J/psi(1S) => l+ l- ) .... ' ) >> ( MCPT > 500 * MeV ) >> ( MCY > 2.5 ) >> ~MCEMPTY " Preambulo = [ "from LoKiMC.decorators import *" ] )
How to select events with multiple reconstructed primary vertices?
Here one can use
LoKi::VoidFilter
and check number of primary vertices from
LHCb::GenCollisioons
container:
1000from Configurables import LoKi __VoidFilter as Filter
1010
1020fltr = Filter ( 'Multy_PV' , .. Code = " 1 < CONTAINS ( 'Rec/Vertex/Primary') " , ## get from TES the container "Rec/Vertex/Primary" and check its size... ... )
1030
How to select events with certain multiplicity of long tracks?
Here one can use
LoKi::VoidFilter
:
1000from Configurables import LoKi __VoidFilter as Filter
1010
1020fltr = Filter ( 'TrackVFilter , .. Code = " TrSOURCE( 'Rec/Track/Best' , TrLONG ) >> ( TrSIZE > 100 ) " , Preambulo = [ "from LoKiTracks.decorators import *" ] ... )
1030
1040
How to select events with at least one backward track?
Here one can use
LoKi::VoidFilter
:
1000from Configurables import LoKi __VoidFilter as Filter
1010
1020fltr = Filter ( 'TrackVFilter , .. Code = " TrSOURCE( 'Rec/Track/Best' , TrBACKWARD ) >> ~TrEMPTY " , Preambulo = [ "from LoKiTracks.decorators import *" ] ... )
1030
1040
How to select events with at least two good high-pt muons?
Here one can use
LoKi::VoidFilter
:
1000from Configurables import LoKi __VoidFilter as Filter
1010
1020fltr = Filter ( 'TrackVFilter , .. Code = " SOURCE( 'Phys/StdLooseMuons' , ( PT > 1.5 GeV ) & ISMUON & ( PIDmu > 0 ) ) >> ( 2 <= SIZE ) " , Preambulo = [ "from LoKiPhys.decorators import *" ] ... )
1030
1040
Vanya BELYAEV - 20 June 2k+10