From e8f15915fd90c1ec5b82beb22fd2df9772a95f9e Mon Sep 17 00:00:00 2001 From: Maurizio Martinelli Date: Thu, 11 Feb 2021 14:14:45 +0100 Subject: [PATCH 01/21] some files to configure DaVinci with PyConf --- .../python/DaVinci/algorithms_pyconf.py | 308 ++++++++ Phys/DaVinci/python/DaVinci/config.py | 128 ++++ Phys/DaVinci/python/DaVinci/hacks.py | 35 + .../python/DaVinci/standard_particles.py | 666 ++++++++++++++++++ Phys/DaVinci/tests/selection.py | 42 ++ Phys/DaVinci/tests/simple_histos.py | 20 + 6 files changed, 1199 insertions(+) create mode 100644 Phys/DaVinci/python/DaVinci/algorithms_pyconf.py create mode 100644 Phys/DaVinci/python/DaVinci/config.py create mode 100644 Phys/DaVinci/python/DaVinci/hacks.py create mode 100644 Phys/DaVinci/python/DaVinci/standard_particles.py create mode 100644 Phys/DaVinci/tests/selection.py create mode 100644 Phys/DaVinci/tests/simple_histos.py diff --git a/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py b/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py new file mode 100644 index 00000000..7e4c3438 --- /dev/null +++ b/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py @@ -0,0 +1,308 @@ +############################################################################### +# (c) Copyright 2019 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. # +############################################################################### +"""Selection and combiner wrappers. + +Algorithms that inherit from DVCommonBase, like FilterDesktop and +CombineParticles, are not functional and do not expose input/output +DataHandles. They also do some funky internal location mangling to save +additional objects next to the Particle objects they create. The wrappers here +try to work around these traits to make the algorithms behave like any other +functional algorithms. +""" +from __future__ import absolute_import, division, print_function +import string + +from Configurables import ( + LoKi__Hybrid__DictTransform_TMVATransform_ as TMVAtransform, + LoKi__Hybrid__DictOfFunctors as DictOfFunctors, + LoKi__Hybrid__DictValue as DictValue, +) + +from RecoConf.hlt1_tracking import EmptyFilter +from PyConf.Algorithms import (CombineParticles, FilterDesktop, + DaVinci__N3BodyDecays as N3BodyDecays, + DaVinci__N4BodyDecays as N4BodyDecays) + +__all__ = [ + 'EmptyFilter', 'ParticleFilter', 'ParticleCombiner', + 'ParticleFilterWithPVs', 'ParticleCombinerWithPVs', 'require_all', + 'N3BodyCombiner', 'N3BodyCombinerWithPVs', 'N4BodyCombiner', + 'N4BodyCombinerWithPVs', 'NeutralParticleCombiner', + 'NeutralParticleCombinerWithPVs' +] + + +def require_all(*cuts): + """Return a cut string requiring all arguments. + + Example: + + >>> require_all('PT > {pt_min}', 'DLLK < {dllk_max}') + '(PT > {pt_min}) & (DLLK < {dllk_max})' + """ + cuts = ['({})'.format(c) for c in cuts] + return ' & '.join(cuts) + + +def _dvalgorithm_inputs(particle_inputs, pvs): + """Return a dict suitable for a DVAlgorithm input transform.""" + # ExtraInputs is added by the data handle mixin, so we bundle all inputs + # there to make them available to the scheduler + d = {'Inputs': particle_inputs, 'ExtraInputs': particle_inputs} + if pvs: + d['InputPrimaryVertices'] = pvs + return d + + +def _dvalgorithm_inputs_1(ParticlesA, PrimaryVertices=None): + return _dvalgorithm_inputs([ParticlesA], PrimaryVertices) + + +def _dvalgorithm_inputs_2(ParticlesA, ParticlesB, PrimaryVertices=None): + return _dvalgorithm_inputs([ParticlesA, ParticlesB], PrimaryVertices) + + +def _dvalgorithm_inputs_3(ParticlesA, + ParticlesB, + ParticlesC, + PrimaryVertices=None): + return _dvalgorithm_inputs([ParticlesA, ParticlesB, ParticlesC], + PrimaryVertices) + + +def _dvalgorithm_inputs_4(ParticlesA, + ParticlesB, + ParticlesC, + ParticlesD, + PrimaryVertices=None): + return _dvalgorithm_inputs( + [ParticlesA, ParticlesB, ParticlesC, ParticlesD], PrimaryVertices) + + +def _dvalgorithm_inputs_5(ParticlesA, + ParticlesB, + ParticlesC, + ParticlesD, + ParticlesE, + PrimaryVertices=None): + return _dvalgorithm_inputs( + [ParticlesA, ParticlesB, ParticlesC, ParticlesD, ParticlesE], + PrimaryVertices) + + +def _dvalgorithm_outputs(Particles): + """Return a dict suitable for a DVAlgorithm output transform.""" + # ExtraOutputs is added by the data handle mixin, so we can add the output + # there to make it available to the scheduler + # Could add, for example, output P2PV relations or refitted PVs here as + # well + d = {'Output': Particles, 'ExtraOutputs': [Particles]} + return d + + +def make_dvalgorithm(algorithm, ninputs=1): + """Return a DVAlgorithm that's wrapped to make it behave nicely.""" + # TODO(AP, NN): Workaround for CombineParticles accepting a list of inputs + # We have to have one 'Algorithm' wrapper per number of inputs, as we have + # to have one named input property per input container + input_transform = { + 1: _dvalgorithm_inputs_1, + 2: _dvalgorithm_inputs_2, + 3: _dvalgorithm_inputs_3, + 4: _dvalgorithm_inputs_4, + 5: _dvalgorithm_inputs_5 + }[ninputs] + + def wrapped(**kwargs): + return algorithm( + input_transform=input_transform, + output_transform=_dvalgorithm_outputs, + WriteP2PVRelations=False, + ModifyLocations=False, + **kwargs) + + return wrapped + + +filter_desktop = make_dvalgorithm(FilterDesktop) +# Map number of inputs to the combiner that should be used +combiners = { + 1: make_dvalgorithm(CombineParticles), + 2: make_dvalgorithm(CombineParticles, ninputs=2), + 3: make_dvalgorithm(CombineParticles, ninputs=3), + 4: make_dvalgorithm(CombineParticles, ninputs=4), + 5: make_dvalgorithm(CombineParticles, ninputs=5) +} + +threebodycombiners = { + 1: make_dvalgorithm(N3BodyDecays), + 2: make_dvalgorithm(N3BodyDecays, ninputs=2), + 3: make_dvalgorithm(N3BodyDecays, ninputs=3), + 4: make_dvalgorithm(N3BodyDecays, ninputs=4) +} + +fourbodycombiners = { + 1: make_dvalgorithm(N4BodyDecays), + 2: make_dvalgorithm(N4BodyDecays, ninputs=2), + 3: make_dvalgorithm(N4BodyDecays, ninputs=3), + 4: make_dvalgorithm(N4BodyDecays, ninputs=4) +} + + +def ParticleFilter(particles, **kwargs): + """Return a filter algorithm that takes `particles` as inputs. + + Additional keyword arguments are forwarded to FilterDesktop. + """ + return filter_desktop(ParticlesA=particles, **kwargs).Particles + + +def ParticleFilterWithPVs(particles, pvs, **kwargs): + """Return a filter algorithm that takes `particles` and `pvs` as inputs. + + Additional keyword arguments are forwarded to FilterDesktop. + """ + return ParticleFilter(particles=particles, PrimaryVertices=pvs, **kwargs) + + +def ParticleFilterWithTMVA(name, + particles, + pvs, + mva_code, + mva_name, + xml_file, + bdt_vars, + Key="BDT", + **kwargs): + """Return a filter algorithm that takes `particles`, the `MVACode`, the `MVA_name`, + + an `XMLFile` and the `BDTVars` as inputs. The `Key` is an optional input. + + Additional keyword arguments are forwarded to FilterDesktop. + """ + + #setup the name for the filter + particlefiltered = ParticleFilterWithPVs( + particles=particles, + pvs=pvs, + Code=mva_code.format(mva_name=mva_name), + **kwargs) + + #setup the names for the DictValue, TMVA and MVADict. + #each tool needs to be named relative to its 'owner' + dv_name = "{owner}.{mva_name}".format( + owner=particlefiltered.producer.name, mva_name=mva_name) + tmva_name = "{owner}.TMVA".format(owner=dv_name) + mvadict_name = "{owner}.MVAdict".format(owner=tmva_name) + + tmva_source = "LoKi::Hybrid::DictOfFunctors/MVAdict" + dv_source = "LoKi::Hybrid::DictTransform/TMVA" + + Options = {"XMLFile": xml_file, "Name": Key, "KeepVars": "0"} + # Just need to make sure each Configurable is instantied; don't need to + # assign them to anything + TMVAtransform(name=tmva_name, Options=Options, Source=tmva_source) + DictOfFunctors(name=mvadict_name, Variables=bdt_vars) + DictValue(name=dv_name, Key=Key, Source=dv_source) + + return particlefiltered + + +def ParticleCombiner(particles, my_combiners=combiners, **kwargs): + """Return a combiner algorithm that takes `particles` as inputs. + + Additional keyword arguments are forwarded to CombineParticles. + """ + particles = particles if isinstance(particles, list) else [particles] + ninputs = len(particles) + + # Need to dispatch to the right combiner, based on the number of inputs + assert len(my_combiners + ) >= ninputs, 'Do not have a combiner for {} inputs'.format( + ninputs) + combiner = my_combiners[ninputs] + + # Map each input container to an input property name + inputs = { + 'Particles' + letter: p + for p, letter in zip(particles, string.ascii_uppercase) + } + # We need to merge dicts, we make sure we don't have overlapping keys (the + # caller really shouldn't specify ParticleX keys anyway) + assert set(inputs).intersection(kwargs) == set() + kwargs = dict(list(inputs.items()) + list(kwargs.items())) + + return combiner(**kwargs).Particles + + +def N3BodyCombiner(particles, **kwargs): + """Return a N3BodyDecays combiner algorithm that takes particles as inputs. + + Additional keyword arguments are forwarded to N3BodyDecays. + """ + return ParticleCombiner( + particles, my_combiners=threebodycombiners, **kwargs) + + +def N4BodyCombiner(particles, **kwargs): + """Return a N4BodyDecays combiner algorithm that takes particles as inputs. + + Additional keyword arguments are forwarded to N4BodyDecays. + """ + return ParticleCombiner( + particles, my_combiners=fourbodycombiners, **kwargs) + + +def ParticleCombinerWithPVs(particles, pvs, **kwargs): + """Return a combiner algorithm that takes `particles` and `pvs` as inputs. + + Additional keyword arguments are forwarded to CombineParticles. + """ + return ParticleCombiner(particles=particles, PrimaryVertices=pvs, **kwargs) + + +def N3BodyCombinerWithPVs(particles, pvs, **kwargs): + """Return a combiner algorithm that takes `particles` and `pvs` as inputs. + + Additional keyword arguments are forwarded to CombineParticles. + """ + ## TODO: eliminate duplication of code with ParticleCombinerWithPVs + return N3BodyCombiner(particles=particles, PrimaryVertices=pvs, **kwargs) + + +def N4BodyCombinerWithPVs(particles, pvs, **kwargs): + """Return a combiner algorithm that takes `particles` and `pvs` as inputs. + + Additional keyword arguments are forwarded to CombineParticles. + """ + ## TODO: eliminate duplication of code with ParticleCombinerWithPVs + return N4BodyCombiner(particles=particles, PrimaryVertices=pvs, **kwargs) + + +def NeutralParticleCombinerWithPVs(particles, pvs, **kwargs): + """Return a combiner algorithm that takes `particles` and `pvs` as inputs. + + No vertex fit is performed, just momentum addition + + Additional keyword arguments are forwarded to CombineParticles. + """ + return NeutralParticleCombiner( + particles=particles, PrimaryVertices=pvs, **kwargs) + + +def NeutralParticleCombiner(particles, **kwargs): + """Return a combiner algorithm that takes `particles` as input. + No vertex fit is performed, just momentum addition + + Additional keyword arguments are forwarded to CombineParticles. + """ + return ParticleCombiner( + particles=particles, ParticleCombiners={"": "ParticleAdder"}, **kwargs) diff --git a/Phys/DaVinci/python/DaVinci/config.py b/Phys/DaVinci/python/DaVinci/config.py new file mode 100644 index 00000000..e8a7f73c --- /dev/null +++ b/Phys/DaVinci/python/DaVinci/config.py @@ -0,0 +1,128 @@ +############################################################################### +# (c) Copyright 2021 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. # +############################################################################### +"""DaVinci configured using PyConf components. +""" + +from __future__ import absolute_import +import logging +from collections import namedtuple +from PyConf import configurable +from PyConf.Algorithms import DeterministicPrescaler +from PyConf.application import ApplicationOptions, configure_input, configure, make_odin +from PyConf.control_flow import CompositeNode, NodeLogic + +log = logging.getLogger(__name__) + +options = ApplicationOptions(_enabled=False) + + +class DVSelection(namedtuple('DVSelection', + ['node', 'extra_outputs'])): # noqa + """Immutable object fully qualifiying an DaVinci selection. + Copied from HltLine without the prescaler + + Attributes: + node (CompositeNode): the control flow node of the line + + """ + __slots__ = () # do not add __dict__ (preserve immutability) + + def __new__(cls, + name, + algs, + extra_outputs=None): + """Initialize a HltLine from name, algs and prescale. + + Creates a control flow `CompositeNode` with the given `algs` + combined with `LAZY_AND` logic. A `DeterministicPrescaler` is + always inserted even if the prescale is 1. + + Args: + name (str): name of the line + algs: iterable of algorithms + prescale (float): accept fraction of the prescaler + extra_outputs (iterable of 2-tuple): List of (name, DataHandle) pairs. + """ + # prescaler = DeterministicPrescaler( + # AcceptFraction=prescale, + # SeedName=name + "Prescaler", + # ODINLocation=make_odin()) + node = CompositeNode( + #name, (prescaler, ) + tuple(algs), + name, tuple(algs), + combineLogic=NodeLogic.LAZY_AND, + forceOrder=True) + if extra_outputs is None: + extra_outputs = [] + return super(DVSelection, cls).__new__(cls, node, frozenset(extra_outputs)) + + @property + def name(self): + """Selection name""" + return self.node.name + + @property + def output_producer(self): + """Return the producer that defines the output of this line. + + The producer is defined as the last child in the control flow node, + i.e. the last item passed as the `algs` argument to the `HltLine` + constructor. + + If the producer creates no output, None is returned. + """ + children = self.node.children + last = children[-1] + # Could in principle have control node here; will deal with this use + # case if it arises + assert isinstance(last, Algorithm) + # If the last algorithm produces nothing, there is no 'producer' + return last if last.outputs else None + + def produces_output(self): + """Return True if this line produces output.""" + return self.output_producer is not None + + +def dv_node(name,algs,logic=NodeLogic.NONLAZY_OR): + return CompositeNode( + name, + combineLogic=logic, + children=algs, + forceOrder=False) + +def davinci_control_flow(options, dvsels=[]): + options.finalize() + dec = CompositeNode( + 'dv_decision', + combineLogic=NodeLogic.NONLAZY_OR, + children=[dvsel.node for dvsel in dvsels], + forceOrder=False) + + return CompositeNode( + 'davinci', + combineLogic=NodeLogic.NONLAZY_OR, + children=[dec], + forceOrder=True) + +def run_davinci(options, dvsels=[], public_tools=[]): + ''' + DaVinci application control flow + + Args: + options (ApplicationOptions): holder of application options + public_tools (list): list of public `Tool` instances to configure + ''' + config = configure_input(options) + top_dv_node = davinci_control_flow(options, dvsels) + config.update(configure(options,top_dv_node,public_tools=public_tools)) + #print(options) + return config diff --git a/Phys/DaVinci/python/DaVinci/hacks.py b/Phys/DaVinci/python/DaVinci/hacks.py new file mode 100644 index 00000000..377d8e01 --- /dev/null +++ b/Phys/DaVinci/python/DaVinci/hacks.py @@ -0,0 +1,35 @@ +############################################################################### +# (c) Copyright 2019 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. # +############################################################################### +"""Hacks for making legacy and future code work together.""" +from __future__ import absolute_import, division, print_function + +from Configurables import LoKi__Hybrid__Tool + +from PyConf.components import Tool + + +def patched_hybrid_tool(name): + """Return a LoKi::Hybrid::Tool configured for non-DVAlgorithms. + + Some modules import functors that depend on the DVAlgorithm context being + available. The LoKi::Hybrid::Tool tool loads these modules by default, + breaking algorithms that don't inherit from DVAlgorithm, so we remove them + from the list. + """ + # List of modules we will delete from the default list + dv_modules = ['LoKiPhys.decorators', 'LoKiArrayFunctors.decorators'] + dummy = LoKi__Hybrid__Tool('DummyFactoryNotForUse') + + return Tool( + LoKi__Hybrid__Tool, + name='{}HybridFactory'.format(name), + public=True, + Modules=[m for m in dummy.Modules if m not in dv_modules]) diff --git a/Phys/DaVinci/python/DaVinci/standard_particles.py b/Phys/DaVinci/python/DaVinci/standard_particles.py new file mode 100644 index 00000000..b7a7a6c6 --- /dev/null +++ b/Phys/DaVinci/python/DaVinci/standard_particles.py @@ -0,0 +1,666 @@ +############################################################################### +# (c) Copyright 2019 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. # +############################################################################### +"""Maker functions for Particle definitions common across HLT2. + +The Run 2 code makes the sensible choice of creating Particle objects first, +and then filtering these with FilterDesktop instances. Because the +FunctionalParticleMaker can apply LoKi cut strings directly to Track and +ProtoParticle objects, we just do the one step. +""" +from __future__ import absolute_import, division, print_function + +from GaudiKernel.SystemOfUnits import GeV, MeV, mm, picosecond + +from PyConf.Algorithms import ( + FunctionalParticleMaker, + LHCb__Phys__ParticleMakers__PhotonMaker as PhotonMaker, + LHCb__Phys__ParticleMakers__MergedPi0Maker as MergedPi0Maker, + Proto2ChargedBasic, +) +from PyConf.Tools import (LoKi__Hybrid__ProtoParticleFilter as + ProtoParticleFilter, LoKi__Hybrid__TrackSelector as + TrackSelector) + +from PyConf import configurable + +from .algorithms_pyconf import ( + require_all, + ParticleFilter, + ParticleFilterWithPVs, + ParticleCombiner, + ParticleCombinerWithPVs, + NeutralParticleCombinerWithPVs, +) + +from .hacks import patched_hybrid_tool +from RecoConf.reconstruction_objects import ( + make_charged_protoparticles as _make_charged_protoparticles, make_pvs as + _make_pvs, make_neutral_protoparticles as _make_neutral_protoparticles) + +_KAON0_M = 497.611 * MeV # +/- 0.013, PDG, PR D98, 030001 and 2019 update +_LAMBDA_M = 1115.683 * MeV # +/- 0.006, PDG, PR D98, 030001 and 2019 update + + +@configurable +def get_all_track_selector(Code='TrALL', **kwargs): + return TrackSelector(Code=Code, **kwargs) + + +@configurable +def get_long_track_selector(Code='TrALL', **kwargs): + return TrackSelector(Code=require_all('TrLONG', Code), **kwargs) + + +@configurable +def get_down_track_selector(Code='TrALL', **kwargs): + return TrackSelector(Code=require_all('TrDOWNSTREAM', Code), **kwargs) + + +@configurable +def get_upstream_track_selector(Code='TrALL', **kwargs): + return TrackSelector(Code=require_all('TrUPSTREAM', Code), **kwargs) + + +@configurable +def standard_protoparticle_filter(Code='PP_ALL', **kwargs): + return ProtoParticleFilter( + Code=Code, Factory=patched_hybrid_tool('PPFactory'), **kwargs) + + +@configurable +def _make_particles(species, + make_protoparticles=_make_charged_protoparticles, + get_track_selector=get_long_track_selector, + make_protoparticle_filter=standard_protoparticle_filter): + """ creates LHCb::Particles from LHCb::ProtoParticles """ + particles = FunctionalParticleMaker( + InputProtoParticles=make_protoparticles(), + ParticleID=species, + TrackSelector=get_track_selector(), + ProtoParticleFilter=make_protoparticle_filter()).Particles + return particles + + +@configurable +def _make_ChargedBasics( + species, + make_protoparticles=_make_charged_protoparticles, + get_track_selector=get_long_track_selector, + make_protoparticle_filter=standard_protoparticle_filter): + """ creates LHCb::v2::ChargedBasics from LHCb::ProtoParticles """ + particles = Proto2ChargedBasic( + InputProtoParticles=make_protoparticles(), + ParticleID=species, + TrackSelector=get_track_selector(), + ProtoParticleFilter=make_protoparticle_filter()).Particles + return particles + + +@configurable +def _make_all_ChargedBasics(species): + return _make_ChargedBasics( + species=species, + get_track_selector=get_all_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +@configurable +def _make_long_ChargedBasics(species): + return _make_ChargedBasics( + species=species, + get_track_selector=get_long_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +def make_long_cb_electrons(): + return _make_long_ChargedBasics('electron') + + +def make_long_cb_muons(): + return _make_long_ChargedBasics('muon') + + +def make_long_cb_protons(): + return _make_long_ChargedBasics('proton') + + +def make_long_cb_kaons(): + return _make_long_ChargedBasics('kaon') + + +def make_long_cb_pions(): + return _make_long_ChargedBasics('pion') + + +def make_has_rich_long_cb_kaons(): + with standard_protoparticle_filter.bind(Code='PP_HASRICH'): + return make_long_cb_kaons() + + +def make_has_rich_long_cb_pions(): + with standard_protoparticle_filter.bind(Code='PP_HASRICH'): + return make_long_cb_pions() + + +def make_all_cb_electrons(): + return _make_all_ChargedBasics('electron') + + +def make_all_cb_muons(): + return _make_all_ChargedBasics('muon') + + +def make_all_cb_protons(): + return _make_all_ChargedBasics('proton') + + +def make_all_cb_kaons(): + return _make_all_ChargedBasics('kaon') + + +def make_all_cb_pions(): + return _make_all_ChargedBasics('pion') + + +@configurable +def make_photons(make_neutral_protoparticles=_make_neutral_protoparticles, + pvs=_make_pvs, + **kwargs): + """ creates photon LHCb::Particles from LHCb::ProtoParticles (PVs are optional) """ + particles = PhotonMaker( + InputProtoParticles=make_neutral_protoparticles(), + InputPrimaryVertices=pvs(), + **kwargs).Particles + return particles + + +@configurable +def make_resolved_pi0s(particles=make_photons, + mass_window=30. * MeV, + pvs=_make_pvs, + PtCut=0. * MeV, + **kwargs): + comb_code = require_all("ADAMASS('pi0') < {mass_window}").format( + mass_window=mass_window) + mother_code = require_all("PT > {PtCut}").format(PtCut=PtCut) + return NeutralParticleCombinerWithPVs( + particles=particles(**kwargs), + pvs=pvs(), + DecayDescriptors=["pi0 -> gamma gamma"], + CombinationCut=comb_code, + MotherCut=mother_code) + + +@configurable +def make_merged_pi0s(mass_window=60. * MeV, + PtCut=2000. * MeV, + make_neutral_protoparticles=_make_neutral_protoparticles, + pvs=_make_pvs, + **kwargs): + particles = MergedPi0Maker( + InputProtoParticles=make_neutral_protoparticles(), + InputPrimaryVertices=pvs(), + MassWindow=mass_window, + PtCut=PtCut, + **kwargs).Particles + return particles + + +#Long particles +def make_long_electrons_no_brem(): + return _make_particles( + species="electron", + get_track_selector=get_long_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +def make_long_pions(): + return _make_particles( + species="pion", + get_track_selector=get_long_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +def make_long_kaons(): + return _make_particles( + species="kaon", + get_track_selector=get_long_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +def make_long_protons(): + return _make_particles( + species="proton", + get_track_selector=get_long_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +def make_long_muons(): + return _make_particles( + species="muon", + get_track_selector=get_long_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +#Down particles +def make_down_pions(): + return _make_particles( + species="pion", + get_track_selector=get_down_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +def make_down_kaons(): + return _make_particles( + species="kaon", + get_track_selector=get_down_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +def make_down_protons(): + return _make_particles( + species="proton", + get_track_selector=get_down_track_selector, + make_protoparticle_filter=standard_protoparticle_filter) + + +@configurable +def make_phi2kk(am_max=1100. * MeV, adoca_chi2=30, vchi2=25.0): + kaons = make_long_kaons() + descriptors = ['phi(1020) -> K+ K-'] + combination_code = require_all("AM < {am_max}", + "ADOCACHI2CUT({adoca_chi2}, '')").format( + am_max=am_max, adoca_chi2=adoca_chi2) + vertex_code = "(VFASPF(VCHI2) < {vchi2})".format(vchi2=vchi2) + return ParticleCombiner( + particles=kaons, + DecayDescriptors=descriptors, + CombinationCut=combination_code, + MotherCut=vertex_code) + + +# Make V0s +def _make_long_for_V0(particles, pvs): + code = require_all("BPVVALID()", "MIPCHI2DV(PRIMARY)>36") + return ParticleFilterWithPVs(particles, pvs, Code=code) + + +def _make_down_for_V0(particles): + code = require_all("P>3000*MeV", "PT > 175.*MeV") + return ParticleFilter(particles, Code=code) + + +def make_long_pions_for_V0(): + return _make_long_for_V0(make_long_pions(), _make_pvs()) + + +def make_long_protons_for_V0(): + return _make_long_for_V0(make_long_protons(), _make_pvs()) + + +def make_down_pions_for_V0(): + return _make_down_for_V0(make_down_pions()) + + +def make_down_protons_for_V0(): + return _make_down_for_V0(make_down_protons()) + + +@configurable +def _make_V0LL(particles, + descriptors, + pname, + pvs, + am_dmass=50 * MeV, + m_dmass=35 * MeV, + vchi2pdof_max=30, + bpvltime_min=2.0 * picosecond): + """Make long-long V0 -> h+ h'- candidates + Initial implementation a replication of the old Hlt2SharedParticles + """ + combination_code = require_all("ADAMASS('{pname}') < {am_dmass}").format( + pname=pname, am_dmass=am_dmass) + vertex_code = require_all("ADMASS('{pname}')<{m_dmass}", + "CHI2VXNDOF<{vchi2pdof_max}", + "BPVLTIME() > {bpvltime_min}").format( + pname=pname, + m_dmass=m_dmass, + vchi2pdof_max=vchi2pdof_max, + bpvltime_min=bpvltime_min) + return ParticleCombinerWithPVs( + particles=particles, + pvs=pvs, + DecayDescriptors=descriptors, + CombinationCut=combination_code, + MotherCut=vertex_code) + + +@configurable +def _make_V0DD(particles, + descriptors, + pvs, + am_min=_KAON0_M - 80 * MeV, + am_max=_KAON0_M + 80 * MeV, + m_min=_KAON0_M - 64 * MeV, + m_max=_KAON0_M + 64 * MeV, + vchi2pdof_max=30, + bpvvdz_min=400 * mm): + """Make down-down V0 -> h+ h'- candidates + Initial implementation a replication of the old Hlt2SharedParticles + """ + combination_code = require_all("in_range({am_min}, AM, {am_max})").format( + am_min=am_min, am_max=am_max) + vertex_code = require_all("in_range({m_min}, M, {m_max})", + "CHI2VXNDOF<{vchi2pdof_max}", + "BPVVDZ() > {bpvvdz_min}").format( + m_min=m_min, + m_max=m_max, + vchi2pdof_max=vchi2pdof_max, + bpvvdz_min=bpvvdz_min) + return ParticleCombinerWithPVs( + particles=particles, + pvs=pvs, + DecayDescriptors=descriptors, + CombinationCut=combination_code, + MotherCut=vertex_code) + + +def make_KsLL(): + pions = make_long_pions_for_V0() + descriptors = ["KS0 -> pi+ pi-"] + return _make_V0LL( + particles=[pions], + descriptors=descriptors, + pname='KS0', + pvs=_make_pvs()) + + +def make_KsDD(): + pions = make_down_pions_for_V0() + descriptors = ["KS0 -> pi+ pi-"] + return _make_V0DD( + particles=[pions], descriptors=descriptors, pvs=_make_pvs()) + + +def make_LambdaLL(): + pions = make_long_pions_for_V0() + protons = make_long_protons_for_V0() + descriptors = ["[Lambda0 -> p+ pi-]cc"] + return _make_V0LL( + particles=[pions, protons], + descriptors=descriptors, + pname='Lambda0', + pvs=_make_pvs(), + am_dmass=50 * MeV, + m_dmass=20 * MeV, + vchi2pdof_max=30, + bpvltime_min=2.0 * picosecond) + + +@configurable +def make_LambdaDD(): + pions = make_down_pions_for_V0() + protons = make_down_protons_for_V0() + descriptors = ["[Lambda0 -> p+ pi-]cc"] + return _make_V0DD( + particles=[pions, protons], + descriptors=descriptors, + pvs=_make_pvs(), + am_min=_LAMBDA_M - 80 * MeV, + am_max=_LAMBDA_M + 80 * MeV, + m_min=_LAMBDA_M - 21 * MeV, + m_max=_LAMBDA_M + 24 * MeV, + vchi2pdof_max=30, + bpvvdz_min=400 * mm) + + +# Make pions +@configurable +def make_has_rich_long_pions(): + with standard_protoparticle_filter.bind(Code='PP_HASRICH'): + return make_long_pions() + + +@configurable +def make_has_rich_down_pions(): + with standard_protoparticle_filter.bind(Code='PP_HASRICH'): + return make_down_pions() + + +# Make kaons +@configurable +def make_has_rich_long_kaons(): + with standard_protoparticle_filter.bind(Code='PP_HASRICH'): + return make_long_kaons() + + +@configurable +def make_has_rich_down_kaons(): + with standard_protoparticle_filter.bind(Code='PP_HASRICH'): + return make_down_kaons() + + +# Make protons +@configurable +def make_has_rich_long_protons(): + with standard_protoparticle_filter.bind(Code='PP_HASRICH'): + return make_long_protons() + + +@configurable +def make_has_rich_down_protons(): + with standard_protoparticle_filter.bind(Code='PP_HASRICH'): + return make_down_protons() + + +@configurable +def make_detached_mumu(probnn_mu=0.2, + pt_mu=0. * GeV, + minipchi2=9., + trghostprob=0.25, + adocachi2cut=30, + bpvvdchi2=30, + vfaspfchi2ndof=10): + #def make_detached_mumu(probnn_mu=-0.2, pt_mu=0.*GeV, minipchi2=0., trghostprob=0.925, adocachi2cut=30, bpvvdchi2=30, vfaspfchi2ndof=10): + muons = make_long_muons() + descriptors = ['J/psi(1S) -> mu+ mu-', '[J/psi(1S) -> mu+ mu+]cc'] + daughters_code = { + 'mu+': + '(PROBNNmu > {probnn_mu}) & (PT > {pt_mu}) & (MIPCHI2DV(PRIMARY) > {minipchi2}) & (TRGHOSTPROB < {trghostprob})' + .format( + probnn_mu=probnn_mu, + pt_mu=pt_mu, + minipchi2=minipchi2, + trghostprob=trghostprob), + 'mu-': + '(PROBNNmu > {probnn_mu}) & (PT > {pt_mu}) & (MIPCHI2DV(PRIMARY) > {minipchi2}) & (TRGHOSTPROB < {trghostprob})' + .format( + probnn_mu=probnn_mu, + pt_mu=pt_mu, + minipchi2=minipchi2, + trghostprob=trghostprob) + } + combination_code = "ADOCACHI2CUT({adocachi2cut}, '')".format( + adocachi2cut=adocachi2cut) + vertex_code = require_all( + "(VFASPF(VCHI2/VDOF) < {vfaspfchi2ndof}) & (BPVVDCHI2() > {bpvvdchi2})" + ).format( + vfaspfchi2ndof=vfaspfchi2ndof, bpvvdchi2=bpvvdchi2) + + return ParticleCombinerWithPVs( + particles=muons, + pvs=_make_pvs(), + DecayDescriptors=descriptors, + DaughtersCuts=daughters_code, + CombinationCut=combination_code, + MotherCut=vertex_code) + + +#Update to ProbNNe once the variables are ready +@configurable +def make_detached_ee(probnn_e=2, + pt_e=0.25 * GeV, + minipchi2=9., + trghostprob=0.25, + adocachi2cut=30, + bpvvdchi2=30, + vfaspfchi2ndof=10): + electrons = make_long_electrons_no_brem() + descriptors = ['J/psi(1S) -> e+ e-', '[J/psi(1S) -> e+ e+]cc'] + daughters_code = { + 'e+': + '(PIDe > {probnn_e}) & (PT > {pt_e}) & (MIPCHI2DV(PRIMARY) > {minipchi2}) & (TRGHOSTPROB < {trghostprob})' + .format( + probnn_e=probnn_e, + pt_e=pt_e, + minipchi2=minipchi2, + trghostprob=trghostprob), + 'e-': + '(PIDe > {probnn_e}) & (PT > {pt_e}) & (MIPCHI2DV(PRIMARY) > {minipchi2}) & (TRGHOSTPROB < {trghostprob})' + .format( + probnn_e=probnn_e, + pt_e=pt_e, + minipchi2=minipchi2, + trghostprob=trghostprob) + } + combination_code = require_all("ADOCACHI2CUT({adocachi2cut}, '')").format( + adocachi2cut=adocachi2cut) + vertex_code = require_all( + "(VFASPF(VCHI2/VDOF) < {vfaspfchi2ndof}) & (BPVVDCHI2() > {bpvvdchi2})" + ).format( + vfaspfchi2ndof=vfaspfchi2ndof, bpvvdchi2=bpvvdchi2) + return ParticleCombinerWithPVs( + particles=electrons, + pvs=_make_pvs(), + DecayDescriptors=descriptors, + DaughtersCuts=daughters_code, + CombinationCut=combination_code, + MotherCut=vertex_code) + + +@configurable +def make_detached_mue(probnn_mu=0.2, + pt_mu=0. * GeV, + probnn_e=2, + pt_e=0.25 * GeV, + minipchi2=9., + trghostprob=0.25, + adocachi2cut=30, + bpvvdchi2=30, + vfaspfchi2ndof=10): + muons = make_long_muons() + electrons = make_long_electrons_no_brem() + descriptors = ['[J/psi(1S) -> mu+ e-]cc', '[J/psi(1S) -> mu+ e+]cc'] + daughters_code = { + 'mu+': + '(PROBNNmu > {probnn_mu}) & (PT > {pt_mu}) & (MIPCHI2DV(PRIMARY) > {minipchi2}) & (TRGHOSTPROB < {trghostprob})' + .format( + probnn_mu=probnn_mu, + pt_mu=pt_mu, + minipchi2=minipchi2, + trghostprob=trghostprob), + 'mu-': + '(PROBNNmu > {probnn_mu}) & (PT > {pt_mu}) & (MIPCHI2DV(PRIMARY) > {minipchi2}) & (TRGHOSTPROB < {trghostprob})' + .format( + probnn_mu=probnn_mu, + pt_mu=pt_mu, + minipchi2=minipchi2, + trghostprob=trghostprob), + 'e+': + '(PIDe > {probnn_e}) & (PT > {pt_e}) & (MIPCHI2DV(PRIMARY) > {minipchi2}) & (TRGHOSTPROB < {trghostprob})' + .format( + probnn_e=probnn_e, + pt_e=pt_e, + minipchi2=minipchi2, + trghostprob=trghostprob), + 'e-': + '(PIDe > {probnn_e}) & (PT > {pt_e}) & (MIPCHI2DV(PRIMARY) > {minipchi2}) & (TRGHOSTPROB < {trghostprob})' + .format( + probnn_e=probnn_e, + pt_e=pt_e, + minipchi2=minipchi2, + trghostprob=trghostprob) + } + combination_code = require_all("ADOCACHI2CUT({adocachi2cut}, '')").format( + adocachi2cut=adocachi2cut) + vertex_code = require_all( + "(VFASPF(VCHI2/VDOF) < {vfaspfchi2ndof}) & (BPVVDCHI2() > {bpvvdchi2})" + ).format( + vfaspfchi2ndof=vfaspfchi2ndof, bpvvdchi2=bpvvdchi2) + return ParticleCombinerWithPVs( + particles=[muons, electrons], + pvs=_make_pvs(), + DecayDescriptors=descriptors, + DaughtersCuts=daughters_code, + CombinationCut=combination_code, + MotherCut=vertex_code) + + +# Make muons +@configurable +def make_ismuon_long_muon(): + with standard_protoparticle_filter.bind(Code='PP_ISMUON'): + return make_long_muons() + + +@configurable +def make_dimuon_base(name='DiMuonBaseCombiner', maxVCHI2PDOF=25): + """Basic dimuon without any requirements but common vertex + Please DO NOT add pt requirements here: + a dedicated (tighter) dimuon filter is implemented in the dimuon module. + """ + + # get the long muons + muons = make_ismuon_long_muon() + + # require that the muons come from the same vertex + mother_code = require_all("VFASPF(VCHI2PDOF) < {vchi2}").format( + vchi2=maxVCHI2PDOF) + + return ParticleCombiner( + name=name, + particles=muons, + DecayDescriptors=['J/psi(1S) -> mu+ mu-'], + CombinationCut='AALL', + MotherCut=mother_code) + + +@configurable +def make_mass_constrained_jpsi2mumu(name='MassConstrJpsi2MuMuMaker', + jpsi_maker=make_dimuon_base, + pid_mu=0, + pt_mu=0.5 * GeV, + admass=250. * MeV, + adoca_chi2=20, + vchi2=16): + """Make the Jpsi, starting from dimuons""" + + # get the dimuons with basic cuts (only vertexing) + # note that the make_dimuon_base combiner uses vertexChi2/ndof < 25, + # which is looser than the vertexChi2 < 16 required here + dimuons = jpsi_maker() + + code = require_all( + 'ADMASS("J/psi(1S)") < {admass}', + 'DOCACHI2MAX < {adoca_chi2}', + 'VFASPF(VCHI2) < {vchi2}', + 'INTREE(("mu+" == ABSID) & (PIDmu > {pid_mu}))', + 'INTREE(("mu+" == ABSID) & (PT > {pt_mu}))', + #'MFIT', # not really needed + ).format( + admass=admass, + adoca_chi2=adoca_chi2, + vchi2=vchi2, + pid_mu=pid_mu, + pt_mu=pt_mu, + ) + + return ParticleFilter(dimuons, name=name, Code=code) diff --git a/Phys/DaVinci/tests/selection.py b/Phys/DaVinci/tests/selection.py new file mode 100644 index 00000000..8d5dc2df --- /dev/null +++ b/Phys/DaVinci/tests/selection.py @@ -0,0 +1,42 @@ +from PyConf import configurable +from PyConf.Algorithms import GaudiHistoAlgorithm, FunctionalParticleMaker +from DaVinci import options, run_davinci, dv_node, DVSelection +# +from RecoConf.hlt1_tracking import require_pvs +from RecoConf.reconstruction_objects import (make_pvs, make_charged_protoparticles, + upfront_reconstruction, make_tracks) +from RecoConf.global_tools import stateProvider_with_simplified_geom +from PyConf.control_flow import NodeLogic +from PyConf.Tools import (LoKi__Hybrid__ProtoParticleFilter as ProtoParticleFilter, + LoKi__Hybrid__TrackSelector as TrackSelector) + + +# print control flow and data flow graphs +options.control_flow_file = 'control_flow.gv' +options.data_flow_file = 'data_flow.gv' + +options.ntuple_file = 'DVU_test-ntp.root' +options.histo_file = 'DVU_test-his.root' + +# Setup dataset +options.evt_max = 10 +options.set_input_and_conds_from_testfiledb('Upgrade_Bd2KstarMuMu') +#options.set_input_and_conds_from_testfiledb('upgrade-magdown-sim09c-up02-reco-up01-minbias-ldst') + +options.input_raw_format = 4.3 + +print(options) + +# check tracks: +from DaVinciU.standard_particles import make_detached_mumu, make_mass_constrained_jpsi2mumu + +sel = DVSelection(name="DVselection", + algs=upfront_reconstruction() + [make_detached_mumu()] ) +sel2= DVSelection(name="DVselection2", + algs=upfront_reconstruction() + [make_mass_constrained_jpsi2mumu()] ) + + + +# run davinci +public_tools = [stateProvider_with_simplified_geom()] +run_davinci(options, [sel, sel2], public_tools) diff --git a/Phys/DaVinci/tests/simple_histos.py b/Phys/DaVinci/tests/simple_histos.py new file mode 100644 index 00000000..5a5242bc --- /dev/null +++ b/Phys/DaVinci/tests/simple_histos.py @@ -0,0 +1,20 @@ +from PyConf import configurable +from PyConf.Algorithms import GaudiHistoAlgorithm +from DaVinci import options, run_davinci, dv_node + +# print control flow and data flow graphs +options.control_flow_file = 'control_flow.gv' +options.data_flow_file = 'data_flow.gv' + +options.ntuple_file = 'DVU_test-ntp.root' +options.histo_file = 'DVU_test-his.root' + +# Setup dataset +options.evt_max = 100 +options.set_input_and_conds_from_testfiledb('Upgrade_Bd2KstarMuMu') + +# define algorithm +simple_histos = GaudiHistoAlgorithm(name="SimpleHistos",HistoPrint=True) + +# run davinci +run_davinci(options, [dv_node('commmon',[simple_histos])]) -- GitLab From 70858c4701837b4ace130a4c03c3300ad48ff65c Mon Sep 17 00:00:00 2001 From: Maurizio Martinelli Date: Thu, 11 Feb 2021 14:22:15 +0100 Subject: [PATCH 02/21] add dependencies on Moore --- CMakeLists.txt | 1 + Phys/DaVinci/CMakeLists.txt | 3 ++- Phys/DaVinci/python/DaVinci/__init__.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c5befcb9..182cd997 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ find_package(GaudiProject) # Declare project name and version gaudi_project(DaVinci v52r0 USE Analysis v32r0 + Moore v51r2 DATA AppConfig VERSION v3r* FieldMap VERSION v5r* ParamFiles VERSION v8r* diff --git a/Phys/DaVinci/CMakeLists.txt b/Phys/DaVinci/CMakeLists.txt index 0a060354..ffb4d9ce 100644 --- a/Phys/DaVinci/CMakeLists.txt +++ b/Phys/DaVinci/CMakeLists.txt @@ -21,7 +21,8 @@ gaudi_depends_on_subdirs(Calo/CaloDAQ GaudiPython GaudiSvc Sim/SimComponents - Kernel/FSRAlgs) + Kernel/FSRAlgs + Hlt/RecoConf) find_package(HepMC) diff --git a/Phys/DaVinci/python/DaVinci/__init__.py b/Phys/DaVinci/python/DaVinci/__init__.py index 3870abce..d271ea61 100644 --- a/Phys/DaVinci/python/DaVinci/__init__.py +++ b/Phys/DaVinci/python/DaVinci/__init__.py @@ -12,6 +12,6 @@ from __future__ import absolute_import from .ConfigurationUpgrade import data, mc, main - +from .config import options,run_davinci,dv_node,DVSelection __all__ = ('data', 'mc', 'main') -- GitLab From 60e8e0cedd8a96c4b83dfb6c2982be452afb0c67 Mon Sep 17 00:00:00 2001 From: Maurizio Martinelli Date: Thu, 11 Feb 2021 14:28:46 +0100 Subject: [PATCH 03/21] updated copyright for test files --- Phys/DaVinci/tests/selection.py | 10 ++++++++++ Phys/DaVinci/tests/simple_histos.py | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/Phys/DaVinci/tests/selection.py b/Phys/DaVinci/tests/selection.py index 8d5dc2df..eb96975f 100644 --- a/Phys/DaVinci/tests/selection.py +++ b/Phys/DaVinci/tests/selection.py @@ -1,3 +1,13 @@ +############################################################################## +# (c) Copyright 2020-2021 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. # +############################################################################### from PyConf import configurable from PyConf.Algorithms import GaudiHistoAlgorithm, FunctionalParticleMaker from DaVinci import options, run_davinci, dv_node, DVSelection diff --git a/Phys/DaVinci/tests/simple_histos.py b/Phys/DaVinci/tests/simple_histos.py index 5a5242bc..2240d114 100644 --- a/Phys/DaVinci/tests/simple_histos.py +++ b/Phys/DaVinci/tests/simple_histos.py @@ -1,3 +1,13 @@ +############################################################################## +# (c) Copyright 2020-2021 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. # +############################################################################### from PyConf import configurable from PyConf.Algorithms import GaudiHistoAlgorithm from DaVinci import options, run_davinci, dv_node -- GitLab From 5d6f2b103aea9d75440e9baf39496ca59705d1db Mon Sep 17 00:00:00 2001 From: Gitlab CI Date: Thu, 11 Feb 2021 13:23:00 +0000 Subject: [PATCH 04/21] Fixed formatting patch generated by https://gitlab.cern.ch/lhcb/DaVinci/-/jobs/12092002 --- Phys/DaVinci/python/DaVinci/__init__.py | 2 +- Phys/DaVinci/python/DaVinci/config.py | 40 ++++++++++++------------- Phys/DaVinci/tests/selection.py | 21 +++++++------ Phys/DaVinci/tests/simple_histos.py | 4 +-- 4 files changed, 32 insertions(+), 35 deletions(-) diff --git a/Phys/DaVinci/python/DaVinci/__init__.py b/Phys/DaVinci/python/DaVinci/__init__.py index d271ea61..e3bd7f80 100644 --- a/Phys/DaVinci/python/DaVinci/__init__.py +++ b/Phys/DaVinci/python/DaVinci/__init__.py @@ -12,6 +12,6 @@ from __future__ import absolute_import from .ConfigurationUpgrade import data, mc, main -from .config import options,run_davinci,dv_node,DVSelection +from .config import options, run_davinci, dv_node, DVSelection __all__ = ('data', 'mc', 'main') diff --git a/Phys/DaVinci/python/DaVinci/config.py b/Phys/DaVinci/python/DaVinci/config.py index e8a7f73c..1f415a96 100644 --- a/Phys/DaVinci/python/DaVinci/config.py +++ b/Phys/DaVinci/python/DaVinci/config.py @@ -25,7 +25,7 @@ options = ApplicationOptions(_enabled=False) class DVSelection(namedtuple('DVSelection', - ['node', 'extra_outputs'])): # noqa + ['node', 'extra_outputs'])): # noqa """Immutable object fully qualifiying an DaVinci selection. Copied from HltLine without the prescaler @@ -35,10 +35,7 @@ class DVSelection(namedtuple('DVSelection', """ __slots__ = () # do not add __dict__ (preserve immutability) - def __new__(cls, - name, - algs, - extra_outputs=None): + def __new__(cls, name, algs, extra_outputs=None): """Initialize a HltLine from name, algs and prescale. Creates a control flow `CompositeNode` with the given `algs` @@ -57,12 +54,14 @@ class DVSelection(namedtuple('DVSelection', # ODINLocation=make_odin()) node = CompositeNode( #name, (prescaler, ) + tuple(algs), - name, tuple(algs), + name, + tuple(algs), combineLogic=NodeLogic.LAZY_AND, forceOrder=True) if extra_outputs is None: extra_outputs = [] - return super(DVSelection, cls).__new__(cls, node, frozenset(extra_outputs)) + return super(DVSelection, cls).__new__(cls, node, + frozenset(extra_outputs)) @property def name(self): @@ -92,26 +91,25 @@ class DVSelection(namedtuple('DVSelection', return self.output_producer is not None -def dv_node(name,algs,logic=NodeLogic.NONLAZY_OR): +def dv_node(name, algs, logic=NodeLogic.NONLAZY_OR): return CompositeNode( - name, - combineLogic=logic, - children=algs, - forceOrder=False) + name, combineLogic=logic, children=algs, forceOrder=False) + def davinci_control_flow(options, dvsels=[]): options.finalize() dec = CompositeNode( - 'dv_decision', - combineLogic=NodeLogic.NONLAZY_OR, - children=[dvsel.node for dvsel in dvsels], - forceOrder=False) + 'dv_decision', + combineLogic=NodeLogic.NONLAZY_OR, + children=[dvsel.node for dvsel in dvsels], + forceOrder=False) return CompositeNode( - 'davinci', - combineLogic=NodeLogic.NONLAZY_OR, - children=[dec], - forceOrder=True) + 'davinci', + combineLogic=NodeLogic.NONLAZY_OR, + children=[dec], + forceOrder=True) + def run_davinci(options, dvsels=[], public_tools=[]): ''' @@ -123,6 +121,6 @@ def run_davinci(options, dvsels=[], public_tools=[]): ''' config = configure_input(options) top_dv_node = davinci_control_flow(options, dvsels) - config.update(configure(options,top_dv_node,public_tools=public_tools)) + config.update(configure(options, top_dv_node, public_tools=public_tools)) #print(options) return config diff --git a/Phys/DaVinci/tests/selection.py b/Phys/DaVinci/tests/selection.py index eb96975f..d9fb93ea 100644 --- a/Phys/DaVinci/tests/selection.py +++ b/Phys/DaVinci/tests/selection.py @@ -13,13 +13,13 @@ from PyConf.Algorithms import GaudiHistoAlgorithm, FunctionalParticleMaker from DaVinci import options, run_davinci, dv_node, DVSelection # from RecoConf.hlt1_tracking import require_pvs -from RecoConf.reconstruction_objects import (make_pvs, make_charged_protoparticles, - upfront_reconstruction, make_tracks) +from RecoConf.reconstruction_objects import ( + make_pvs, make_charged_protoparticles, upfront_reconstruction, make_tracks) from RecoConf.global_tools import stateProvider_with_simplified_geom from PyConf.control_flow import NodeLogic -from PyConf.Tools import (LoKi__Hybrid__ProtoParticleFilter as ProtoParticleFilter, - LoKi__Hybrid__TrackSelector as TrackSelector) - +from PyConf.Tools import (LoKi__Hybrid__ProtoParticleFilter as + ProtoParticleFilter, LoKi__Hybrid__TrackSelector as + TrackSelector) # print control flow and data flow graphs options.control_flow_file = 'control_flow.gv' @@ -40,12 +40,11 @@ print(options) # check tracks: from DaVinciU.standard_particles import make_detached_mumu, make_mass_constrained_jpsi2mumu -sel = DVSelection(name="DVselection", - algs=upfront_reconstruction() + [make_detached_mumu()] ) -sel2= DVSelection(name="DVselection2", - algs=upfront_reconstruction() + [make_mass_constrained_jpsi2mumu()] ) - - +sel = DVSelection( + name="DVselection", algs=upfront_reconstruction() + [make_detached_mumu()]) +sel2 = DVSelection( + name="DVselection2", + algs=upfront_reconstruction() + [make_mass_constrained_jpsi2mumu()]) # run davinci public_tools = [stateProvider_with_simplified_geom()] diff --git a/Phys/DaVinci/tests/simple_histos.py b/Phys/DaVinci/tests/simple_histos.py index 2240d114..01f6fc5f 100644 --- a/Phys/DaVinci/tests/simple_histos.py +++ b/Phys/DaVinci/tests/simple_histos.py @@ -24,7 +24,7 @@ options.evt_max = 100 options.set_input_and_conds_from_testfiledb('Upgrade_Bd2KstarMuMu') # define algorithm -simple_histos = GaudiHistoAlgorithm(name="SimpleHistos",HistoPrint=True) +simple_histos = GaudiHistoAlgorithm(name="SimpleHistos", HistoPrint=True) # run davinci -run_davinci(options, [dv_node('commmon',[simple_histos])]) +run_davinci(options, [dv_node('commmon', [simple_histos])]) -- GitLab From ece7df6484a646ebfd777a301b724c03c74f3022 Mon Sep 17 00:00:00 2001 From: Maurizio Martinelli Date: Thu, 11 Feb 2021 14:35:48 +0100 Subject: [PATCH 05/21] fixed a typo --- Phys/DaVinci/tests/selection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Phys/DaVinci/tests/selection.py b/Phys/DaVinci/tests/selection.py index d9fb93ea..efc23c74 100644 --- a/Phys/DaVinci/tests/selection.py +++ b/Phys/DaVinci/tests/selection.py @@ -38,7 +38,7 @@ options.input_raw_format = 4.3 print(options) # check tracks: -from DaVinciU.standard_particles import make_detached_mumu, make_mass_constrained_jpsi2mumu +from DaVinci.standard_particles import make_detached_mumu, make_mass_constrained_jpsi2mumu sel = DVSelection( name="DVselection", algs=upfront_reconstruction() + [make_detached_mumu()]) -- GitLab From 24fd2035f39badc75cd384a0335973723a0cac3d Mon Sep 17 00:00:00 2001 From: erodrigu Date: Wed, 17 Feb 2021 13:41:39 +0100 Subject: [PATCH 06/21] Add YAML file for application option default values a la PyConf --- .../options/application-option-defaults.yaml | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 Phys/DaVinci/options/application-option-defaults.yaml diff --git a/Phys/DaVinci/options/application-option-defaults.yaml b/Phys/DaVinci/options/application-option-defaults.yaml new file mode 100644 index 00000000..7b1eafe9 --- /dev/null +++ b/Phys/DaVinci/options/application-option-defaults.yaml @@ -0,0 +1,85 @@ +############################################################################### +# (c) Copyright 2021 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. # +############################################################################### + +# Definitions of, and defaults for, the DaVinci application options. + +auditors: + text: '"""List of auditors to run. Possible common choices include "NameAuditor", "MemoryAuditor", "ChronoAuditor". See Gaudi manual for a full list. Default = []."""' + value: [] +buffer_events: + text: '"""Number of events to pre-fetch if use_iosvc=True. Default = 20000 is reasonable for most machines; it might need to be increased for more modern/powerful machines."""' + value: 20000 +callgrind_profile: + text: '"""Enable callgrind profiling. Default = False."""' + value: False +conddb_tag: + text: '"""Tag for the CondDB."""' + value: '' +control_flow_file: + text: '"""Control flow file name (.gv extension since default output format for the DOT language). Default = '' for no file generation."""' + value: '' +data_flow_file: + text: '"""Data flow file name (.gv extension since default output format for the DOT language). Default = '' for no file generation."""' + value: '' +data_type: + text: '"""Data type, can be ["Upgrade"]."""' + value: 'Upgrade' +dddb_tag: + text: '""" Data type, can be ["Upgrade"] Forwarded to PhysConf, AnalysisConf, DstConf and LHCbApp"""' + value: 'dddb-20171126' +dqflags_tag: + text: '"""Tag for DQFLAGS. Default as set in DDDBConf for DataType """' + value: '' +evt_max: + text: '"""Number of events to analyse. Default = -1 to run over all events."""' + value: -1 +histo_file: + text: '"""Name of output histogram file. Default = ''."""' + value: '' +ignore_dq_flags: + text: '"""If False, process only events with good DQ. Default = False."""' + value: False +input_files: + text: '"""Input data. Default = []. """' + value: [] +input_type: + text: '"""Type of input files, e.g. "DST", "DIGI", "RDST", "MDST", "XDST" or "LDST". Default = DST."""' + value: 'DST' +msg_svc_format: + text: '"""MessageSvc output format.Default = "% F%35W%S %7W%R%T %0W%M"."""' + value: '% F%35W%S %7W%R%T %0W%M' +msg_svc_time_format: + text: '"""MessageSvc time format. Default = "%Y-%m-%d %H:%M:%S UTC"."""' + value: '%Y-%m-%d %H:%M:%S UTC' +ntuple_file: + text: '"""Name of output ntuple file. Default = ''."""' + value: '' +output_level: + text: '"""Set the output level used in the job. Default = INFO=3."""' + value: 3 +print_freq: + text: '"""Frequency at which to print event numbers. Default = 1000."""' + value: 1000 +python_logging_level: + text: '"""Python logger level. Default = logging.WARNING=30."""' + value: 30 +skip_events: + text: '"""Number of events to skip at the beginning. Default = 0."""' + value: 0 +simulation: + text: '"""Boolean to specify simulated samples. Default = False."""' + value: False +user_algorithms: + text: '"""List of user algorithms to run. Default = []."""' + value: [] +use_iosvc: + text: '"""Use an alternative, faster, IIOSvc implementation for MDFs. Default = False."""' + value: False -- GitLab From f7ee49bef6b3a67421be8b60dc50d893c3e37f45 Mon Sep 17 00:00:00 2001 From: erodrigu Date: Wed, 17 Feb 2021 13:42:38 +0100 Subject: [PATCH 07/21] Add DaVinci.application.DVAppOptions class inheriting from PyConf.ApplicationOptions --- Phys/DaVinci/python/DaVinci/application.py | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Phys/DaVinci/python/DaVinci/application.py diff --git a/Phys/DaVinci/python/DaVinci/application.py b/Phys/DaVinci/python/DaVinci/application.py new file mode 100644 index 00000000..44ea1876 --- /dev/null +++ b/Phys/DaVinci/python/DaVinci/application.py @@ -0,0 +1,41 @@ +############################################################################### +# (c) Copyright 2021 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. # +############################################################################### + +import os, yaml + +from PyConf.application import ApplicationOptions + + +def define_app_option_defaults(yaml_file="$DAVINCIROOT/options/application-option-defaults.yaml"): + """ + Define/digest the default values for the application options as described in YAML. + """ + slots, doc = {}, {} + + with open(os.path.expandvars(yaml_file)) as defaults: + config = yaml.safe_load(defaults) + + for key, args in config.items(): + for name, value in args.items(): + if name == 'value': + slots[key] = value + else: + doc[key] = value + + return slots + + +class DVAppOptions(ApplicationOptions): + """ + Enhanced PyConf.application.ApplicationOptions class + with slots defined via a YAML file. + """ + __slots__ = define_app_option_defaults() -- GitLab From 4c11d6a1475b4de2aa21ff5667e7bf653a7e0111 Mon Sep 17 00:00:00 2001 From: erodrigu Date: Wed, 17 Feb 2021 13:43:13 +0100 Subject: [PATCH 08/21] Use new DaVinci.application.DVAppOptions class --- Phys/DaVinci/python/DaVinci/config.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Phys/DaVinci/python/DaVinci/config.py b/Phys/DaVinci/python/DaVinci/config.py index 1f415a96..537dd9da 100644 --- a/Phys/DaVinci/python/DaVinci/config.py +++ b/Phys/DaVinci/python/DaVinci/config.py @@ -16,12 +16,15 @@ import logging from collections import namedtuple from PyConf import configurable from PyConf.Algorithms import DeterministicPrescaler -from PyConf.application import ApplicationOptions, configure_input, configure, make_odin +from PyConf.application import configure_input, configure, make_odin from PyConf.control_flow import CompositeNode, NodeLogic +from DaVinci.application import DVAppOptions + + log = logging.getLogger(__name__) -options = ApplicationOptions(_enabled=False) +options = DVAppOptions(_enabled=False) class DVSelection(namedtuple('DVSelection', -- GitLab From 85d516239999a118133658b492cb9951a12cfb63 Mon Sep 17 00:00:00 2001 From: Gitlab CI Date: Wed, 17 Feb 2021 12:45:02 +0000 Subject: [PATCH 09/21] Fixed formatting patch generated by https://gitlab.cern.ch/lhcb/DaVinci/-/jobs/12189203 --- Phys/DaVinci/python/DaVinci/application.py | 5 +++-- Phys/DaVinci/python/DaVinci/config.py | 1 - 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Phys/DaVinci/python/DaVinci/application.py b/Phys/DaVinci/python/DaVinci/application.py index 44ea1876..f752d745 100644 --- a/Phys/DaVinci/python/DaVinci/application.py +++ b/Phys/DaVinci/python/DaVinci/application.py @@ -14,12 +14,13 @@ import os, yaml from PyConf.application import ApplicationOptions -def define_app_option_defaults(yaml_file="$DAVINCIROOT/options/application-option-defaults.yaml"): +def define_app_option_defaults( + yaml_file="$DAVINCIROOT/options/application-option-defaults.yaml"): """ Define/digest the default values for the application options as described in YAML. """ slots, doc = {}, {} - + with open(os.path.expandvars(yaml_file)) as defaults: config = yaml.safe_load(defaults) diff --git a/Phys/DaVinci/python/DaVinci/config.py b/Phys/DaVinci/python/DaVinci/config.py index 537dd9da..7085d7e6 100644 --- a/Phys/DaVinci/python/DaVinci/config.py +++ b/Phys/DaVinci/python/DaVinci/config.py @@ -21,7 +21,6 @@ from PyConf.control_flow import CompositeNode, NodeLogic from DaVinci.application import DVAppOptions - log = logging.getLogger(__name__) options = DVAppOptions(_enabled=False) -- GitLab From 988287c88804ff4749a5cfacbc7ec28c0fe4d77c Mon Sep 17 00:00:00 2001 From: Maurizio Martinelli Date: Wed, 17 Feb 2021 14:40:10 +0100 Subject: [PATCH 10/21] removed dependency from Hlt/RecoConf and updated test --- .../python/DaVinci/algorithms_pyconf.py | 5 +- Phys/DaVinci/python/DaVinci/data_from_file.py | 322 ++++++++++++++++++ Phys/DaVinci/python/DaVinci/reco_objects.py | 86 +++++ .../python/DaVinci/standard_particles.py | 2 +- Phys/DaVinci/tests/selection.py | 18 +- 5 files changed, 418 insertions(+), 15 deletions(-) create mode 100644 Phys/DaVinci/python/DaVinci/data_from_file.py create mode 100644 Phys/DaVinci/python/DaVinci/reco_objects.py diff --git a/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py b/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py index 7e4c3438..971d2883 100644 --- a/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py +++ b/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py @@ -26,13 +26,14 @@ from Configurables import ( LoKi__Hybrid__DictValue as DictValue, ) -from RecoConf.hlt1_tracking import EmptyFilter +#from RecoConf.hlt1_tracking import EmptyFilter from PyConf.Algorithms import (CombineParticles, FilterDesktop, DaVinci__N3BodyDecays as N3BodyDecays, DaVinci__N4BodyDecays as N4BodyDecays) __all__ = [ - 'EmptyFilter', 'ParticleFilter', 'ParticleCombiner', + #'EmptyFilter', 'ParticleFilter', 'ParticleCombiner', + 'ParticleFilter', 'ParticleCombiner', 'ParticleFilterWithPVs', 'ParticleCombinerWithPVs', 'require_all', 'N3BodyCombiner', 'N3BodyCombinerWithPVs', 'N4BodyCombiner', 'N4BodyCombinerWithPVs', 'NeutralParticleCombiner', diff --git a/Phys/DaVinci/python/DaVinci/data_from_file.py b/Phys/DaVinci/python/DaVinci/data_from_file.py new file mode 100644 index 00000000..69801d8c --- /dev/null +++ b/Phys/DaVinci/python/DaVinci/data_from_file.py @@ -0,0 +1,322 @@ +############################################################################### +# (c) Copyright 2019 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. # +############################################################################### + +###### +### N.B. THIS FILE IS INTENDED TO AVOID DEPENDENCIES ON MOORE, +### IS NEEDED FOR TESTING PURPOSES AND NEEDS TO BE REMOVED IN PRODUCTION +###### + +"""Load data from files and set up unpackers. + +There are two things we have to deal with: + +1. Loading the data from the file in to the TES, done by + Gaudi::Hive::FetchDataFromFile. +2. Unpacking and preparing packed containers, if the 'reconstruction' is + defined as the objects already present in the file. + +In most LHCb applications, step 2 is done for you behind the scenes. The +DataOnDemandSvc is configured in LHCb/GaudiConf/DstConf.py to unpack containers +when they are requested. It also configures adding RICH, MUON, and combined PID +information to ProtoParticles when they're unpacked. Because we don't have the +DataOnDemandSvc here, we have to do this by hand. + +The interesting 'user-facing' exports of this module are: + +* [reco,mc]_from_file(): Dict of names to locations that can be loaded from a file. +* [reco,mc]_unpackers(): Dict from unpacked object name to Algorithm that produces a + container of those objects. +""" +from __future__ import absolute_import, division, print_function +import collections + +from Gaudi.Configuration import ERROR +from Configurables import ( + DataPacking__Unpack_LHCb__MuonPIDPacker_, + DataPacking__Unpack_LHCb__RichPIDPacker_, UnpackCaloHypo, + UnpackProtoParticle, UnpackRecVertex, UnpackTrackFunctional, + UnpackMCParticle, UnpackMCVertex, DataPacking__Unpack_LHCb__MCVPHitPacker_ + as UnpackMCVPHit, DataPacking__Unpack_LHCb__MCUTHitPacker_ as + UnpackMCUTHit, DataPacking__Unpack_LHCb__MCFTHitPacker_ as UnpackMCFTHit, + DataPacking__Unpack_LHCb__MCRichHitPacker_ as UnpackMCRichHit, + DataPacking__Unpack_LHCb__MCEcalHitPacker_ as UnpackMCEcalHit, + DataPacking__Unpack_LHCb__MCHcalHitPacker_ as UnpackMCHcalHit, + DataPacking__Unpack_LHCb__MCMuonHitPacker_ as UnpackMCMuonHit, + DataPacking__Unpack_LHCb__MCRichDigitSummaryPacker_ as RichSumUnPack) + +from PyConf.components import Algorithm, force_location +from PyConf.application import make_data_with_FetchDataFromFile +from PyConf.Tools import (ChargedProtoParticleAddRichInfo, + ChargedProtoParticleAddMuonInfo, + ChargedProtoParticleAddCombineDLLs) + + +def packed_reco_from_file(): + return { + 'PackedPVs': '/Event/pRec/Vertex/Primary', + 'PackedCaloElectrons': '/Event/pRec/Calo/Electrons', + 'PackedCaloPhotons': '/Event/pRec/Calo/Photons', + 'PackedCaloMergedPi0s': '/Event/pRec/Calo/MergedPi0s', + 'PackedCaloSplitPhotons': '/Event/pRec/Calo/SplitPhotons', + 'PackedMuonPIDs': '/Event/pRec/Muon/MuonPID', + 'PackedRichPIDs': '/Event/pRec/Rich/PIDs', + 'PackedTracks': '/Event/pRec/Track/Best', + 'PackedMuonTracks': '/Event/pRec/Track/Muon', + 'PackedNeutralProtos': '/Event/pRec/ProtoP/Neutrals', + 'PackedChargedProtos': '/Event/pRec/ProtoP/Charged', + } + + +def packed_mc_from_file(): + return { + 'PackedMCParticles': '/Event/pSim/MCParticles', + 'PackedMCVertices': '/Event/pSim/MCVertices', + 'PackedMCVPHits': '/Event/pSim/VP/Hits', + 'PackedMCUTHits': '/Event/pSim/UT/Hits', + 'PackedMCFTHits': '/Event/pSim/FT/Hits', + 'PackedMCRichHits': '/Event/pSim/Rich/Hits', + 'PackedMCEcalHits': '/Event/pSim/Ecal/Hits', + 'PackedMCHcalHits': '/Event/pSim/Hcal/Hits', + 'PackedMCMuonHits': '/Event/pSim/Muon/Hits', + 'PackedMCRichDigitSummaries': '/Event/pSim/Rich/DigitSummaries', + } + + +def unpacked_reco_locations(): + # If the structure is not like this, pointers point to to the wrong place... + # The SmartRefs held by the unpacked MC objects only work if we unpack to these specific locations + locations = { + k: v.replace('pRec', 'Rec') + for k, v in packed_reco_from_file().items() + } + return locations + + +def unpacked_mc_locations(): + # If the structure is not like this, pointers point to to the wrong place... + # The SmartRefs held by the unpacked MC objects only work if we unpack to these specific locations + return { + 'PackedMCParticles': '/Event/MC/Particles', + 'PackedMCVertices': '/Event/MC/Vertices', + 'PackedMCVPHits': '/Event/MC/VP/Hits', + 'PackedMCUTHits': '/Event/MC/UT/Hits', + 'PackedMCFTHits': '/Event/MC/FT/Hits', + 'PackedMCRichHits': '/Event/MC/Rich/Hits', + 'PackedMCEcalHits': '/Event/MC/Ecal/Hits', + 'PackedMCHcalHits': '/Event/MC/Hcal/Hits', + 'PackedMCMuonHits': '/Event/MC/Muon/Hits', + 'PackedMCRichDigitSummaries': '/Event/MC/Rich/DigitSummaries', + } + + +def reco_from_file(): + # TODO(AP) should only add the packed data if we're running on Upgrade MC + # where Brunel has already been run + packed_data = packed_reco_from_file() + # raw_event = raw_event_from_file() + # We don't want any keys accidentally overwriting each other + # assert set(packed_data.keys()).intersection(set(raw_event.keys())) == set() + # return dict(list(packed_data.items()) + list(raw_event.items())) + return packed_data + + +def mc_from_file(): + # TODO(AP) should only add the packed data if we're running on Upgrade MC + # where Brunel has already been run + packed_data = packed_mc_from_file() + return packed_data + + +def reco_unpacker(key, configurable, name, **kwargs): + """Return unpacker that reads from file and unpacks to a forced output location.""" + packed_loc = reco_from_file()[key] + unpacked_loc = unpacked_reco_locations()[key] + alg = Algorithm( + configurable, + name=name, + outputs={'OutputName': force_location(unpacked_loc)}, + InputName=make_data_with_FetchDataFromFile(packed_loc), + **kwargs) + return alg + + +def mc_unpacker(key, configurable, name, **kwargs): + """Return unpacker that reads from file and unpacks to a forced output location.""" + packed_loc = mc_from_file()[key] + unpacked_loc = unpacked_mc_locations()[key] + alg = Algorithm( + configurable, + name=name, + outputs={'OutputName': force_location(unpacked_loc)}, + InputName=make_data_with_FetchDataFromFile(packed_loc), + **kwargs) + return alg + + +def make_mc_track_info(): + return make_data_with_FetchDataFromFile('/Event/MC/TrackInfo') + + +def reco_unpackers(): + muonPIDs = reco_unpacker('PackedMuonPIDs', + DataPacking__Unpack_LHCb__MuonPIDPacker_, + 'UnpackMuonPIDs') + richPIDs = reco_unpacker( + 'PackedRichPIDs', + DataPacking__Unpack_LHCb__RichPIDPacker_, + 'UnpackRichPIDs', + OutputLevel=ERROR) + # The OutputLevel above suppresses the following useless warnings (plus more?) + # WARNING DataPacking::Unpack:: Incorrect data version 0 for packing version > 3. Correcting data to version 2. + + # Ordered so that dependents are unpacked first + d = collections.OrderedDict([ + ('PVs', reco_unpacker('PackedPVs', UnpackRecVertex, + 'UnpackRecVertices')), + ('CaloElectrons', + reco_unpacker('PackedCaloElectrons', UnpackCaloHypo, + 'UnpackCaloElectrons')), + ('CaloPhotons', + reco_unpacker('PackedCaloPhotons', UnpackCaloHypo, + 'UnpackCaloPhotons')), + ('CaloMergedPi0s', + reco_unpacker('PackedCaloMergedPi0s', UnpackCaloHypo, + 'UnpackCaloMergedPi0s')), + ('CaloSplitPhotons', + reco_unpacker('PackedCaloSplitPhotons', UnpackCaloHypo, + 'UnpackCaloSplitPhotons')), + ('MuonPIDs', muonPIDs), + ('RichPIDs', richPIDs), + ('Tracks', + reco_unpacker('PackedTracks', UnpackTrackFunctional, + 'UnpackBestTracks')), + ('MuonTracks', + reco_unpacker('PackedMuonTracks', UnpackTrackFunctional, + 'UnpackMuonTracks')), + ('NeutralProtos', + reco_unpacker('PackedNeutralProtos', UnpackProtoParticle, + 'UnpackNeutralProtos')), + ('ChargedProtos', + reco_unpacker( + 'PackedChargedProtos', + UnpackProtoParticle, + 'UnpackChargedProtos', + AddInfo=[ + ChargedProtoParticleAddRichInfo( + InputRichPIDLocation=richPIDs.OutputName), + ChargedProtoParticleAddMuonInfo( + InputMuonPIDLocation=muonPIDs.OutputName), + ChargedProtoParticleAddCombineDLLs() + ])), + ]) + + # Make sure we have consistent names, and that we're unpacking everything + # we load from the file + assert set(['Packed' + k for k in d.keys()]) - set( + packed_reco_from_file().keys()) == set() + + return d + + +def mc_unpackers(): + # Ordered so that dependents are unpacked first + mc_vertices = mc_unpacker('PackedMCVertices', UnpackMCVertex, + 'UnpackMCVertices') + # Make sure that MC particles and MC vertices are unpacked together, + # see https://gitlab.cern.ch/lhcb/LHCb/issues/57 for details. + mc_particles = mc_unpacker( + 'PackedMCParticles', + UnpackMCParticle, + 'UnpackMCParticles', + ExtraInputs=[mc_vertices]) + + mc_vp_hits = mc_unpacker('PackedMCVPHits', UnpackMCVPHit, 'UnpackMCVPHits') + mc_ut_hits = mc_unpacker('PackedMCUTHits', UnpackMCUTHit, 'UnpackMCUTHits') + mc_ft_hits = mc_unpacker('PackedMCFTHits', UnpackMCFTHit, 'UnpackMCFTHits') + mc_rich_hits = mc_unpacker('PackedMCRichHits', UnpackMCRichHit, + 'UnpackMCRichHits') + mc_ecal_hits = mc_unpacker('PackedMCEcalHits', UnpackMCEcalHit, + 'UnpackMCEcalHits') + mc_hcal_hits = mc_unpacker('PackedMCHcalHits', UnpackMCHcalHit, + 'UnpackMCHcalHits') + mc_muon_hits = mc_unpacker('PackedMCMuonHits', UnpackMCMuonHit, + 'UnpackMCMuonHits') + + # RICH Digit summaries + mc_rich_digit_sums = mc_unpacker('PackedMCRichDigitSummaries', + RichSumUnPack, "RichSumUnPack") + + d = collections.OrderedDict([ + ('MCRichDigitSummaries', mc_rich_digit_sums), + ('MCParticles', mc_particles), + ('MCVertices', mc_vertices), + ('MCVPHits', mc_vp_hits), + ('MCUTHits', mc_ut_hits), + ('MCFTHits', mc_ft_hits), + ('MCRichHits', mc_rich_hits), + ('MCEcalHits', mc_ecal_hits), + ('MCHcalHits', mc_hcal_hits), + ('MCMuonHits', mc_muon_hits), + ]) + + # Make sure we have consistent names, and that we're unpacking everything + # we load from the file + assert set(['Packed' + k for k in d.keys()]) - set( + packed_mc_from_file().keys()) == set() + + return d + + +def boole_links_digits_mcparticles(): + """Return a dict of locations for MC linker tables (to mcparticles) created by Boole.""" + locations = { + "EcalDigits": "/Event/Link/Raw/Ecal/Digits", + "FTLiteClusters": "/Event/Link/Raw/FT/LiteClusters", + "HcalDigits": "/Event/Link/Raw/Hcal/Digits", + "MuonDigits": "/Event/Link/Raw/Muon/Digits", + "UTClusters": "/Event/Link/Raw/UT/Clusters", + "VPDigits": "/Event/Link/Raw/VP/Digits", + } + return { + key: make_data_with_FetchDataFromFile(loc) + for key, loc in locations.items() + } + + +def boole_links_digits_mchits(): + """Return a dict of locations for MC linker tables (to mchits) created by Boole. + + These locations are only propagated out of Boole for eXtendend DIGI and DST types. + """ + locations = { + "FTLiteClusters": "/Event/Link/Raw/FT/LiteClusters2MCHits", + "UTClusters": "/Event/Link/Raw/UT/Clusters2MCHits", + "VPDigits": "/Event/Link/Raw/VP/Digits2MCHits", + } + return { + key: make_data_with_FetchDataFromFile(loc) + for key, loc in locations.items() + } + + +def brunel_links(): + """Return a dict of locations for MC linker tables created by Brunel.""" + locations = { + "CaloElectrons": "/Event/Link/Rec/Calo/Electrons", + "CaloMergedPi0s": "/Event/Link/Rec/Calo/MergedPi0s", + "CaloPhotons": "/Event/Link/Rec/Calo/Photons", + "CaloSplitPhotons": "/Event/Link/Rec/Calo/SplitPhotons", + "Tracks": "/Event/Link/Rec/Track/Best", + } + return { + key: make_data_with_FetchDataFromFile(loc) + for key, loc in locations.items() + } diff --git a/Phys/DaVinci/python/DaVinci/reco_objects.py b/Phys/DaVinci/python/DaVinci/reco_objects.py new file mode 100644 index 00000000..9a0ff8fd --- /dev/null +++ b/Phys/DaVinci/python/DaVinci/reco_objects.py @@ -0,0 +1,86 @@ +############################################################################## +# (c) Copyright 2020-2021 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. # +############################################################################### + +###### +### N.B. THIS FILE IS INTENDED TO AVOID DEPENDENCIES ON MOORE, +### IS NEEDED FOR TESTING PURPOSES AND NEEDS TO BE REMOVED IN PRODUCTION +###### + +from PyConf import configurable +from .data_from_file import reco_unpackers + + +def upfront_reconstruction_from_file(): # renamed from upfront_reconstruction + """Return a list DataHandles that define the upfront reconstruction output. + + This differs from `reconstruction` as it should not be used as inputs to + other algorithms, but only to define the control flow, i.e. the return + value of this function should be ran before all HLT2 lines. + + """ + return list(reco_unpackers().values()) + + +def reconstruction_from_file(): # renamed from reconstruction + """Return a {name: DataHandle} dict that define the reconstruction output.""" + return {k: v.OutputName for k, v in reco_unpackers().items()} + + +def make_charged_protoparticles(): + return reconstruction()['ChargedProtos'] + + +def make_neutral_protoparticles(): + return reconstruction()['NeutralProtos'] + + +def make_pvs(): + return reconstruction()['PVs'] + + +def make_tracks(): + return reconstruction()['Tracks'] + +@configurable +def reconstruction(from_file=True): + """Return reconstruction objects. + + Note it is advised to use this function if more than one object is needed, + rather than the accessors below as it makes the configuration slower. + """ + # removed reco since it will not be done in DV + reco = reconstruction_from_file() + upfront_reconstruction = upfront_reconstruction_from_file() + + charged_protos = reco["ChargedProtos"] + neutral_protos = reco["NeutralProtos"] + best_tracks = reco["Tracks"] + pvs = reco["PVs"] + electrons = reco["CaloElectrons"] + photons = reco["CaloPhotons"] + mergedPi0s = reco["CaloMergedPi0s"] + splitPhotons = reco["CaloSplitPhotons"] + muon_pids = reco["MuonPIDs"] + rich_pids = reco["RichPIDs"] + + return { + "ChargedProtos": charged_protos, + "NeutralProtos": neutral_protos, + "Tracks": best_tracks, + "PVs": pvs, + "UpfrontReconstruction": upfront_reconstruction, + "CaloElectrons": electrons, + "CaloPhotons": photons, + "CaloMergedPi0s": mergedPi0s, + "CaloSplitPhotons": splitPhotons, + "MuonPIDs": muon_pids, + "RichPIDs": rich_pids, + } diff --git a/Phys/DaVinci/python/DaVinci/standard_particles.py b/Phys/DaVinci/python/DaVinci/standard_particles.py index b7a7a6c6..96d6097d 100644 --- a/Phys/DaVinci/python/DaVinci/standard_particles.py +++ b/Phys/DaVinci/python/DaVinci/standard_particles.py @@ -41,7 +41,7 @@ from .algorithms_pyconf import ( ) from .hacks import patched_hybrid_tool -from RecoConf.reconstruction_objects import ( +from .reco_objects import ( make_charged_protoparticles as _make_charged_protoparticles, make_pvs as _make_pvs, make_neutral_protoparticles as _make_neutral_protoparticles) diff --git a/Phys/DaVinci/tests/selection.py b/Phys/DaVinci/tests/selection.py index efc23c74..c3d88430 100644 --- a/Phys/DaVinci/tests/selection.py +++ b/Phys/DaVinci/tests/selection.py @@ -11,11 +11,8 @@ from PyConf import configurable from PyConf.Algorithms import GaudiHistoAlgorithm, FunctionalParticleMaker from DaVinci import options, run_davinci, dv_node, DVSelection +from DaVinci.hacks import patched_hybrid_tool # -from RecoConf.hlt1_tracking import require_pvs -from RecoConf.reconstruction_objects import ( - make_pvs, make_charged_protoparticles, upfront_reconstruction, make_tracks) -from RecoConf.global_tools import stateProvider_with_simplified_geom from PyConf.control_flow import NodeLogic from PyConf.Tools import (LoKi__Hybrid__ProtoParticleFilter as ProtoParticleFilter, LoKi__Hybrid__TrackSelector as @@ -37,15 +34,12 @@ options.input_raw_format = 4.3 print(options) -# check tracks: from DaVinci.standard_particles import make_detached_mumu, make_mass_constrained_jpsi2mumu - +from DaVinci.reco_objects import upfront_reconstruction_from_file as upfront_reconstruction sel = DVSelection( - name="DVselection", algs=upfront_reconstruction() + [make_detached_mumu()]) -sel2 = DVSelection( - name="DVselection2", - algs=upfront_reconstruction() + [make_mass_constrained_jpsi2mumu()]) + name="DVselection", algs= upfront_reconstruction() +[make_detached_mumu()]) # run davinci -public_tools = [stateProvider_with_simplified_geom()] -run_davinci(options, [sel, sel2], public_tools) +#public_tools = [stateProvider_with_simplified_geom()] +#run_davinci(options, [sel, sel2], public_tools) +run_davinci(options, [sel])#, public_tools) -- GitLab From b867cfaa6b5c7c871550135ff58ae389099896be Mon Sep 17 00:00:00 2001 From: erodrigu Date: Wed, 17 Feb 2021 14:44:43 +0100 Subject: [PATCH 11/21] Make sure DVAppOptions.getPropertiesWithDescription() work --- Phys/DaVinci/python/DaVinci/application.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Phys/DaVinci/python/DaVinci/application.py b/Phys/DaVinci/python/DaVinci/application.py index f752d745..e7b5fd73 100644 --- a/Phys/DaVinci/python/DaVinci/application.py +++ b/Phys/DaVinci/python/DaVinci/application.py @@ -31,7 +31,7 @@ def define_app_option_defaults( else: doc[key] = value - return slots + return slots, doc class DVAppOptions(ApplicationOptions): @@ -39,4 +39,5 @@ class DVAppOptions(ApplicationOptions): Enhanced PyConf.application.ApplicationOptions class with slots defined via a YAML file. """ - __slots__ = define_app_option_defaults() + __slots__, _propertyDocDct = define_app_option_defaults() + -- GitLab From 13644bc491bdc6226f81a03d7cbe1b9f79ca4fce Mon Sep 17 00:00:00 2001 From: Gitlab CI Date: Wed, 17 Feb 2021 13:46:56 +0000 Subject: [PATCH 12/21] Fixed formatting patch generated by https://gitlab.cern.ch/lhcb/DaVinci/-/jobs/12190841 --- Phys/DaVinci/python/DaVinci/algorithms_pyconf.py | 14 ++++++++++---- Phys/DaVinci/python/DaVinci/application.py | 1 - Phys/DaVinci/python/DaVinci/data_from_file.py | 1 - Phys/DaVinci/python/DaVinci/reco_objects.py | 5 +++-- Phys/DaVinci/tests/selection.py | 4 ++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py b/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py index 971d2883..536392fe 100644 --- a/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py +++ b/Phys/DaVinci/python/DaVinci/algorithms_pyconf.py @@ -33,10 +33,16 @@ from PyConf.Algorithms import (CombineParticles, FilterDesktop, __all__ = [ #'EmptyFilter', 'ParticleFilter', 'ParticleCombiner', - 'ParticleFilter', 'ParticleCombiner', - 'ParticleFilterWithPVs', 'ParticleCombinerWithPVs', 'require_all', - 'N3BodyCombiner', 'N3BodyCombinerWithPVs', 'N4BodyCombiner', - 'N4BodyCombinerWithPVs', 'NeutralParticleCombiner', + 'ParticleFilter', + 'ParticleCombiner', + 'ParticleFilterWithPVs', + 'ParticleCombinerWithPVs', + 'require_all', + 'N3BodyCombiner', + 'N3BodyCombinerWithPVs', + 'N4BodyCombiner', + 'N4BodyCombinerWithPVs', + 'NeutralParticleCombiner', 'NeutralParticleCombinerWithPVs' ] diff --git a/Phys/DaVinci/python/DaVinci/application.py b/Phys/DaVinci/python/DaVinci/application.py index e7b5fd73..8bb52ecc 100644 --- a/Phys/DaVinci/python/DaVinci/application.py +++ b/Phys/DaVinci/python/DaVinci/application.py @@ -40,4 +40,3 @@ class DVAppOptions(ApplicationOptions): with slots defined via a YAML file. """ __slots__, _propertyDocDct = define_app_option_defaults() - diff --git a/Phys/DaVinci/python/DaVinci/data_from_file.py b/Phys/DaVinci/python/DaVinci/data_from_file.py index 69801d8c..25ec6926 100644 --- a/Phys/DaVinci/python/DaVinci/data_from_file.py +++ b/Phys/DaVinci/python/DaVinci/data_from_file.py @@ -13,7 +13,6 @@ ### N.B. THIS FILE IS INTENDED TO AVOID DEPENDENCIES ON MOORE, ### IS NEEDED FOR TESTING PURPOSES AND NEEDS TO BE REMOVED IN PRODUCTION ###### - """Load data from files and set up unpackers. There are two things we have to deal with: diff --git a/Phys/DaVinci/python/DaVinci/reco_objects.py b/Phys/DaVinci/python/DaVinci/reco_objects.py index 9a0ff8fd..87931be7 100644 --- a/Phys/DaVinci/python/DaVinci/reco_objects.py +++ b/Phys/DaVinci/python/DaVinci/reco_objects.py @@ -18,7 +18,7 @@ from PyConf import configurable from .data_from_file import reco_unpackers -def upfront_reconstruction_from_file(): # renamed from upfront_reconstruction +def upfront_reconstruction_from_file(): # renamed from upfront_reconstruction """Return a list DataHandles that define the upfront reconstruction output. This differs from `reconstruction` as it should not be used as inputs to @@ -29,7 +29,7 @@ def upfront_reconstruction_from_file(): # renamed from upfront_reconstruction return list(reco_unpackers().values()) -def reconstruction_from_file(): # renamed from reconstruction +def reconstruction_from_file(): # renamed from reconstruction """Return a {name: DataHandle} dict that define the reconstruction output.""" return {k: v.OutputName for k, v in reco_unpackers().items()} @@ -49,6 +49,7 @@ def make_pvs(): def make_tracks(): return reconstruction()['Tracks'] + @configurable def reconstruction(from_file=True): """Return reconstruction objects. diff --git a/Phys/DaVinci/tests/selection.py b/Phys/DaVinci/tests/selection.py index c3d88430..4f1f31cf 100644 --- a/Phys/DaVinci/tests/selection.py +++ b/Phys/DaVinci/tests/selection.py @@ -37,9 +37,9 @@ print(options) from DaVinci.standard_particles import make_detached_mumu, make_mass_constrained_jpsi2mumu from DaVinci.reco_objects import upfront_reconstruction_from_file as upfront_reconstruction sel = DVSelection( - name="DVselection", algs= upfront_reconstruction() +[make_detached_mumu()]) + name="DVselection", algs=upfront_reconstruction() + [make_detached_mumu()]) # run davinci #public_tools = [stateProvider_with_simplified_geom()] #run_davinci(options, [sel, sel2], public_tools) -run_davinci(options, [sel])#, public_tools) +run_davinci(options, [sel]) #, public_tools) -- GitLab From 4d934f87706ced488e0e96b8e996ad627635e274 Mon Sep 17 00:00:00 2001 From: Maurizio Martinelli Date: Wed, 17 Feb 2021 14:48:59 +0100 Subject: [PATCH 13/21] removed dependency on Moore in CMakeLists.txt --- CMakeLists.txt | 1 - Phys/DaVinci/CMakeLists.txt | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 182cd997..c5befcb9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,6 @@ find_package(GaudiProject) # Declare project name and version gaudi_project(DaVinci v52r0 USE Analysis v32r0 - Moore v51r2 DATA AppConfig VERSION v3r* FieldMap VERSION v5r* ParamFiles VERSION v8r* diff --git a/Phys/DaVinci/CMakeLists.txt b/Phys/DaVinci/CMakeLists.txt index ffb4d9ce..0a060354 100644 --- a/Phys/DaVinci/CMakeLists.txt +++ b/Phys/DaVinci/CMakeLists.txt @@ -21,8 +21,7 @@ gaudi_depends_on_subdirs(Calo/CaloDAQ GaudiPython GaudiSvc Sim/SimComponents - Kernel/FSRAlgs - Hlt/RecoConf) + Kernel/FSRAlgs) find_package(HepMC) -- GitLab From 542a85870f37f1faea9a7d16ad7699c6795ac20c Mon Sep 17 00:00:00 2001 From: Maurizio Martinelli Date: Wed, 17 Feb 2021 16:32:18 +0100 Subject: [PATCH 14/21] fixed simple_histos example --- Phys/DaVinci/tests/simple_histos.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Phys/DaVinci/tests/simple_histos.py b/Phys/DaVinci/tests/simple_histos.py index 01f6fc5f..d8a9d854 100644 --- a/Phys/DaVinci/tests/simple_histos.py +++ b/Phys/DaVinci/tests/simple_histos.py @@ -10,7 +10,7 @@ ############################################################################### from PyConf import configurable from PyConf.Algorithms import GaudiHistoAlgorithm -from DaVinci import options, run_davinci, dv_node +from DaVinci import options, run_davinci, dv_node, DVSelection # print control flow and data flow graphs options.control_flow_file = 'control_flow.gv' @@ -19,7 +19,7 @@ options.data_flow_file = 'data_flow.gv' options.ntuple_file = 'DVU_test-ntp.root' options.histo_file = 'DVU_test-his.root' -# Setup dataset +# Setup datase options.evt_max = 100 options.set_input_and_conds_from_testfiledb('Upgrade_Bd2KstarMuMu') @@ -27,4 +27,5 @@ options.set_input_and_conds_from_testfiledb('Upgrade_Bd2KstarMuMu') simple_histos = GaudiHistoAlgorithm(name="SimpleHistos", HistoPrint=True) # run davinci -run_davinci(options, [dv_node('commmon', [simple_histos])]) +algs = DVSelection(name="DVselection", algs= [simple_histos]) +run_davinci(options, [algs]) -- GitLab From c7df293cffbb36e5b0862263f2b127fa9091f645 Mon Sep 17 00:00:00 2001 From: Gitlab CI Date: Wed, 17 Feb 2021 15:33:30 +0000 Subject: [PATCH 15/21] Fixed formatting patch generated by https://gitlab.cern.ch/lhcb/DaVinci/-/jobs/12193343 --- Phys/DaVinci/tests/simple_histos.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Phys/DaVinci/tests/simple_histos.py b/Phys/DaVinci/tests/simple_histos.py index d8a9d854..c23b2564 100644 --- a/Phys/DaVinci/tests/simple_histos.py +++ b/Phys/DaVinci/tests/simple_histos.py @@ -27,5 +27,5 @@ options.set_input_and_conds_from_testfiledb('Upgrade_Bd2KstarMuMu') simple_histos = GaudiHistoAlgorithm(name="SimpleHistos", HistoPrint=True) # run davinci -algs = DVSelection(name="DVselection", algs= [simple_histos]) +algs = DVSelection(name="DVselection", algs=[simple_histos]) run_davinci(options, [algs]) -- GitLab From bf8f637d6e5d45a5ec4b9c8e74cf8cd60b157d2b Mon Sep 17 00:00:00 2001 From: erodrigu Date: Wed, 17 Feb 2021 19:37:58 +0100 Subject: [PATCH 16/21] Adapt run_davinci to empty list of 'selections' --- Phys/DaVinci/python/DaVinci/config.py | 16 ++++++++++------ Phys/DaVinci/tests/selection.py | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Phys/DaVinci/python/DaVinci/config.py b/Phys/DaVinci/python/DaVinci/config.py index 7085d7e6..789607a6 100644 --- a/Phys/DaVinci/python/DaVinci/config.py +++ b/Phys/DaVinci/python/DaVinci/config.py @@ -93,9 +93,9 @@ class DVSelection(namedtuple('DVSelection', return self.output_producer is not None -def dv_node(name, algs, logic=NodeLogic.NONLAZY_OR): +def dv_node(name, algs, logic=NodeLogic.NONLAZY_OR, forceOrder=False): return CompositeNode( - name, combineLogic=logic, children=algs, forceOrder=False) + name, combineLogic=logic, children=algs, forceOrder=forceOrder) def davinci_control_flow(options, dvsels=[]): @@ -121,8 +121,12 @@ def run_davinci(options, dvsels=[], public_tools=[]): options (ApplicationOptions): holder of application options public_tools (list): list of public `Tool` instances to configure ''' - config = configure_input(options) - top_dv_node = davinci_control_flow(options, dvsels) - config.update(configure(options, top_dv_node, public_tools=public_tools)) - #print(options) + if not dvsels: + dummy = CompositeNode("EmptyNode", children=[]) + config = configure(options, dummy, public_tools=public_tools) + else: + config = configure_input(options) + top_dv_node = davinci_control_flow(options, dvsels) + config.update(configure(options, top_dv_node, public_tools=public_tools)) + return config diff --git a/Phys/DaVinci/tests/selection.py b/Phys/DaVinci/tests/selection.py index 4f1f31cf..650ed20d 100644 --- a/Phys/DaVinci/tests/selection.py +++ b/Phys/DaVinci/tests/selection.py @@ -34,7 +34,7 @@ options.input_raw_format = 4.3 print(options) -from DaVinci.standard_particles import make_detached_mumu, make_mass_constrained_jpsi2mumu +from DaVinci.standard_particles import make_detached_mumu from DaVinci.reco_objects import upfront_reconstruction_from_file as upfront_reconstruction sel = DVSelection( name="DVselection", algs=upfront_reconstruction() + [make_detached_mumu()]) -- GitLab From 89edc2ca59d59f724fd85d5bfe27bae48b6c0537 Mon Sep 17 00:00:00 2001 From: erodrigu Date: Wed, 17 Feb 2021 19:39:26 +0100 Subject: [PATCH 17/21] Add 2 new tests for dummy-/trivial jobs --- Phys/DaVinci/tests/dummy_davinci.py | 18 ++++++++++++++++++ Phys/DaVinci/tests/dummy_no_davinci.py | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 Phys/DaVinci/tests/dummy_davinci.py create mode 100644 Phys/DaVinci/tests/dummy_no_davinci.py diff --git a/Phys/DaVinci/tests/dummy_davinci.py b/Phys/DaVinci/tests/dummy_davinci.py new file mode 100644 index 00000000..aabc9915 --- /dev/null +++ b/Phys/DaVinci/tests/dummy_davinci.py @@ -0,0 +1,18 @@ +""" +A dummy DaVinci job with no algorithm/node run. +""" +from __future__ import absolute_import + +from PyConf.application import configure +from PyConf.control_flow import CompositeNode + +from DaVinci import DVSelection +from DaVinci.config import options, run_davinci + + +# Basic input-like metadata required even though there is no input data +options.input_type = "ROOT" +options.dddb_tag = "dummy" +options.conddb_tag = "dummy" + +run_davinci(options) diff --git a/Phys/DaVinci/tests/dummy_no_davinci.py b/Phys/DaVinci/tests/dummy_no_davinci.py new file mode 100644 index 00000000..24c74b66 --- /dev/null +++ b/Phys/DaVinci/tests/dummy_no_davinci.py @@ -0,0 +1,19 @@ +""" +A dummy job with no algorithm/node run. Does not use the "DaVinci runner". +""" +from __future__ import absolute_import + +from PyConf.application import configure +from PyConf.control_flow import CompositeNode + +from DaVinci.config import options + + +dummy = CompositeNode("Dummy", children=[], forceOrder=True) + +# Basic input-like metadata required even though there is no input data +options.input_type = "ROOT" +options.dddb_tag = "dummy" +options.conddb_tag = "dummy" + +config = configure(options, dummy) -- GitLab From 00e498f158ffb0122c231f1acc29ecd7475b3ccf Mon Sep 17 00:00:00 2001 From: Gitlab CI Date: Wed, 17 Feb 2021 18:40:49 +0000 Subject: [PATCH 18/21] Fixed formatting patch generated by https://gitlab.cern.ch/lhcb/DaVinci/-/jobs/12197717 --- Phys/DaVinci/python/DaVinci/config.py | 5 +++-- Phys/DaVinci/tests/dummy_davinci.py | 1 - Phys/DaVinci/tests/dummy_no_davinci.py | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Phys/DaVinci/python/DaVinci/config.py b/Phys/DaVinci/python/DaVinci/config.py index 789607a6..83b88fd6 100644 --- a/Phys/DaVinci/python/DaVinci/config.py +++ b/Phys/DaVinci/python/DaVinci/config.py @@ -127,6 +127,7 @@ def run_davinci(options, dvsels=[], public_tools=[]): else: config = configure_input(options) top_dv_node = davinci_control_flow(options, dvsels) - config.update(configure(options, top_dv_node, public_tools=public_tools)) - + config.update( + configure(options, top_dv_node, public_tools=public_tools)) + return config diff --git a/Phys/DaVinci/tests/dummy_davinci.py b/Phys/DaVinci/tests/dummy_davinci.py index aabc9915..a741e110 100644 --- a/Phys/DaVinci/tests/dummy_davinci.py +++ b/Phys/DaVinci/tests/dummy_davinci.py @@ -9,7 +9,6 @@ from PyConf.control_flow import CompositeNode from DaVinci import DVSelection from DaVinci.config import options, run_davinci - # Basic input-like metadata required even though there is no input data options.input_type = "ROOT" options.dddb_tag = "dummy" diff --git a/Phys/DaVinci/tests/dummy_no_davinci.py b/Phys/DaVinci/tests/dummy_no_davinci.py index 24c74b66..1de21816 100644 --- a/Phys/DaVinci/tests/dummy_no_davinci.py +++ b/Phys/DaVinci/tests/dummy_no_davinci.py @@ -8,7 +8,6 @@ from PyConf.control_flow import CompositeNode from DaVinci.config import options - dummy = CompositeNode("Dummy", children=[], forceOrder=True) # Basic input-like metadata required even though there is no input data -- GitLab From a0970142e7d8e30fba146bc8c7aede032996b8f4 Mon Sep 17 00:00:00 2001 From: erodrigu Date: Wed, 17 Feb 2021 19:42:37 +0100 Subject: [PATCH 19/21] Add copyright headers to 2 test files --- Phys/DaVinci/tests/dummy_davinci.py | 10 ++++++++++ Phys/DaVinci/tests/dummy_no_davinci.py | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/Phys/DaVinci/tests/dummy_davinci.py b/Phys/DaVinci/tests/dummy_davinci.py index a741e110..f88e242c 100644 --- a/Phys/DaVinci/tests/dummy_davinci.py +++ b/Phys/DaVinci/tests/dummy_davinci.py @@ -1,3 +1,13 @@ +############################################################################### +# (c) Copyright 2021 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. # +############################################################################### """ A dummy DaVinci job with no algorithm/node run. """ diff --git a/Phys/DaVinci/tests/dummy_no_davinci.py b/Phys/DaVinci/tests/dummy_no_davinci.py index 1de21816..3dccd43f 100644 --- a/Phys/DaVinci/tests/dummy_no_davinci.py +++ b/Phys/DaVinci/tests/dummy_no_davinci.py @@ -1,3 +1,13 @@ +############################################################################### +# (c) Copyright 2021 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. # +############################################################################### """ A dummy job with no algorithm/node run. Does not use the "DaVinci runner". """ -- GitLab From 7125a7992d759fd8db42de1ff28592870de8ab2e Mon Sep 17 00:00:00 2001 From: Maurizio Martinelli Date: Thu, 18 Feb 2021 09:37:43 +0100 Subject: [PATCH 20/21] removed the reference to the DeterministicPrescaler --- Phys/DaVinci/python/DaVinci/config.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Phys/DaVinci/python/DaVinci/config.py b/Phys/DaVinci/python/DaVinci/config.py index 83b88fd6..2c41b18a 100644 --- a/Phys/DaVinci/python/DaVinci/config.py +++ b/Phys/DaVinci/python/DaVinci/config.py @@ -41,21 +41,14 @@ class DVSelection(namedtuple('DVSelection', """Initialize a HltLine from name, algs and prescale. Creates a control flow `CompositeNode` with the given `algs` - combined with `LAZY_AND` logic. A `DeterministicPrescaler` is - always inserted even if the prescale is 1. + combined with `LAZY_AND` logic. Args: name (str): name of the line algs: iterable of algorithms - prescale (float): accept fraction of the prescaler extra_outputs (iterable of 2-tuple): List of (name, DataHandle) pairs. """ - # prescaler = DeterministicPrescaler( - # AcceptFraction=prescale, - # SeedName=name + "Prescaler", - # ODINLocation=make_odin()) node = CompositeNode( - #name, (prescaler, ) + tuple(algs), name, tuple(algs), combineLogic=NodeLogic.LAZY_AND, -- GitLab From e4653c2371eb850e4189a12258cffa91e235dac8 Mon Sep 17 00:00:00 2001 From: Maurizio Martinelli Date: Thu, 18 Feb 2021 09:47:21 +0100 Subject: [PATCH 21/21] removed unnecessary PyConf imports to hide them from user --- Phys/DaVinci/tests/dummy_davinci.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Phys/DaVinci/tests/dummy_davinci.py b/Phys/DaVinci/tests/dummy_davinci.py index f88e242c..1fdb983b 100644 --- a/Phys/DaVinci/tests/dummy_davinci.py +++ b/Phys/DaVinci/tests/dummy_davinci.py @@ -13,9 +13,6 @@ A dummy DaVinci job with no algorithm/node run. """ from __future__ import absolute_import -from PyConf.application import configure -from PyConf.control_flow import CompositeNode - from DaVinci import DVSelection from DaVinci.config import options, run_davinci -- GitLab