Skip to content
Snippets Groups Projects
Commit 360e468d authored by Patrick Koppenburg's avatar Patrick Koppenburg :leaves:
Browse files

Remove selection framework

parent fbd8e15d
No related branches found
No related tags found
1 merge request!3392Remove FilterDesktop and selection framework
Showing
with 0 additions and 29418 deletions
###############################################################################
# (c) Copyright 2000-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. #
###############################################################################
#[=======================================================================[.rst:
Phys/MVADictTools
-----------------
#]=======================================================================]
gaudi_add_library(MVADictToolsLib
SOURCES
src/lib/BBDecTreeTransform.cpp
src/lib/HDKerasModel.cpp
src/lib/HEPDroneTransform.cpp
src/lib/MatrixnetTransform.cpp
src/lib/TMVATransform.cpp
src/lib/Utils.cpp
LINK
PUBLIC
Boost::headers
Gaudi::GaudiKernel
Rec::DaVinciInterfacesLib
Rec::kerasLib
Rec::lwtnnParserLib
ROOT::TMVA
PRIVATE
Boost::filesystem
ROOT::XMLIO
)
gaudi_add_module(MVADictTools
SOURCES
src/component/BBDecTreeTool.cpp
src/component/HEPDroneTool.cpp
src/component/MVAManager.cpp
src/component/MatrixnetClassifierTool.cpp
src/component/TMVAClassifierTool.cpp
LINK
Gaudi::GaudiAlgLib
MVADictToolsLib
Rec::DaVinciInterfacesLib
Rec::LoKiArrayFunctorsLib
)
gaudi_add_executable(utesttmva
SOURCES
src/applications/utesttmva.cxx
LINK
Boost::unit_test_framework
Gaudi::GaudiKernel
MVADictToolsLib
BLAS::BLAS
TEST
)
gaudi_install(PYTHON)
gaudi_add_tests(QMTest)
----------------------------------------------------------------------------
! Package : Phys/MVADictTools
! Responsible : Sam Hall, Sebastian Neubert
! Purpose : Generic MVA classifier backends for DictTransform
!---------------------------------------------------------------------------
!====================== MVADictTools v1r10 2015-10-19 ======================
! 2015-08-12 - Gerhard Raven
- remove #include of obsolete Gaudi headers
!========================= MVADictTools v1r9p1 2015-07-03 =======================
! 2015-07-03 - Roel Aaij
- Fix resolution of environment variables when opening files.
- Remove useless and unused default path properties.
!========================= MVADictTools v1r9 2015-03-31 =========================
! 2015-03-12 - Roel Aaij
- Return tool configurable from helper functions
- Add utility function to resolve environment variable in filename.
! 2015-03-11 - Egor Khairullin
- Add support for BBDT models (from Phys/BBDecTreeTool) and example of usage
(options/mvaDfromB_bbdt.py)
! 2015-03-06 - Andrey Ustyuzhanin
- fix eos URL to sample file for mvaDfromB scripts
!========================= MVADictTools v1r8 2014-12-15 =========================
! 2014-10-31 - Andrey Ustyuzhanin
- variable length array -> alloca in MatrixnetTransform.cpp
!========================= MVADictTools v1r7 2014-10-30 =========================
! 2014-10-28 - Sam Hall
- Corrected mistake in options/mvaDFromB example
- Lines 74/75
! 2014-10-22 - Marco Clemencic
- Uncommented installation of Python modules in CMake.
!========================= MVADictTools v1r6 2014-09-30 =========================
! 2014-09-24 - Marco Clemencic
- Updated hack for LCG experimental builds.
! 2014-09-19 - Marco Clemencic
- Small hack to be able to compile against LCG experimental builds.
! 2014-09-12 - Chris Jones
- Turn off a number of info level messages, unless 'debug' mode is explicitly
requested.
- Fix some python warnings.
! 2014-09-11 - Stefano Perazzini
- Assigned "Silent" as default configuration for the TMVA::Reader
!========================= MVADictTools v1r5 2014-07-25 =========================
! 2014-06-30 - Chris Jones
- Make MVADictTools headers public.
!========================= MVADictTools v1r4 2014-02-20 =========================
! 2014-02-12 - Andrey Ustyuzhanin
- Add support for Matrixnet models and example of usage
(options/mvaDfromB_matrixnet.py)
!========================= MVADictTools v1r3 2014-02-12 =========================
! 2014-01-21 - Chris Jones
- Add a workaround to the requirements file to fix missing GSL symbols
during linking.
- Add explicit usage for LoKiArrayFunctors and DaVinciInterfaces.
Needed to make sure compilation is done in the correct order when all
packages are in the same project (such as for branch releases).
! 2014-01-20 - Marco Clemencic
- Modified unit test to work from an arbitrary directory.
!========================= MVADictTools v1r2p1 2013-12-18 =========================
! 2013-11-15 - Marco Clemencic
- Fixed use of std namespace in TMVATransform.cpp.
!========================= MVADictTools v1r2 2013-10-29 =========================
! 2013-11-14 - Sam Hall
- Updated mvaDfromB.py with improved syntax and use of LoKi preambulo and also
interfacing with the MVADictHelper module, such that only a single line is
required.
! 2013-11-12 - Sam Hall
- Added mvaDfromB.py and bdt_d2kpipi.xml. The former (uses the latter) to run
the D+ -> K- pi+ pi+ BDT on the B+ -> (D+ -> K- pi+ pi+) (rho -> pi+ pi-)
decay at DaVinci level. Hopefullly it is a comprehensiver example for both
the use and the example LoKi functors, which are non-trivial. The python
file also has some PFNs (located at CERN) that to run over.
! 2013-10-24 - Sebastian Neubert
- Added python directory with helper functions to configure MVA tool chains.
Added an example options script to illustrate the use of these.
The compact configuration depends on the stacked LoKi::HybridEngineActor
to avoid the double lock problem.
!========================= MVADictTools v1r1 2013-10-02 =========================
! 2012-09-29 - Sam Hall
- Looks for .xml in local directory and then in a path, specifically
TMVATRANSFORMPATH - if file is still not found an error is thrown.
! 2013-08-08 - Sebastian Neubert
- Added MVAManager algorithm.
Holds one IParticleDictTool in order to avoid the
double lock problem during instantiation of LoKi functors
This class is only needed as a container for the tool.
It has no functionality of its own
- Added example how to cut on MVA output by using the VALUE functor
and and the LoKi::Hybrid::DictValue tool.
! 2013-08-06 - Sebastian Neubert
- small fix: replaced endmsg by std::endl
! 2013-08-05 - Chris Jones
- Split code into a linker library and a component library, to allow
sharing between the Gaudi components and the test applications.
- Various other minor clean ups to the requirements and CMake files.
! 2013-08-02 - Marco Clemencic
- Added the unit test in the CMake configuration.
! 2013-08-02 - Sebastian Neubert
- changed DictTransform policies to use std::ostream
- Created header file for TMVAClassifierTool
- added unit test framework for TMVATransform
- added a first unit test
- added qmtest call to utest
!========================= MVADictTools v1r0 2013-08-01 =========================
! 2013-08-01 - Marco Clemencic
- Added CMake configuration.
! 2013-08-01 Sebastian Neubert
- renamed the dictionary tools in the LoKi::Hybrid:: namespace
MultiToolDictTool -> DictOfFunctors
Dict2TupleTool -> Dict2Tuple
DictTransformTool -> DictTransform
! 2013-07-31 - Sam Hall
- KeepVars added to TMVAClassifierTool
! 2013-07-30 - Sebastian Neubert
- Creating LHCb package Phys/MVADictTools
! 2013-07-30 - Sebastian Neubert
- Cleaning up
Renamed several components
Moved Dict tools into LoKiArrayFunctors
Removed old stuff
Added better comments to opt/mvaexampleTMVA.py
Added example options file opt/dictexample.py
! 2013-07-29 - Sam Hall
- TMVATransform works, complete with output
! 2013-07-28 - Sam Hall
- Added TestPhi2KK.xml (mini test bdt)
- Options.h is now much better and TMVATransform is in a working state
except for the branch -> fucntor matching.
! 2013-07-26 - Sebastian Neubert
- New options with the correct usage of the branch and variable naming
! 2013-07-25 - Sebastian Neubert
- Added DictMergeTool
! 2013-07-23 - Sebastian Neubert
- Added example how to apply dicttools to a branch with several LoKi functors
need to figure out how to solve the nameing issue for subbranches
! 2013-07-21 - Sam Hall
- Added TMVATransform and rudimentary Options parser
- Options parser then simplified and TMVAClassifier works!
Well, the reader is initialized etc.
! 2013-07-22 - Sebastian Neubert
- Added templated Dict2DictTool.
offers a more generic way to implement an MVAClassifier
added info stream the Dict-Transform
! 2013-07-19 - Sebastian Neubert
- Introducing new, more linear architecture
- Adding MVAClassifierBase and inheriting MVAClassifierDummy from this one
! 2013-07-19 - Sam Hall
- Removal of ChangeVariableNames map in favour of using branches
! 2013-07-19 - Sam Hall
- Protections for TMVA in place, for example non-existent xml files and
mismatch between xml variables and those given to the tool
- Errors are thrown for any of the above, though not fatal, as the output can
be useful (eg variable names in the xml file).
- For any FAILURES the tuple is filled with 0.0 (perhaps this should be -1e10).
- ChangeVariableNames added (via declareProperty) in order to map names in the
given xml file to variable names in the ntuple. This is done using an
additional map.
- Hopefully works(!), need a test BDT.
! 2013-07-18 - Sebastian Neubert, Sam Hall
- Added MVAClassifierTMVA; added some protections for missing
components. This calss is still WorkInProgress
! 2013-07-17 - Sebastian Neubert
- Added Dict2TupleTool and fixed some initialisation issues
! 2013-07-11 - Sebastian Neubert
- Adding working options file.
So far everything is still dummy implementation
but tool structure is building and can be configured
! 2013-07-10 - Sebastian Neubert
- Adding complete set of Interfaces
- The package depends on the new MultiToolDictTool which
implements IParticleDictTool
- Workflow is designed as follows:
Configure a DictTool to access the functors needed by the MVA
Configure an MVAClassifier (IDict2Val)
to use a specific MVAbackend
load WeightFile into backend etc
Configure a TupleToolMVAClassifier handing over
- the DictTool
- the MVAClassifier
In the event loop:
TupleToolMVAClassifier is applied to a particle
Calls DictTool
Calls LoKi-Functors
Fills Dictionary
returns Dictionary
Calls MVAClassifier through IDict2Val(Dict,)
Calls MVABackend
return MVAresponse
return MVAresponse
Write MVAresponse into Tuple-Collumn
end
! 2013-04-08 - Sebastian Neubert
- First import. Read doxygen for more information
/*****************************************************************************\
* (c) Copyright 2000-2018 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. *
\*****************************************************************************/
#ifndef LIB_BBDECTREETRANSFORM_H
#define LIB_BBDECTREETRANSFORM_H 1
#include "Kernel/IParticleDictTool.h"
#include "TMVA/Reader.h"
#include <ostream>
#include "MVADictTools/Options.h"
typedef IParticleDictTool::DICT DICT;
/** @class BBDecTreeTransform
* Policy class to be used by the DictTransform template
* Implementing the BBDT reader backed
* Moved from Phys/BBDecTreeTool
*
* @author Egor Khairullin
* @date 2015-03-11
*/
class BBDecTreeTransform {
public:
typedef std::map<std::string, std::string> optmap;
private:
bool m_setup_success;
bool m_keep_all_vars;
std::string m_bbdt_file;
std::string m_name;
std::string m_default_path;
// BBDT bits
int m_ntrees; ///< number of trees used in training - it's just multiplier
std::vector<std::vector<double>> m_splits; ///< variable split points
std::vector<unsigned short int> m_values; ///< response values
bool m_debug;
private:
// Helper Functions
void readWeightsFile( std::ostream& );
bool parseOpts( const optmap&, std::ostream& );
/// utility method to obtain index to m_values
int getIndex( const DICT& ) const;
/// utility method to obtain split index for single variable
int getVarIndex( int varIndex, double value ) const;
public:
std::vector<std::string> m_variables; /// variables needed by the classifier
public:
BBDecTreeTransform();
// the policy methods neede for collaboration with DictTransform
bool Init( const optmap& options, std::ostream& info, const bool debug = false );
bool operator()( const DICT& in, DICT& out ) const;
bool checkWeightsFile( std::ostream& info );
};
#endif // LIB_BBDECTREETRANSFORM_H
/*****************************************************************************\
* (c) Copyright 2000-2018 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. *
\*****************************************************************************/
#ifndef LIB_HDKERASMODEL_H
#define LIB_HDKERASMODEL_H
#include <string>
#include "keras/keras_model.h"
#include "lwtnnParser/parse_json.h"
class HDKerasLayer : public KerasLayer {
public:
using KerasLayer::Apply;
using KerasLayer::LoadLayer;
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) = 0;
/// Read flattened transpose of matrix to 2D tensor
virtual Tensor getMatrixTensor( const lwt::LayerConfig& config, size_t n_inputs );
/// Get number of outputs for current layer
virtual size_t GetNOutputs() { return m_n_outputs; }
protected:
size_t m_n_outputs = 0; ///< store number of outputs for current layer
};
class HDKerasLayerActivation : public KerasLayerActivation, public HDKerasLayer {
public:
virtual bool LoadLayer( std::ifstream* file ) override {
return KerasLayerActivation::LoadLayer( file );
} ///< call internal inherited
virtual bool Apply( Tensor* in, Tensor* out ) override {
return KerasLayerActivation::Apply( in, out );
} ///< call internal inherited
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) override;
};
class HDKerasLayerDense : public KerasLayerDense, public HDKerasLayer {
public:
virtual bool LoadLayer( std::ifstream* file ) override {
return KerasLayerDense::LoadLayer( file );
} ///< call internal inherited
virtual bool Apply( Tensor* in, Tensor* out ) override {
return KerasLayerDense::Apply( in, out );
} ///< call internal inherited
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) override;
protected:
HDKerasLayerActivation activation_;
};
class HDKerasLayerConvolution2d : public KerasLayerConvolution2d, public HDKerasLayer {
public:
virtual bool LoadLayer( std::ifstream* file ) override {
return KerasLayerConvolution2d::LoadLayer( file );
} ///< call internal inherited
virtual bool Apply( Tensor* in, Tensor* out ) override {
return KerasLayerConvolution2d::Apply( in, out );
} ///< call internal inherited
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) override;
protected:
HDKerasLayerActivation activation_;
};
class HDKerasLayerFlatten : public KerasLayerFlatten, public HDKerasLayer {
public:
virtual bool LoadLayer( std::ifstream* file ) override {
return KerasLayerFlatten::LoadLayer( file );
} ///< call internal inherited
virtual bool Apply( Tensor* in, Tensor* out ) override {
return KerasLayerFlatten::Apply( in, out );
} ///< call internal inherited
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) override;
};
class HDKerasLayerElu : public KerasLayerElu, public HDKerasLayer {
public:
virtual bool LoadLayer( std::ifstream* file ) override {
return KerasLayerElu::LoadLayer( file );
} ///< call internal inherited
virtual bool Apply( Tensor* in, Tensor* out ) override {
return KerasLayerElu::Apply( in, out );
} ///< call internal inherited
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) override;
};
class HDKerasLayerMaxPooling2d : public KerasLayerMaxPooling2d, public HDKerasLayer {
public:
virtual bool LoadLayer( std::ifstream* file ) override {
return KerasLayerMaxPooling2d::LoadLayer( file );
} ///< call internal inherited
virtual bool Apply( Tensor* in, Tensor* out ) override {
return KerasLayerMaxPooling2d::Apply( in, out );
} ///< call internal inherited
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) override;
};
class HDKerasLayerLSTM : public KerasLayerLSTM, public HDKerasLayer {
public:
virtual bool LoadLayer( std::ifstream* file ) override {
return KerasLayerLSTM::LoadLayer( file );
} ///< call internal inherited
virtual bool Apply( Tensor* in, Tensor* out ) override {
return KerasLayerLSTM::Apply( in, out );
} ///< call internal inherited
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) override;
protected:
HDKerasLayerActivation innerActivation_;
HDKerasLayerActivation activation_;
};
class HDKerasLayerEmbedding : public KerasLayerEmbedding, public HDKerasLayer {
public:
virtual bool LoadLayer( std::ifstream* file ) override {
return KerasLayerEmbedding::LoadLayer( file );
} ///< call internal inherited
virtual bool Apply( Tensor* in, Tensor* out ) override {
return KerasLayerEmbedding::Apply( in, out );
} ///< call internal inherited
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) override;
};
class HDKerasLayerBatchNormalization : public KerasLayerBatchNormalization, public HDKerasLayer {
public:
virtual bool LoadLayer( std::ifstream* file ) override {
return KerasLayerBatchNormalization::LoadLayer( file );
} ///< call internal inherited
virtual bool Apply( Tensor* in, Tensor* out ) override {
return KerasLayerBatchNormalization::Apply( in, out );
} ///< call internal inherited
/// Interface to load layer from JSON configuration object
virtual bool LoadLayer( const lwt::LayerConfig& config, size_t n_inputs = 0 ) override;
};
class HDKerasModel : public KerasModel {
public:
using KerasModel::LoadModel;
/// Interface to load Keras Neural Network from JSON configuration file
virtual bool LoadJSONModel( const std::string& filename );
/// Interface to load Keras Neural Network from JSON configuration object
virtual bool LoadJSONModel( const lwt::JSONConfig& config );
};
#endif // LIB_HDKERASMODEL_H
/*****************************************************************************\
* (c) Copyright 2000-2018 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. *
\*****************************************************************************/
#ifndef LIB_HEPDRONETRANSFORM_H
#define LIB_HEPDRONETRANSFORM_H
#include "Kernel/IParticleDictTool.h"
#include <map>
#include <memory>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
#include "HDKerasModel.h"
#include "MVADictTools/Options.h"
typedef IParticleDictTool::DICT DICT;
/** @class HEPDroneTransform
* Policy class to be used by the DictTransform template
* Implementing the HEPDrone reader backed
*
* @author Konstantin Gizdov
* @date 2018-02-08
*/
class HEPDroneTransform {
public:
typedef std::map<std::string, std::string> optmap; /// map to parse options
/// the policy methods needed for collaboration with DictTransform
bool Init( const optmap& options, std::ostream& info, const bool debug = false );
bool operator()( const DICT& in, DICT& out ) const;
private:
/// HDKerasModel for evaluation
std::unique_ptr<HDKerasModel> m_model = std::make_unique<HDKerasModel>();
/// NN JSON config
lwt::JSONConfig m_config{};
// Helper Functions
/// check JSON configuration file
bool checkDroneFile( std::ostream& info );
/// read JSON and configure NN
void readDroneFile( std::ostream& );
/// parse tool options
bool parseOpts( const optmap&, std::ostream& );
/// convert input vector to NN input tensor
Tensor dictInputToTensor( const DICT& in ) const;
/// convert NN output tensor to output vector
std::vector<std::pair<std::string, double>> tensorOutToVec( const Tensor& in ) const;
bool m_setup_success{false}; ///< setup status
bool m_keep_all_vars{true}; ///< keep input variables together with response
bool m_json{true}; ///< are we using JSON or HD5 config file
std::string m_drone_file{}; ///< path to configuration file
std::string m_name{}; ///< name of output branch
std::ostream* m_info{}; ///< store location of info buffer for internal use
bool m_debug{false}; ///< debug flag
};
#endif // LIB_HEPDRONETRANSFORM_H
/*****************************************************************************\
* (c) Copyright 2000-2018 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. *
\*****************************************************************************/
#ifndef LIB_MATRIXNETTRANSFORM_H
#define LIB_MATRIXNETTRANSFORM_H 1
#include "GaudiKernel/MsgStream.h"
#include "Kernel/IParticleDictTool.h"
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "Options.h"
// typedef std::map<std::string, float> DICT;
typedef IParticleDictTool::DICT DICT;
/** @class MatrixnetTransform
* Policy class to be used by the DictTransform template
* Implementing the Matrixnet Reader backend
*
* @author Andrey Ustyuzhanin, Egor Khairullin
* @date 2014-01-31
*/
class MatrixnetTransform {
public:
typedef std::map<std::string, std::string> optmap;
private:
bool m_setup_success = false;
bool m_keep_all_vars = true;
std::string m_matrixnet_file;
std::string m_name;
std::string m_default_path;
// Matrixnet bits
std::string m_formula;
bool m_debug = false;
private:
// Helper Functions
void readWeightsFile( std::ostream& );
bool parseOpts( const optmap&, std::ostream& );
public:
std::vector<std::string> m_variables; /// variables needed by the classifier
MatrixnetTransform() = default;
bool Init( const optmap& options, std::ostream& info, const bool debug = false );
bool operator()( const DICT& in, DICT& out ) const;
};
#endif // LIB_MATRIXNETTRANSFORM_H
/*****************************************************************************\
* (c) Copyright 2000-2018 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. *
\*****************************************************************************/
#ifndef OPTIONS_MVACLASSIFIER_H
#define OPTIONS_MVACLASSIFIER_H 1
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <map>
#include <string>
/***
* Options class to pass options from map<string, string> from python
* Then can perform a check
*
* @author Sam Hall
* @date 2013-07-29
*/
class Options {
private:
//============================================================================
// pass the options parser
bool m_pass;
// Options map
std::map<std::string, std::string> m_opts;
// Options map of allowed options
std::map<std::string, std::string> m_allowed;
//============================================================================
public:
//============================================================================
// constructor and destructor
Options( const std::map<std::string, std::string>& opts ) : m_pass( true ) {
m_opts = opts;
return;
}
~Options() { ; }
//============================================================================
// add an option with no default ==> Required
template <class T>
void add( std::string name, std::string about, T& input, std::ostream& info ) {
m_allowed[name] = about;
if ( m_opts.count( name ) ) {
try {
input = boost::lexical_cast<T>( m_opts[name] );
} catch ( boost::bad_lexical_cast& ) {
info << "ERROR casting option \"" << name << "\" as " << m_opts[name] << std::endl;
m_pass &= false;
return;
}
} else {
info << "ERROR: Option \"" << name << "\"";
if ( name != about ) { info << " (" << about << ")"; }
info << " is undefined (and required)" << std::endl;
m_pass &= false;
return;
}
info << name << " : " << input << std::endl;
m_opts.erase( name );
m_pass &= true;
return;
}
// add non-required option
template <class T>
void add( std::string name, std::string about, T& input, std::ostream& info, const T& init ) {
m_allowed[name] = about;
if ( m_opts.count( name ) ) {
try {
input = boost::lexical_cast<T>( m_opts[name] );
} catch ( boost::bad_lexical_cast& ) {
info << "ERROR casting option \"" << name << "\" as " << m_opts[name] << std::endl;
m_pass &= false;
return;
}
} else {
input = init;
m_pass &= true;
return;
}
info << name << " : " << input << std::endl;
m_opts.erase( name );
m_pass &= true;
return;
}
// perform checks
bool check( std::ostream& info ) {
if ( m_opts.size() > 0 ) {
std::map<std::string, std::string>::iterator it;
info << "ERROR Unkonown options:" << std::endl;
it = m_opts.begin();
for ( ; it != m_opts.end(); ++it ) { info << " " << it->first << " : " << it->second << std::endl; }
info << "The allowed options are:" << std::endl;
it = m_allowed.begin();
for ( ; it != m_allowed.end(); ++it ) { info << " " << it->first << " : " << it->second << std::endl; }
m_pass &= false;
}
return m_pass;
}
//============================================================================
};
#endif
/*****************************************************************************\
* (c) Copyright 2000-2018 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. *
\*****************************************************************************/
#pragma once
#include <memory>
#include <ostream>
#include <vector>
#include "Kernel/IParticleDictTool.h"
#include "Kernel/SynchronizedValue.h"
#include "TMVA/MethodBase.h"
#include "TMVA/Reader.h"
#include "MVADictTools/Options.h"
/** @class TMVATransform
* Policy class to be used by the DictTransform template
* Implementing the TMVA Reader backend
*
* @author Sam Hall
* @date 2013-07-29
*/
class TMVATransform {
public:
using optmap = std::map<std::string, std::string>;
private:
bool m_setup_success{false};
bool m_keep_all_vars{false};
std::string m_reader_opts{"Silent"}; // Silent : none, V : verbose, Color : colored
std::string m_weightfile;
std::string m_name;
std::string m_branchname;
// TMVA bits
std::unique_ptr<TMVA::Reader> m_reader;
mutable LHCb::cxx::SynchronizedValue<std::unique_ptr<::TMVA::MethodBase>> m_mva{nullptr};
auto evaluateMVA( std::vector<float> const& vals ) const {
// given that the MVA must know how many inputs it expects, and `vals` also knows how many
// items it contains, why must one add an explicit `GetNVariables()` to `Event`? And why
// must one pass `event` instead of just vals?
// and why does `GetMvaValue` assign the address of `event` to fTmpEvent, call the internal
// GetMvaValue, and then reset fTmpEvent instead of just passing the pointer explicitly?
// As a result of this use of fTmpEvent, this method is not thread-safe, and thus needs
// a lock...
return m_mva.with_lock( [event = ::TMVA::Event{vals, m_reader->DataInfo().GetNVariables()}](
std::unique_ptr<::TMVA::MethodBase>& mb ) { return mb->GetMvaValue( &event, 0 ); } );
}
// spectators variables.
std::vector<std::string> m_spectator;
bool m_debug{false};
private:
// Helper Functions
void readWeightsFile( std::ostream& );
bool parseOpts( const optmap&, std::ostream& );
public:
std::vector<std::string> m_variables; /// variables needed by the classifier
public:
// the policy methods neede for collaboration with DictTransform
bool Init( const optmap& options, std::ostream& info, const bool debug = false );
bool operator()( const IParticleDictTool::DICT& in, IParticleDictTool::DICT& out ) const;
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
###############################################################################
# (c) Copyright 2000-2018 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. #
###############################################################################
################################################################################
# First build the selection
################################################################################
from Configurables import CombineParticles
_jpsi2mumu = CombineParticles("Jpsi2MuMu")
_jpsi2mumu.DecayDescriptor = "J/psi(1S) -> mu+ mu-"
_jpsi2mumu.CombinationCut = "ADAMASS('J/psi(1S)')<30*MeV"
_jpsi2mumu.MotherCut = "(VFASPF(VCHI2/VDOF)<10)"
from PhysSelPython.Wrappers import Selection
from StandardParticles import StdLooseMuons, StdLooseKaons
LooseJpsi2MuMu = Selection(
"SelLooseJpsi2MuMu",
Algorithm=_jpsi2mumu,
RequiredSelections=[StdLooseMuons])
from Configurables import FilterDesktop
_jpsifilter = FilterDesktop("_jpsiFilter", Code="(PT>1*GeV) & (P>3*GeV)")
Jpsi2MuMu = Selection(
"SelJpsi2MuMu", Algorithm=_jpsifilter, RequiredSelections=[LooseJpsi2MuMu])
_phi2kk = CombineParticles("Phi2KK")
_phi2kk.DecayDescriptor = "phi(1020) -> K+ K-"
_phi2kk.CombinationCut = "ADAMASS('phi(1020)')<50*MeV"
_phi2kk.MotherCut = "(VFASPF(VCHI2/VDOF)<100)"
Phi2KK = Selection(
"SelPhi2KK", Algorithm=_phi2kk, RequiredSelections=[StdLooseKaons])
_bs2JpsiPhi = CombineParticles(
"Bs2JpsiPhi",
DecayDescriptor="B_s0 -> phi(1020) J/psi(1S)",
CombinationCut="ADAMASS('B_s0')<2*GeV",
MotherCut="(VFASPF(VCHI2/VDOF)<10) & (BPVIPCHI2()<100)")
Bs2JpsiPhi = Selection(
"SelBs2JpsiPhi",
Algorithm=_bs2JpsiPhi,
RequiredSelections=[Phi2KK, Jpsi2MuMu])
from PhysSelPython.Wrappers import SelectionSequence
SeqBs2JpsiPhi = SelectionSequence("SeqBs2JpsiPhi", TopSelection=Bs2JpsiPhi)
simulation = False
from DecayTreeTuple.Configuration import *
tuple = DecayTreeTuple()
tuple.Inputs = ["Phys/SelBs2JpsiPhi/Particles"]
tuple.Decay = "[B_s0 -> (^J/psi(1S) => ^mu+ ^mu-) (^phi(1020) -> ^K+ ^K-)]cc"
tuple.ToolList = []
tuple.UseLabXSyntax = True
tuple.RevertToPositiveID = False
#The traditional TupleTool
#LoKi_All=tuple.addTupleTool("LoKi::Hybrid::TupleTool/LoKi_All")
#LoKi_All.Variables = {
# "lokiP" : "P",
# "lokiPT" : "PT",
#}
################################################################################
# Finished building normal selection
################################################################################
################################################################################
################################################################################
# The NEW MVA Dictionary Tools - Demo of dummy Dict transformation
################################################################################
# Imports
from Configurables import LoKi__Hybrid__DictOfFunctors
from Configurables import LoKi__Hybrid__Dict2Tuple
from Configurables import LoKi__Hybrid__DictTransform_DummyTransform_ as DummyTransform
#We are going to add the MVA tools to the phi
tuple.addBranches({
"Phi": "B_s0 -> (^phi(1020) -> K+ K-) ? ",
})
# we are adding the Dict2Tuple to the Phi branch.
# this will write the result of the transformation into the ntuple
# All variables in the dict will be prefixed with "Phi_" as they are written into the ntuple
Phi = tuple.Phi.addTupleTool(LoKi__Hybrid__Dict2Tuple, "Dummy2Tuple")
# Add a DictTransfromTool to the Dict2Tuple
# the DummyTransform implements an indentity "transformation:" on a dictionary
# and prints the contents of the input dict to std::cout
Phi.addTool(DummyTransform, "Trafo")
Phi.Source = "LoKi::Hybrid::DictTransform<DummyTransform>/Trafo"
# Configure the (options depend on which classifier is used)
Phi.Trafo.Options = {
"Name":
"OysterSauce", # DictTransforms can be configured with custom options
}
# Note that other dictionary transformations can easily be added by
# implementing a new DictTransformationTool using the DictTransformation policies
# see Phys/LoKiArrayFunctors/src/Components/DummyTransform.cpp for a prototype
# Add a DictOfFunctors as the source of the transformation
# the MultiTool will use LoKiFunctors to query the variables needed
Phi.Trafo.addTool(LoKi__Hybrid__DictOfFunctors, "dict")
Phi.Trafo.Source = "LoKi::Hybrid::DictOfFunctors/dict"
# the variable names have to correspond exactly to what is needed by the transformation tool
# the prefixing with the node names has to be done manually here!
Phi.Trafo.dict.Variables = {
"lab1_PT": "PT",
"lab1_IPCHI2_OWNPV": "MIPCHI2DV(PRIMARY)",
"lab2_PT": "CHILD(PT,1)",
"lab3_PT": "CHILD(PT,2)",
"lab2_IPCHI2_OWNPV": "CHILD(MIPCHI2DV(PRIMARY),1)",
"lab3_IPCHI2_OWNPV": "CHILD(MIPCHI2DV(PRIMARY),2)",
}
# How to write a dictionary directly into the ntuple:
#tuple.addTupleTool(LoKi__Hybrid__Dict2Tuple, "MVATuple")
#tuple.MVATuple.addTool(LoKi__Hybrid__DictOfFunctors, "MVADict2Tuple")
#tuple.MVATuple.Source = "MVADict2Tuple"
#tuple.MVATuple.MVADict2Tuple.Variables = variables
################################################################################
# End of MVAClassifier TupleTool
################################################################################
if (simulation): tuple.ToolList += ["TupleToolMCTruth"]
from Configurables import DaVinci, LHCbApp
DaVinci().DataType = "2012"
DaVinci().DDDBtag = "dddb-20120831"
DaVinci().CondDBtag = "cond-20120831"
DaVinci().Input = [
'/afs/cern.ch/work/s/shall/dsts/00020198_00012742_1.dimuon.dst'
]
#save an ntuple
DaVinci().EvtMax = 1000
DaVinci().UserAlgorithms = [SeqBs2JpsiPhi, tuple]
DaVinci().TupleFile = "DVNtuples.root"
DaVinci().Simulation = simulation
File deleted
###############################################################################
# (c) Copyright 2000-2018 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. #
###############################################################################
################################################################################
"""
ADDING BDT TO TUPLE
Example script to run a BDT at DaVinci level over a uDST.
The exact BDT is used to distinguish:
D+ -> K- pi+ pi+
originating from a B. More details available if required.
We use the example decay:
[B+ -> ^(D+ -> ^pi+ ^pi+ ^K-) ^(rho(770)0 -> ^pi+ ^pi-)]CC'
from the B2DPiPiD2HHHCFPIDBeauty2CharmLine.
Workflow goes as the following:
- Create selection from stripping using FilterDesktop
- Create tuple
- Add branch for the D to the tuple
- Add Dict2Tuple tool (adds elements of dictionary to tuple)
- Add TMVAClassifier to Dict2Tuple tool
- TMVAClassifier is a DictTransform
- Configure TMVA options
- Add variables to TMVA, must be named the same as in the .xml
- Will run over a few files at cern by default
Tutorial begins at TUTORIAL
N.B. labX notation for input BDT is used with this LoKi notation of CHILD
"""
from __future__ import print_function
from builtins import range
__title__ = "mvaDfromB.py"
__author__ = ["Sam Hall", "Sebastian Neubert"]
__email__ = ["shall@cern.ch", "sneubert@cern.ch"]
################################################################################
# Imports
################################################################################
from DecayTreeTuple.Configuration import *
from Configurables import DaVinci
from Configurables import FilterDesktop
from PhysSelPython.Wrappers import Selection
from PhysSelPython.Wrappers import SelectionSequence
from PhysSelPython.Wrappers import DataOnDemand
################################################################################
# Config
simulation = False
rootInTES = '/Event/Bhadron'
DaVinci(RootInTES=rootInTES, InputType='MDST')
################################################################################
################################################################################
# Imports for LoKi functors
from LoKiPhys.decorators import *
from LoKiArrayFunctors.decorators import *
from LoKiProtoParticles.decorators import *
#from LoKiCore.decorators import * # For debugging in ipython
################################################################################
def labvar(labX, var):
"""Quick function to return formatted lab_variable"""
return 'lab{}_{}'.format(labX, var)
################################################################################
def get_preambulo():
"""Add shorthands to prambulo to make LoKi functors easier to read"""
preambulo = [
'fitVeloChi2 = TINFO(LHCb.Track.FitVeloChi2,-1)',
'fitVeloNdof = TINFO(LHCb.Track.FitVeloNDoF,-1)',
'fitTChi2 = TINFO(LHCb.Track.FitTChi2,-1)',
'fitTNdof = TINFO(LHCb.Track.FitTNDoF,-1)',
]
return preambulo
################################################################################
def get_bdt_vars():
"""Return all variables required for the BDT
Variable names MUST correspond exactly to what is needed by classifier (xml)
If they are unknown: they are in the xml, and they will be shown in stdout
"""
labX = 2 # lab number of parent D
ndau = 3 # number of daughters
bdt_vars = {}
# Variables for D and daughters; labX_ prefix added later
vars_parent = {
'P': 'P',
'PT': 'PT',
'ENDVERTEX_CHI2': 'VFASPF(VCHI2)',
'IPCHI2_OWNPV': 'MIPCHI2DV(PRIMARY)',
'FDCHI2_OWNPV': 'BPVVDCHI2',
}
vars_daughters = {
'P':
'CHILD(P,{0})',
'PT':
'CHILD(PT,{0})',
'PE':
'CHILD(E,{0})',
'PX':
'CHILD(PX,{0})',
'PY':
'CHILD(PY,{0})',
'PZ':
'CHILD(PZ,{0})',
'IPCHI2_OWNPV':
'CHILD(MIPCHI2DV(PRIMARY),{0})',
# If NDOF > 0 then CHi2/NDOF else -1
'TRACK_VeloCHI2NDOF':
'switch(CHILD(fitVeloNdof,{0})>0,CHILD(fitVeloChi2,{0})/CHILD(fitVeloNdof,{0}),-1)',
'TRACK_TCHI2NDOF':
'switch(CHILD(fitTNdof,{0})>0,CHILD(fitTChi2,{0})/CHILD(fitTNdof,{0}),-1)',
'TRACK_MatchCHI2':
'CHILD(TINFO(LHCb.Track.FitMatchChi2,-1.),{0})',
'TRACK_GhostProb':
'CHILD(TRGHOSTPROB,{0})',
'UsedRichAerogel':
'switch(CHILDCUT(PPCUT(PP_USEDAEROGEL),{0}),1,0)',
'UsedRich1Gas':
'switch(CHILDCUT(PPCUT(PP_USEDRICH1GAS),{0}),1,0)',
'UsedRich2Gas':
'switch(CHILDCUT(PPCUT(PP_USEDRICH2GAS),{0}),1,0)',
'RichAbovePiThres':
'switch(CHILDCUT(PPCUT(PP_RICHTHRES_PI),{0}),1,0)',
'RichAboveKaThres':
'switch(CHILDCUT(PPCUT(PP_RICHTHRES_K),{0}),1,0)',
'RichAbovePrThres':
'switch(CHILDCUT(PPCUT(PP_RICHTHRES_P),{0}),1,0)',
'RichDLLe':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLe,-1000),{0})',
'RichDLLmu':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLmu,-1000),{0})',
'RichDLLk':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLk,-1000),{0})',
'RichDLLp':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLp,-1000),{0})',
'RichDLLbt':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLbt,-1000),{0})',
'MuonLLbg':
'CHILD(PPINFO(LHCb.ProtoParticle.MuonBkgLL,-1000),{0})',
'MuonLLmu':
'CHILD(PPINFO(LHCb.ProtoParticle.MuonMuLL,-1000),{0})',
'isMuon':
'switch(CHILDCUT(ISMUON,{0}),1,0)',
'MuonNShared':
'CHILD(PPINFO(LHCb.ProtoParticle.MuonNShared,-1000),{0})',
'VeloCharge':
'CHILD(PPINFO(LHCb.ProtoParticle.VeloCharge,-1000),{0})',
}
# Add all parent D variables to output
for var, loki in vars_parent.items():
bdt_vars.update({labvar(labX, var): loki})
# Add all daughter variables to output
for child, lab in enumerate(range(labX + 1, labX + ndau + 1)):
for var, loki in vars_daughters.items():
bdt_vars.update({labvar(lab, var): loki.format(child + 1)})
# Print out variables for sanity
for key in sorted(bdt_vars):
print('{:<25} : {}'.format(key, bdt_vars[key].replace(',', ', ')))
print(80 * '-')
return bdt_vars
################################################################################
def get_selection_sequence(name):
"""Get the selection from stripping stream"""
# Relative lesLoc for uDST, no preceeding '/'
tesLoc = 'Phys/B2DPiPiD2HHHCFPIDBeauty2CharmLine/Particles'
alg = FilterDesktop('SelFilterFor{}B2D'.format(name))
alg.Code = 'ALL'
reqSels = [DataOnDemand(Location=tesLoc)]
sel = Selection('Sel' + name, Algorithm=alg, RequiredSelections=reqSels)
return SelectionSequence('SelSeq' + name, TopSelection=sel)
################################################################################
def decay_tree_tuple(name, sel_seq, decay):
"""Create simple DecayTree"""
tpl = DecayTreeTuple('{}DTTuple'.format(name))
tpl.Inputs = [sel_seq.outputLocation()]
tpl.ToolList = [
'TupleToolTrigger',
'TupleToolKinematic',
'TupleToolPid',
'TupleToolGeometry',
'TupleToolPrimaries',
]
# Output distributions for pions do not match unless labX == True
tpl.UseLabXSyntax = False # True
tpl.RevertToPositiveID = False
tpl.Decay = decay
return tpl
################################################################################
# Make selection
################################################################################
name = 'b2dpipi'
decay = '[B+ -> ^(D+ -> ^K- ^pi+ ^pi+) ^(rho(770)0 -> ^pi+ ^pi-)]CC'
seq = GaudiSequencer('My{}DTTupleSeq'.format(name))
sel = get_selection_sequence(name)
seq.Members += [sel.sequence()]
# Make tuple
tpl = decay_tree_tuple(name, sel, decay)
################################################################################
# TUTORIAL
################################################################################
# Add branch of the decay where BDT is added
# - in this case adding to (D+ -> K- pi+ pi+)
tpl.addBranches({'D': '[B+ -> ^(D+ -> K- pi+ pi+) (rho(770)0 -> pi+ pi-)]CC'})
LoKi_D = tpl.D.addTupleTool('LoKi::Hybrid::TupleTool/LoKi_D')
# THIS IS THE LINE:
# pass the banch,, xml, variables, name, and whether you want all variables
# in the nTuple (default to False), add preamulo if you wish
from MVADictHelpers import *
addTMVAclassifierTuple(
tpl.D,
'bdt_d2kpipi.xml',
get_bdt_vars(),
Name='BDT',
Keep=True,
Preambulo=get_preambulo())
################################################################################
seq.Members += [tpl]
DaVinci().appendToMainSequence([seq])
################################################################################
# DaVinci
# uDST config at the top
DaVinci().DDDBtag = 'dddb-20130111'
DaVinci().CondDBtag = 'cond-20130114'
DaVinci().Simulation = simulation
DaVinci().EvtMax = -1
DaVinci().SkipEvents = 0
DaVinci().DataType = '2012'
DaVinci().PrintFreq = 1000
DaVinci().TupleFile = 'bdt_d.root'
################################################################################
################################################################################
# Run on some eos data located at CERN
################################################################################
from Configurables import EventSelector
DaVinci().EvtMax = 10000
eos = 'root://eoslhcb.cern.ch//eos/lhcb/grid/prod/lhcb/LHCb/Collision12/BHADRON.MDST'
EventSelector().Input = [
'PFN:{}/00020198/0000/00020198_00007143_1.bhadron.mdst'.format(eos),
'PFN:{}/00020198/0000/00020198_00007352_1.bhadron.mdst'.format(eos),
'PFN:{}/00020738/0000/00020738_00003969_1.bhadron.mdst'.format(eos),
'PFN:{}/00020456/0000/00020456_00001811_1.bhadron.mdst'.format(eos)
]
################################################################################
###############################################################################
# (c) Copyright 2000-2018 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. #
###############################################################################
################################################################################
"""
ADDING BDT TO TUPLE
Example script to run a BDT at DaVinci level over a uDST.
The exact BDT is used to distinguish:
D+ -> K- pi+ pi+
originating from a B. More details available if required.
We use the example decay:
[B+ -> ^(D+ -> ^pi+ ^pi+ ^K-) ^(rho(770)0 -> ^pi+ ^pi-)]CC'
from the B2DPiPiD2HHHCFPIDBeauty2CharmLine.
Workflow goes as the following:
- Create selection from stripping using FilterDesktop
- Create tuple
- Add branch for the D to the tuple
- Add Dict2Tuple tool (adds elements of dictionary to tuple)
- Add TMVAClassifier to Dict2Tuple tool
- TMVAClassifier is a DictTransform
- Configure TMVA options
- Add variables to TMVA, must be named the same as in the .xml
- Will run over a few files at cern by default
Tutorial begins at TUTORIAL
N.B. labX notation for input BDT is used with this LoKi notation of CHILD
"""
from __future__ import print_function
from builtins import range
__title__ = "mvaDfromB_bbdt.py"
__author__ = [
"Sam Hall", "Sebastian Neubert", "Andrey Ustyuzhanin", "Egor Khairullin"
]
__email__ = [
"shall@cern.ch", "sneubert@cern.ch", "austyuzh@cern.ch",
"egor.khairullin@cern.ch"
]
################################################################################
# Imports
################################################################################
from DecayTreeTuple.Configuration import *
from Configurables import DaVinci
from Configurables import FilterDesktop
from PhysSelPython.Wrappers import Selection
from PhysSelPython.Wrappers import SelectionSequence
from PhysSelPython.Wrappers import DataOnDemand
################################################################################
# Config
simulation = False
rootInTES = '/Event/Bhadron'
DaVinci(RootInTES=rootInTES, InputType='MDST')
################################################################################
################################################################################
# Imports for LoKi functors
from LoKiPhys.decorators import *
from LoKiArrayFunctors.decorators import *
from LoKiProtoParticles.decorators import *
#from LoKiCore.decorators import * # For debugging in ipython
################################################################################
def labvar(labX, var):
"""Quick function to return formatted lab_variable"""
return 'lab{}_{}'.format(labX, var)
################################################################################
def get_preambulo():
"""Add shorthands to prambulo to make LoKi functors easier to read"""
preambulo = [
'fitVeloChi2 = TINFO(LHCb.Track.FitVeloChi2,-1)',
'fitVeloNdof = TINFO(LHCb.Track.FitVeloNDoF,-1)',
'fitTChi2 = TINFO(LHCb.Track.FitTChi2,-1)',
'fitTNdof = TINFO(LHCb.Track.FitTNDoF,-1)',
]
return preambulo
################################################################################
def get_bdt_vars():
"""Return all variables required for the BDT
Variable names MUST correspond exactly to what is needed by classifier (xml)
If they are unknown: they are in the xml, and they will be shown in stdout
"""
labX = 2 # lab number of parent D
ndau = 3 # number of daughters
bdt_vars = {}
# Variables for D and daughters; labX_ prefix added later
vars_parent = {
'P': 'P',
'PT': 'PT',
'ENDVERTEX_CHI2': 'VFASPF(VCHI2)',
'IPCHI2_OWNPV': 'MIPCHI2DV(PRIMARY)',
'FDCHI2_OWNPV': 'BPVVDCHI2',
}
vars_daughters = {
'P':
'CHILD(P,{0})',
'PT':
'CHILD(PT,{0})',
'PE':
'CHILD(E,{0})',
'PX':
'CHILD(PX,{0})',
'PY':
'CHILD(PY,{0})',
'PZ':
'CHILD(PZ,{0})',
'IPCHI2_OWNPV':
'CHILD(MIPCHI2DV(PRIMARY),{0})',
# If NDOF > 0 then CHi2/NDOF else -1
'TRACK_VeloCHI2NDOF':
'switch(CHILD(fitVeloNdof,{0})>0,CHILD(fitVeloChi2,{0})/CHILD(fitVeloNdof,{0}),-1)',
'TRACK_TCHI2NDOF':
'switch(CHILD(fitTNdof,{0})>0,CHILD(fitTChi2,{0})/CHILD(fitTNdof,{0}),-1)',
'TRACK_MatchCHI2':
'CHILD(TINFO(LHCb.Track.FitMatchChi2,-1.),{0})',
'TRACK_GhostProb':
'CHILD(TRGHOSTPROB,{0})',
'UsedRichAerogel':
'switch(CHILDCUT(PPCUT(PP_USEDAEROGEL),{0}),1,0)',
'UsedRich1Gas':
'switch(CHILDCUT(PPCUT(PP_USEDRICH1GAS),{0}),1,0)',
'UsedRich2Gas':
'switch(CHILDCUT(PPCUT(PP_USEDRICH2GAS),{0}),1,0)',
'RichAbovePiThres':
'switch(CHILDCUT(PPCUT(PP_RICHTHRES_PI),{0}),1,0)',
'RichAboveKaThres':
'switch(CHILDCUT(PPCUT(PP_RICHTHRES_K),{0}),1,0)',
'RichAbovePrThres':
'switch(CHILDCUT(PPCUT(PP_RICHTHRES_P),{0}),1,0)',
'RichDLLe':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLe,-1000),{0})',
'RichDLLmu':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLmu,-1000),{0})',
'RichDLLk':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLk,-1000),{0})',
'RichDLLp':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLp,-1000),{0})',
'RichDLLbt':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLbt,-1000),{0})',
'MuonLLbg':
'CHILD(PPINFO(LHCb.ProtoParticle.MuonBkgLL,-1000),{0})',
'MuonLLmu':
'CHILD(PPINFO(LHCb.ProtoParticle.MuonMuLL,-1000),{0})',
'isMuon':
'switch(CHILDCUT(ISMUON,{0}),1,0)',
'MuonNShared':
'CHILD(PPINFO(LHCb.ProtoParticle.MuonNShared,-1000),{0})',
'VeloCharge':
'CHILD(PPINFO(LHCb.ProtoParticle.VeloCharge,-1000),{0})',
}
# Add all parent D variables to output
for var, loki in vars_parent.items():
bdt_vars.update({labvar(labX, var): loki})
# Add all daughter variables to output
for child, lab in enumerate(range(labX + 1, labX + ndau + 1)):
for var, loki in vars_daughters.items():
bdt_vars.update({labvar(lab, var): loki.format(child + 1)})
# Print out variables for sanity
for key in sorted(bdt_vars):
print('{:<25} : {}'.format(key, bdt_vars[key].replace(',', ', ')))
print(80 * '-')
return bdt_vars
################################################################################
def get_selection_sequence(name):
"""Get the selection from stripping stream"""
# Relative lesLoc for uDST, no preceeding '/'
tesLoc = 'Phys/B2DPiPiD2HHHCFPIDBeauty2CharmLine/Particles'
alg = FilterDesktop('SelFilterFor{}B2D'.format(name))
alg.Code = 'ALL'
reqSels = [DataOnDemand(Location=tesLoc)]
sel = Selection('Sel' + name, Algorithm=alg, RequiredSelections=reqSels)
return SelectionSequence('SelSeq' + name, TopSelection=sel)
################################################################################
def decay_tree_tuple(name, sel_seq, decay):
"""Create simple DecayTree"""
tpl = DecayTreeTuple('{}DTTuple'.format(name))
tpl.Inputs = [sel_seq.outputLocation()]
tpl.ToolList = [
'TupleToolTrigger',
'TupleToolKinematic',
'TupleToolPid',
'TupleToolGeometry',
'TupleToolPrimaries',
]
# Output distributions for pions do not match unless labX == True
tpl.UseLabXSyntax = False # True
tpl.RevertToPositiveID = False
tpl.Decay = decay
return tpl
################################################################################
# Make selection
################################################################################
name = 'b2dpipi'
decay = '[B+ -> ^(D+ -> ^K- ^pi+ ^pi+) ^(rho(770)0 -> ^pi+ ^pi-)]CC'
seq = GaudiSequencer('My{}DTTupleSeq'.format(name))
sel = get_selection_sequence(name)
seq.Members += [sel.sequence()]
# Make tuple
tpl = decay_tree_tuple(name, sel, decay)
################################################################################
# TUTORIAL
################################################################################
# Add branch of the decay where BDT is added
# - in this case adding to (D+ -> K- pi+ pi+)
tpl.addBranches({'D': '[B+ -> ^(D+ -> K- pi+ pi+) (rho(770)0 -> pi+ pi-)]CC'})
LoKi_D = tpl.D.addTupleTool('LoKi::Hybrid::TupleTool/LoKi_D')
# THIS IS THE LINE:
# pass the banch,, xml, variables, name, and whether you want all variables
# in the nTuple (default to False), add preamulo if you wish
from MVADictHelpers import *
addBBDecTreeclassifierTuple(
tpl.D,
'bbdt.f',
get_bdt_vars(),
Name='BDT',
Keep=True,
Preambulo=get_preambulo())
################################################################################
seq.Members += [tpl]
DaVinci().appendToMainSequence([seq])
################################################################################
# DaVinci
# uDST config at the top
DaVinci().DDDBtag = 'dddb-20130111'
DaVinci().CondDBtag = 'cond-20130114'
DaVinci().Simulation = simulation
DaVinci().EvtMax = -1
DaVinci().SkipEvents = 0
DaVinci().DataType = '2012'
DaVinci().PrintFreq = 1000
DaVinci().TupleFile = 'bdt_d_bbdt.root'
################################################################################
################################################################################
# Run on some eos data located at CERN
################################################################################
from Configurables import EventSelector
DaVinci().EvtMax = 10000
eos = 'root://eoslhcb.cern.ch//eos/lhcb/grid/prod/lhcb/LHCb/Collision12/BHADRON.MDST'
EventSelector().Input = [
'PFN:{}/00020198/0000/00020198_00007143_1.bhadron.mdst'.format(eos),
'PFN:{}/00020198/0000/00020198_00007352_1.bhadron.mdst'.format(eos),
'PFN:{}/00020738/0000/00020738_00003969_1.bhadron.mdst'.format(eos),
'PFN:{}/00020456/0000/00020456_00001811_1.bhadron.mdst'.format(eos)
]
################################################################################
###############################################################################
# (c) Copyright 2000-2018 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. #
###############################################################################
################################################################################
"""
ADDING BDT TO TUPLE
Example script to run a BDT at DaVinci level over a uDST.
The exact BDT is used to distinguish:
D+ -> K- pi+ pi+
originating from a B. More details available if required.
We use the example decay:
[B+ -> ^(D+ -> ^pi+ ^pi+ ^K-) ^(rho(770)0 -> ^pi+ ^pi-)]CC'
from the B2DPiPiD2HHHCFPIDBeauty2CharmLine.
Workflow goes as the following:
- Create selection from stripping using FilterDesktop
- Create tuple
- Add branch for the D to the tuple
- Add Dict2Tuple tool (adds elements of dictionary to tuple)
- Add TMVAClassifier to Dict2Tuple tool
- TMVAClassifier is a DictTransform
- Configure TMVA options
- Add variables to TMVA, must be named the same as in the .xml
- Will run over a few files at cern by default
Tutorial begins at TUTORIAL
N.B. labX notation for input BDT is used with this LoKi notation of CHILD
"""
from __future__ import print_function
from builtins import range
__title__ = "mvaDfromB_matrixnet.py"
__author__ = ["Sam Hall", "Sebastian Neubert", "Andrey Ustyuzhanin"]
__email__ = ["shall@cern.ch", "sneubert@cern.ch", "austyuzh@cern.ch"]
################################################################################
# Imports
################################################################################
from DecayTreeTuple.Configuration import *
from Configurables import DaVinci
from Configurables import FilterDesktop
from PhysSelPython.Wrappers import Selection
from PhysSelPython.Wrappers import SelectionSequence
from PhysSelPython.Wrappers import DataOnDemand
################################################################################
# Config
simulation = False
rootInTES = '/Event/Bhadron'
DaVinci(RootInTES=rootInTES, InputType='MDST')
################################################################################
################################################################################
# Imports for LoKi functors
from LoKiPhys.decorators import *
from LoKiArrayFunctors.decorators import *
from LoKiProtoParticles.decorators import *
#from LoKiCore.decorators import * # For debugging in ipython
################################################################################
def labvar(labX, var):
"""Quick function to return formatted lab_variable"""
return 'lab{}_{}'.format(labX, var)
################################################################################
def get_preambulo():
"""Add shorthands to prambulo to make LoKi functors easier to read"""
preambulo = [
'fitVeloChi2 = TINFO(LHCb.Track.FitVeloChi2,-1)',
'fitVeloNdof = TINFO(LHCb.Track.FitVeloNDoF,-1)',
'fitTChi2 = TINFO(LHCb.Track.FitTChi2,-1)',
'fitTNdof = TINFO(LHCb.Track.FitTNDoF,-1)',
]
return preambulo
################################################################################
def get_bdt_vars():
"""Return all variables required for the BDT
Variable names MUST correspond exactly to what is needed by classifier (xml)
If they are unknown: they are in the xml, and they will be shown in stdout
"""
labX = 2 # lab number of parent D
ndau = 3 # number of daughters
bdt_vars = {}
# Variables for D and daughters; labX_ prefix added later
vars_parent = {
'P': 'P',
'PT': 'PT',
'ENDVERTEX_CHI2': 'VFASPF(VCHI2)',
'IPCHI2_OWNPV': 'MIPCHI2DV(PRIMARY)',
'FDCHI2_OWNPV': 'BPVVDCHI2',
}
vars_daughters = {
'P':
'CHILD(P,{0})',
'PT':
'CHILD(PT,{0})',
'PE':
'CHILD(E,{0})',
'PX':
'CHILD(PX,{0})',
'PY':
'CHILD(PY,{0})',
'PZ':
'CHILD(PZ,{0})',
'IPCHI2_OWNPV':
'CHILD(MIPCHI2DV(PRIMARY),{0})',
# If NDOF > 0 then CHi2/NDOF else -1
'TRACK_VeloCHI2NDOF':
'switch(CHILD(fitVeloNdof,{0})>0,CHILD(fitVeloChi2,{0})/CHILD(fitVeloNdof,{0}),-1)',
'TRACK_TCHI2NDOF':
'switch(CHILD(fitTNdof,{0})>0,CHILD(fitTChi2,{0})/CHILD(fitTNdof,{0}),-1)',
'TRACK_MatchCHI2':
'CHILD(TINFO(LHCb.Track.FitMatchChi2,-1.),{0})',
'TRACK_GhostProb':
'CHILD(TRGHOSTPROB,{0})',
'UsedRichAerogel':
'switch(CHILDCUT(PPCUT(PP_USEDAEROGEL),{0}),1,0)',
'UsedRich1Gas':
'switch(CHILDCUT(PPCUT(PP_USEDRICH1GAS),{0}),1,0)',
'UsedRich2Gas':
'switch(CHILDCUT(PPCUT(PP_USEDRICH2GAS),{0}),1,0)',
'RichAbovePiThres':
'switch(CHILDCUT(PPCUT(PP_RICHTHRES_PI),{0}),1,0)',
'RichAboveKaThres':
'switch(CHILDCUT(PPCUT(PP_RICHTHRES_K),{0}),1,0)',
'RichAbovePrThres':
'switch(CHILDCUT(PPCUT(PP_RICHTHRES_P),{0}),1,0)',
'RichDLLe':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLe,-1000),{0})',
'RichDLLmu':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLmu,-1000),{0})',
'RichDLLk':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLk,-1000),{0})',
'RichDLLp':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLp,-1000),{0})',
'RichDLLbt':
'CHILD(PPINFO(LHCb.ProtoParticle.RichDLLbt,-1000),{0})',
'MuonLLbg':
'CHILD(PPINFO(LHCb.ProtoParticle.MuonBkgLL,-1000),{0})',
'MuonLLmu':
'CHILD(PPINFO(LHCb.ProtoParticle.MuonMuLL,-1000),{0})',
'isMuon':
'switch(CHILDCUT(ISMUON,{0}),1,0)',
'MuonNShared':
'CHILD(PPINFO(LHCb.ProtoParticle.MuonNShared,-1000),{0})',
'VeloCharge':
'CHILD(PPINFO(LHCb.ProtoParticle.VeloCharge,-1000),{0})',
}
# Add all parent D variables to output
for var, loki in vars_parent.items():
bdt_vars.update({labvar(labX, var): loki})
# Add all daughter variables to output
for child, lab in enumerate(range(labX + 1, labX + ndau + 1)):
for var, loki in vars_daughters.items():
bdt_vars.update({labvar(lab, var): loki.format(child + 1)})
# Print out variables for sanity
for key in sorted(bdt_vars):
print('{:<25} : {}'.format(key, bdt_vars[key].replace(',', ', ')))
print(80 * '-')
return bdt_vars
################################################################################
def get_selection_sequence(name):
"""Get the selection from stripping stream"""
# Relative lesLoc for uDST, no preceeding '/'
tesLoc = 'Phys/B2DPiPiD2HHHCFPIDBeauty2CharmLine/Particles'
alg = FilterDesktop('SelFilterFor{}B2D'.format(name))
alg.Code = 'ALL'
reqSels = [DataOnDemand(Location=tesLoc)]
sel = Selection('Sel' + name, Algorithm=alg, RequiredSelections=reqSels)
return SelectionSequence('SelSeq' + name, TopSelection=sel)
################################################################################
def decay_tree_tuple(name, sel_seq, decay):
"""Create simple DecayTree"""
tpl = DecayTreeTuple('{}DTTuple'.format(name))
tpl.Inputs = [sel_seq.outputLocation()]
tpl.ToolList = [
'TupleToolTrigger',
'TupleToolKinematic',
'TupleToolPid',
'TupleToolGeometry',
'TupleToolPrimaries',
]
# Output distributions for pions do not match unless labX == True
tpl.UseLabXSyntax = False # True
tpl.RevertToPositiveID = False
tpl.Decay = decay
return tpl
################################################################################
# Make selection
################################################################################
name = 'b2dpipi'
decay = '[B+ -> ^(D+ -> ^K- ^pi+ ^pi+) ^(rho(770)0 -> ^pi+ ^pi-)]CC'
seq = GaudiSequencer('My{}DTTupleSeq'.format(name))
sel = get_selection_sequence(name)
seq.Members += [sel.sequence()]
# Make tuple
tpl = decay_tree_tuple(name, sel, decay)
################################################################################
# TUTORIAL
################################################################################
# Add branch of the decay where BDT is added
# - in this case adding to (D+ -> K- pi+ pi+)
tpl.addBranches({'D': '[B+ -> ^(D+ -> K- pi+ pi+) (rho(770)0 -> pi+ pi-)]CC'})
LoKi_D = tpl.D.addTupleTool('LoKi::Hybrid::TupleTool/LoKi_D')
# THIS IS THE LINE:
# pass the banch,, xml, variables, name, and whether you want all variables
# in the nTuple (default to False), add preamulo if you wish
from MVADictHelpers import *
addMatrixnetclassifierTuple(
tpl.D,
'matrixnet.mxf',
get_bdt_vars(),
Name='BDT',
Keep=True,
Preambulo=get_preambulo())
################################################################################
seq.Members += [tpl]
DaVinci().appendToMainSequence([seq])
################################################################################
# DaVinci
# uDST config at the top
DaVinci().DDDBtag = 'dddb-20130111'
DaVinci().CondDBtag = 'cond-20130114'
DaVinci().Simulation = simulation
DaVinci().EvtMax = -1
DaVinci().SkipEvents = 0
DaVinci().DataType = '2012'
DaVinci().PrintFreq = 1000
DaVinci().TupleFile = 'bdt_d_matrixnet.root'
################################################################################
################################################################################
# Run on some eos data located at CERN
################################################################################
from Configurables import EventSelector
DaVinci().EvtMax = 10000
eos = 'root://eoslhcb.cern.ch//eos/lhcb/grid/prod/lhcb/LHCb/Collision12/BHADRON.MDST'
EventSelector().Input = [
'PFN:{}/00020198/0000/00020198_00007143_1.bhadron.mdst'.format(eos),
'PFN:{}/00020198/0000/00020198_00007352_1.bhadron.mdst'.format(eos),
'PFN:{}/00020738/0000/00020738_00003969_1.bhadron.mdst'.format(eos),
'PFN:{}/00020456/0000/00020456_00001811_1.bhadron.mdst'.format(eos)
]
################################################################################
###############################################################################
# (c) Copyright 2000-2018 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. #
###############################################################################
################################################################################
# First build the selection
################################################################################
from Configurables import CombineParticles
_jpsi2mumu = CombineParticles("Jpsi2MuMu")
_jpsi2mumu.DecayDescriptor = "J/psi(1S) -> mu+ mu-"
_jpsi2mumu.CombinationCut = "ADAMASS('J/psi(1S)')<30*MeV"
_jpsi2mumu.MotherCut = "(VFASPF(VCHI2/VDOF)<10)"
from PhysSelPython.Wrappers import Selection
from StandardParticles import StdLooseMuons, StdLooseKaons
LooseJpsi2MuMu = Selection(
"SelLooseJpsi2MuMu",
Algorithm=_jpsi2mumu,
RequiredSelections=[StdLooseMuons])
from Configurables import FilterDesktop
_jpsifilter = FilterDesktop("_jpsiFilter", Code="(PT>1*GeV) & (P>3*GeV)")
Jpsi2MuMu = Selection(
"SelJpsi2MuMu", Algorithm=_jpsifilter, RequiredSelections=[LooseJpsi2MuMu])
_phi2kk = CombineParticles("Phi2KK")
_phi2kk.DecayDescriptor = "phi(1020) -> K+ K-"
_phi2kk.CombinationCut = "ADAMASS('phi(1020)')<50*MeV"
#_phi2kk.MotherCut = "(VFASPF(VCHI2/VDOF)<100)"
#####################################################################################
### use a BDT to select the phi
#####################################################################################
from Configurables import LoKi__Hybrid__DictValue as DictValue
from Configurables import LoKi__Hybrid__DictTransform_TMVATransform_ as TMVAClassifier
from Configurables import LoKi__Hybrid__DictOfFunctors
from Configurables import MVAManager
_manager = MVAManager("MVAManager")
TMVA = TMVAClassifier("TMVA")
# Configure the classifier (available options depend on which classifier is used)
TMVA.Options = {
"Name": "BDT", # Name for the MVA response variable
"XMLFile":
"file://${MVADICTTOOLSROOT}/options/TestPhi2KK.xml", # TMVA uses an xml file to load the classifier
"KeepVars":
"0", # Write out the input variables alongside the classifier response
}
# Add a DictOfFunctors as the source of the classifier
# the DictOfFunctors will use LoKiFunctors to query the variables needed
# and write them into the dictionary
TMVA.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict")
TMVA.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict"
# the variable names have to correspond exactly to what is needed by the classifier
# the prefixing with the node names has to be done manually here!
# this allows to apply this to arbitary branches in a decay tree
TMVA.MVAdict.Variables = {
"lab1_PT": "PT",
"lab1_IPCHI2_OWNPV": "MIPCHI2DV(PRIMARY)",
"lab2_PT": "CHILD(PT,1)",
"lab3_PT": "CHILD(PT,2)",
"lab2_IPCHI2_OWNPV": "CHILD(MIPCHI2DV(PRIMARY),1)",
"lab3_IPCHI2_OWNPV": "CHILD(MIPCHI2DV(PRIMARY),2)",
}
_manager.addTool(TMVA) # using TMVA
_manager.MVATransform = "LoKi::Hybrid::DictTransform<TMVATransform>/TMVA"
# use the VALUE functor to access IParticleValue tools
_phi2kk.MotherCut = "VALUE('LoKi::Hybrid::DictValue/MVAResponse')> -0.5"
# we will get our cut value from a dictionary tool
_phi2kk.addTool(DictValue, "MVAResponse")
_phi2kk.MVAResponse.Key = "BDT" # this is the variable we will take from the dictionary
_phi2kk.MVAResponse.Source = "LoKi::Hybrid::DictTransform<TMVATransform>/TMVA:PUBLIC"
#####################################################################################
#####################################################################################
# Finish the selection
Phi2KK = Selection(
"SelPhi2KK", Algorithm=_phi2kk, RequiredSelections=[StdLooseKaons])
_bs2JpsiPhi = CombineParticles(
"Bs2JpsiPhi",
DecayDescriptor="B_s0 -> phi(1020) J/psi(1S)",
CombinationCut="ADAMASS('B_s0')<2*GeV",
MotherCut="(VFASPF(VCHI2/VDOF)<10) & (BPVIPCHI2()<100)")
Bs2JpsiPhi = Selection(
"SelBs2JpsiPhi",
Algorithm=_bs2JpsiPhi,
RequiredSelections=[Phi2KK, Jpsi2MuMu])
from PhysSelPython.Wrappers import SelectionSequence
SeqBs2JpsiPhi = SelectionSequence("SeqBs2JpsiPhi", TopSelection=Bs2JpsiPhi)
simulation = False
from DecayTreeTuple.Configuration import *
tuple = DecayTreeTuple()
tuple.Inputs = ["Phys/SelBs2JpsiPhi/Particles"]
tuple.Decay = "[B_s0 -> ^(J/psi(1S) -> ^mu+ ^mu-) ^(phi(1020) -> ^K+ ^K-)]CC"
tuple.ToolList = []
tuple.UseLabXSyntax = True
tuple.RevertToPositiveID = False
LoKi_All = tuple.addTupleTool("LoKi::Hybrid::TupleTool/LoKi_All")
LoKi_All.Variables = {
"lokiP": "P",
"lokiPT": "PT",
}
if (simulation): tuple.ToolList += ["TupleToolMCTruth"]
from Configurables import DaVinci, LHCbApp
DaVinci().DataType = "2012"
DaVinci().DDDBtag = "dddb-20120831"
DaVinci().CondDBtag = "cond-20120831"
DaVinci().Input = [
'/afs/cern.ch/work/s/shall/dsts/00024183_00028683_1.dimuon.dst'
]
#save an ntuple
DaVinci().EvtMax = 500
DaVinci().UserAlgorithms = [_manager, SeqBs2JpsiPhi, tuple]
DaVinci().TupleFile = "DVNtuples.root"
DaVinci().Simulation = simulation
###############################################################################
# (c) Copyright 2000-2018 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. #
###############################################################################
################################################################################
# First build the selection
################################################################################
from Configurables import CombineParticles
_jpsi2mumu = CombineParticles("Jpsi2MuMu")
_jpsi2mumu.DecayDescriptor = "J/psi(1S) -> mu+ mu-"
_jpsi2mumu.CombinationCut = "ADAMASS('J/psi(1S)')<30*MeV"
_jpsi2mumu.MotherCut = "(VFASPF(VCHI2/VDOF)<10)"
from PhysSelPython.Wrappers import Selection
from StandardParticles import StdLooseMuons, StdLooseKaons
LooseJpsi2MuMu = Selection(
"SelLooseJpsi2MuMu",
Algorithm=_jpsi2mumu,
RequiredSelections=[StdLooseMuons])
from Configurables import FilterDesktop
_jpsifilter = FilterDesktop("_jpsiFilter", Code="(PT>1*GeV) & (P>3*GeV)")
Jpsi2MuMu = Selection(
"SelJpsi2MuMu", Algorithm=_jpsifilter, RequiredSelections=[LooseJpsi2MuMu])
_phi2kk = CombineParticles("Phi2KK")
_phi2kk.DecayDescriptor = "phi(1020) -> K+ K-"
_phi2kk.CombinationCut = "ADAMASS('phi(1020)')<50*MeV"
_phi2kk.MotherCut = "(VFASPF(VCHI2/VDOF)<100)"
Phi2KK = Selection(
"SelPhi2KK", Algorithm=_phi2kk, RequiredSelections=[StdLooseKaons])
_bs2JpsiPhi = CombineParticles(
"Bs2JpsiPhi",
DecayDescriptor="B_s0 -> phi(1020) J/psi(1S)",
CombinationCut="ADAMASS('B_s0')<2*GeV",
MotherCut="(VFASPF(VCHI2/VDOF)<10) & (BPVIPCHI2()<100)")
Bs2JpsiPhi = Selection(
"SelBs2JpsiPhi",
Algorithm=_bs2JpsiPhi,
RequiredSelections=[Phi2KK, Jpsi2MuMu])
from PhysSelPython.Wrappers import SelectionSequence
SeqBs2JpsiPhi = SelectionSequence("SeqBs2JpsiPhi", TopSelection=Bs2JpsiPhi)
simulation = False
from DecayTreeTuple.Configuration import *
tuple = DecayTreeTuple()
tuple.Inputs = ["Phys/SelBs2JpsiPhi/Particles"]
tuple.Decay = "[B_s0 -> (^J/psi(1S) => ^mu+ ^mu-) (^phi(1020) -> ^K+ ^K-)]cc"
tuple.ToolList = []
tuple.UseLabXSyntax = True
tuple.RevertToPositiveID = False
#The traditional TupleTool
#LoKi_All=tuple.addTupleTool("LoKi::Hybrid::TupleTool/LoKi_All")
#LoKi_All.Variables = {
# "lokiP" : "P",
# "lokiPT" : "PT",
#}
################################################################################
# Finished building normal selection
################################################################################
################################################################################
################################################################################
# The NEW MVA Dictionary Tools used to implement an MVAClassifier
################################################################################
# Imports
from Configurables import LoKi__Hybrid__DictOfFunctors
from Configurables import LoKi__Hybrid__Dict2Tuple
from Configurables import LoKi__Hybrid__DictTransform_TMVATransform_ as TMVAClassifier
#We are going to add the MVA tools to the phi
tuple.addBranches({
"Phi": "B_s0 -> (^phi(1020) -> K+ K-) ? ",
})
# we are adding the Dict2Tuple to the Phi branch.
# this will write the MVA classifier response dictionary into the ntuple
# All variables in the dict will be prefixed with "Phi_" as they are added to the ntuple
Phi_tmva = tuple.Phi.addTupleTool(LoKi__Hybrid__Dict2Tuple, "TMVA2Tuple")
# Add the TMVAClassifier to the Dict2Tuple
Phi_tmva.addTool(TMVAClassifier, "TMVA")
Phi_tmva.Source = "LoKi::Hybrid::DictTransform_TMVATransform_/TMVA"
# Configure the classifier (available options depend on which classifier is used)
Phi_tmva.TMVA.Options = {
"Name": "MyBDT", # Name for the MVA response variable
"XMLFile":
"file://${MVADICTTOOLSROOT}/options/TestPhi2KK.xml", # TMVA uses an xml file to load the classifier
"KeepVars":
"0", # Write out the input variables alongside the classifier response
}
# Note that other dictionary transformations can easily be added by
# implementing a new DictTransformationTool using the DictTransformation policies
# see Phys/LoKiArrayFunctors/src/Components/DummyTransform.cpp for a prototype
# Add a DictOfFunctors as the source of the classifier
# the MultiTool will use LoKiFunctors to query the variables needed
Phi_tmva.TMVA.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict3")
Phi_tmva.TMVA.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict3"
# the variable names have to correspond exactly to what is needed by the classifier
# the prefixing with the node names has to be done manually here!
Phi_tmva.TMVA.MVAdict3.Variables = {
"lab1_PT": "PT",
"lab1_IPCHI2_OWNPV": "MIPCHI2DV(PRIMARY)",
"lab2_PT": "CHILD(PT,1)",
"lab3_PT": "CHILD(PT,2)",
"lab2_IPCHI2_OWNPV": "CHILD(MIPCHI2DV(PRIMARY),1)",
"lab3_IPCHI2_OWNPV": "CHILD(MIPCHI2DV(PRIMARY),2)",
}
# CombineParticles.MotherCut = "DICTCUT(TMVA,MyBDT >0.1)"
# How to write a dictionary directly into the ntuple:
#tuple.addTupleTool(LoKi__Hybrid__Dict2Tuple, "MVATuple")
#tuple.MVATuple.addTool(LoKi__Hybrid__DictOfFunctors, "MVADict2Tuple")
#tuple.MVATuple.Source = "MVADict2Tuple"
#tuple.MVATuple.MVADict2Tuple.Variables = variables
################################################################################
# End of MVAClassifier TupleTool
################################################################################
if (simulation): tuple.ToolList += ["TupleToolMCTruth"]
from Configurables import DaVinci, LHCbApp
DaVinci().DataType = "2012"
DaVinci().DDDBtag = "dddb-20120831"
DaVinci().CondDBtag = "cond-20120831"
DaVinci().Input = [
'/afs/cern.ch/work/s/shall/dsts/00020198_00012742_1.dimuon.dst'
]
#save an ntuple
DaVinci().EvtMax = 500
DaVinci().UserAlgorithms = [SeqBs2JpsiPhi, tuple]
DaVinci().TupleFile = "DVNtuples.root"
DaVinci().Simulation = simulation
###############################################################################
# (c) Copyright 2000-2018 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. #
###############################################################################
################################################################################
# First build the selection
################################################################################
from Configurables import CombineParticles
_jpsi2mumu = CombineParticles("Jpsi2MuMu")
_jpsi2mumu.DecayDescriptor = "J/psi(1S) -> mu+ mu-"
_jpsi2mumu.CombinationCut = "ADAMASS('J/psi(1S)')<30*MeV"
_jpsi2mumu.MotherCut = "(VFASPF(VCHI2/VDOF)<10)"
from PhysSelPython.Wrappers import Selection
from StandardParticles import StdLooseMuons, StdLooseKaons
LooseJpsi2MuMu = Selection(
"SelLooseJpsi2MuMu",
Algorithm=_jpsi2mumu,
RequiredSelections=[StdLooseMuons])
from Configurables import FilterDesktop
_jpsifilter = FilterDesktop("_jpsiFilter", Code="(PT>1*GeV) & (P>3*GeV)")
Jpsi2MuMu = Selection(
"SelJpsi2MuMu", Algorithm=_jpsifilter, RequiredSelections=[LooseJpsi2MuMu])
_phi2kk = CombineParticles("Phi2KK")
_phi2kk.DecayDescriptor = "phi(1020) -> K+ K-"
_phi2kk.CombinationCut = "ADAMASS('phi(1020)')<50*MeV"
#_phi2kk.MotherCut = "(VFASPF(VCHI2/VDOF)<100)"
#####################################################################################
### use a BDT to select the phi
#####################################################################################
# input variables needed by BDT
Vars = {
"lab1_PT": "PT",
"lab1_IPCHI2_OWNPV": "MIPCHI2DV(PRIMARY)",
"lab2_PT": "CHILD(PT,1)",
"lab3_PT": "CHILD(PT,2)",
"lab2_IPCHI2_OWNPV": "CHILD(MIPCHI2DV(PRIMARY),1)",
"lab3_IPCHI2_OWNPV": "CHILD(MIPCHI2DV(PRIMARY),2)",
}
# use the VALUE functor to access IParticleValue tools
_phi2kk.MotherCut = "VALUE('LoKi__Hybrid__DictValue/MVAResponse')> -0.5"
# add the complete tool chain with one command:
from MVADictHelpers import *
addTMVAclassifierValue(
Component=_phi2kk,
XMLFile="file://${MVADICTTOOLSROOT}/options/TestPhi2KK.xml",
Variables=Vars,
Name="MVAResponse")
#####################################################################################
#####################################################################################
# Finish the selection
Phi2KK = Selection(
"SelPhi2KK", Algorithm=_phi2kk, RequiredSelections=[StdLooseKaons])
_bs2JpsiPhi = CombineParticles(
"Bs2JpsiPhi",
DecayDescriptor="B_s0 -> phi(1020) J/psi(1S)",
CombinationCut="ADAMASS('B_s0')<2*GeV",
MotherCut="(VFASPF(VCHI2/VDOF)<10) & (BPVIPCHI2()<100)")
Bs2JpsiPhi = Selection(
"SelBs2JpsiPhi",
Algorithm=_bs2JpsiPhi,
RequiredSelections=[Phi2KK, Jpsi2MuMu])
from PhysSelPython.Wrappers import SelectionSequence
SeqBs2JpsiPhi = SelectionSequence("SeqBs2JpsiPhi", TopSelection=Bs2JpsiPhi)
simulation = False
from DecayTreeTuple.Configuration import *
tuple = DecayTreeTuple()
tuple.Inputs = ["Phys/SelBs2JpsiPhi/Particles"]
tuple.Decay = "[B_s0 -> ^(J/psi(1S) -> ^mu+ ^mu-) ^(phi(1020) -> ^K+ ^K-)]CC"
tuple.ToolList = []
tuple.UseLabXSyntax = True
tuple.RevertToPositiveID = False
LoKi_All = tuple.addTupleTool("LoKi::Hybrid::TupleTool/LoKi_All")
LoKi_All.Variables = {
"lokiP": "P",
"lokiPT": "PT",
}
if (simulation): tuple.ToolList += ["TupleToolMCTruth"]
from Configurables import DaVinci, LHCbApp
DaVinci().DataType = "2012"
DaVinci().DDDBtag = "dddb-20120831"
DaVinci().CondDBtag = "cond-20120831"
DaVinci().Input = [
'/afs/cern.ch/work/s/shall/dsts/00020198_00012742_1.dimuon.dst'
]
#save an ntuple
DaVinci().EvtMax = 500
DaVinci().UserAlgorithms = [SeqBs2JpsiPhi, tuple]
DaVinci().TupleFile = "DVNtuples.root"
DaVinci().Simulation = simulation
###############################################################################
# (c) Copyright 2000-2018 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. #
###############################################################################
# Helper functions to configure complete MVAclassifier tool chains
# TMVA Value (to be used for cutting)
def addTMVAclassifierValue(Component, XMLFile, Variables, ToolName):
from Configurables import LoKi__Hybrid__DictValue as DictValue
Component.addTool(DictValue, ToolName)
MVAResponse = getattr(Component, ToolName)
Key = "BDT"
MVAResponse.Key = Key
MVAResponse.Source = "LoKi::Hybrid::DictTransform<TMVATransform>/TMVA"
Options = {"XMLFile": XMLFile, "Name": Key, "KeepVars": "0"}
from Configurables import LoKi__Hybrid__DictTransform_TMVATransform_ as TMVAtransform
from Configurables import LoKi__Hybrid__DictOfFunctors
MVAResponse.addTool(TMVAtransform, "TMVA")
MVAResponse.TMVA.Options = Options
MVAResponse.TMVA.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict"
MVAResponse.TMVA.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict")
MVAResponse.TMVA.MVAdict.Variables = Variables
return MVAResponse
# TMVA tuple (to be added to the HybridTupleTool)
def addTMVAclassifierTuple(Branch,
XMLFile,
Variables,
Name="BDT",
Keep=False,
Preambulo=[]):
from Configurables import LoKi__Hybrid__Dict2Tuple as Dict2Tuple
Branch.addTupleTool(Dict2Tuple, Name)
MVAResponse = getattr(Branch, Name)
#Key = "BDT"
#MVAResponse.Key = Key
MVAResponse.Source = "LoKi::Hybrid::DictTransform<TMVATransform>/TMVA"
Options = {
"XMLFile": XMLFile,
"Name": Name,
"KeepVars": "1" if Keep else "0"
}
from Configurables import LoKi__Hybrid__DictTransform_TMVATransform_ as TMVAtransform
from Configurables import LoKi__Hybrid__DictOfFunctors
MVAResponse.addTool(TMVAtransform, "TMVA")
MVAResponse.TMVA.Options = Options
MVAResponse.TMVA.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict"
MVAResponse.TMVA.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict")
MVAResponse.TMVA.MVAdict.Preambulo = Preambulo
MVAResponse.TMVA.MVAdict.Variables = Variables
return MVAResponse
# Matrixnet Value (to be used for cutting)
def addMatrixnetclassifierValue(Component,
MatrixnetFile,
Variables,
ToolName,
Preambulo=[]):
from Configurables import LoKi__Hybrid__DictValue as DictValue
Component.addTool(DictValue, ToolName)
MVAResponse = getattr(Component, ToolName)
Key = "BDT"
MVAResponse.Key = Key
MVAResponse.Source = "LoKi::Hybrid::DictTransform<MatrixnetTransform>/Matrixnet"
Options = {"MatrixnetFile": MatrixnetFile, "Name": Key, "KeepVars": "0"}
from Configurables import LoKi__Hybrid__DictTransform_MatrixnetTransform_ as Matrixnettransform
from Configurables import LoKi__Hybrid__DictOfFunctors
MVAResponse.addTool(Matrixnettransform, "Matrixnet")
MVAResponse.Matrixnet.Options = Options
MVAResponse.Matrixnet.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict"
MVAResponse.Matrixnet.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict")
MVAResponse.Matrixnet.MVAdict.Preambulo = Preambulo
MVAResponse.Matrixnet.MVAdict.Variables = Variables
return MVAResponse
# Matrixnet tuple (to be added to the HybridTupleTool)
def addMatrixnetclassifierTuple(Branch,
MatrixnetFile,
Variables,
Name="BDT",
Keep=False,
Preambulo=[]):
from Configurables import LoKi__Hybrid__Dict2Tuple as Dict2Tuple
Branch.addTupleTool(Dict2Tuple, Name)
MVAResponse = getattr(Branch, Name)
#Key = "BDT"
#MVAResponse.Key = Key
MVAResponse.Source = "LoKi::Hybrid::DictTransform<MatrixnetTransform>/Matrixnet"
Options = {
"MatrixnetFile": MatrixnetFile,
"Name": Name,
"KeepVars": "1" if Keep else "0"
}
from Configurables import LoKi__Hybrid__DictTransform_MatrixnetTransform_ as Matrixnettransform
from Configurables import LoKi__Hybrid__DictOfFunctors
MVAResponse.addTool(Matrixnettransform, "Matrixnet")
MVAResponse.Matrixnet.Options = Options
MVAResponse.Matrixnet.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict"
MVAResponse.Matrixnet.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict")
MVAResponse.Matrixnet.MVAdict.Preambulo = Preambulo
MVAResponse.Matrixnet.MVAdict.Variables = Variables
return MVAResponse
# BBDecTree Value (to be used for cutting)
def addBBDecTreeclassifierValue(Component,
BBDecTreeFile,
Variables,
ToolName,
Preambulo=[]):
from Configurables import LoKi__Hybrid__DictValue as DictValue
Component.addTool(DictValue, ToolName)
MVAResponse = getattr(Component, ToolName)
Key = "BDT"
MVAResponse.Key = Key
MVAResponse.Source = "LoKi::Hybrid::DictTransform<BBDecTreeTransform>/BBDecTree"
Options = {"BBDecTreeFile": BBDecTreeFile, "Name": Key, "KeepVars": "0"}
from Configurables import LoKi__Hybrid__DictTransform_BBDecTreeTransform_ as BBDecTreetransform
from Configurables import LoKi__Hybrid__DictOfFunctors
MVAResponse.addTool(BBDecTreetransform, "BBDecTree")
MVAResponse.BBDecTree.Options = Options
MVAResponse.BBDecTree.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict"
MVAResponse.BBDecTree.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict")
MVAResponse.BBDecTree.MVAdict.Preambulo = Preambulo
MVAResponse.BBDecTree.MVAdict.Variables = Variables
return MVAResponse
# BBDecTree tuple (to be added to the HybridTupleTool)
def addBBDecTreeclassifierTuple(Branch,
BBDecTreeFile,
Variables,
Name="BDT",
Keep=False,
Preambulo=[]):
from Configurables import LoKi__Hybrid__Dict2Tuple as Dict2Tuple
Branch.addTupleTool(Dict2Tuple, Name)
MVAResponse = getattr(Branch, Name)
#Key = "BDT"
#MVAResponse.Key = Key
MVAResponse.Source = "LoKi::Hybrid::DictTransform<BBDecTreeTransform>/BBDecTree"
Options = {
"BBDecTreeFile": BBDecTreeFile,
"Name": Name,
"KeepVars": "1" if Keep else "0"
}
from Configurables import LoKi__Hybrid__DictTransform_BBDecTreeTransform_ as BBDecTreetransform
from Configurables import LoKi__Hybrid__DictOfFunctors
MVAResponse.addTool(BBDecTreetransform, "BBDecTree")
MVAResponse.BBDecTree.Options = Options
MVAResponse.BBDecTree.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict"
MVAResponse.BBDecTree.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict")
MVAResponse.BBDecTree.MVAdict.Preambulo = Preambulo
MVAResponse.BBDecTree.MVAdict.Variables = Variables
# end of function
## HEPDrone Value (to be used for cutting)
def addHEPDroneclassifierValue(Component,
HEPDroneFile,
Variables,
ToolName,
Preambulo=[]):
from Configurables import LoKi__Hybrid__DictValue as DictValue
Component.addTool(DictValue, ToolName)
MVAResponse = getattr(Component, ToolName)
Key = "HDNN"
MVAResponse.Key = Key
MVAResponse.Source = "LoKi::Hybrid::DictTransform<HEPDroneTransform>/HEPDrone"
Options = {
"HEPDroneFile": HEPDroneFile,
"Name": Key,
"KeepVars": "0",
"JSONConfig": "1"
}
from Configurables import LoKi__Hybrid__DictTransform_HEPDroneTransform_ as HEPDronetransform
from Configurables import LoKi__Hybrid__DictOfFunctors
MVAResponse.addTool(HEPDronetransform, "HEPDrone")
MVAResponse.HEPDrone.Options = Options
MVAResponse.HEPDrone.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict"
MVAResponse.HEPDrone.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict")
MVAResponse.HEPDrone.MVAdict.Preambulo = Preambulo
MVAResponse.HEPDrone.MVAdict.Variables = Variables
return MVAResponse
## HEPDrone tuple (to be added to the HybridTupleTool)
def addHEPDroneclassifierTuple(Branch,
HEPDroneFile,
Variables,
Name="HDNN",
Keep=False,
Preambulo=[]):
from Configurables import LoKi__Hybrid__Dict2Tuple as Dict2Tuple
Branch.addTupleTool(Dict2Tuple, Name)
MVAResponse = getattr(Branch, Name)
# Key = "HDNN"
# MVAResponse.Key = Key
MVAResponse.Source = "LoKi::Hybrid::DictTransform<HEPDroneTransform>/HEPDrone"
Options = {
"HEPDroneFile": HEPDroneFile,
"Name": Name,
"KeepVars": "1" if Keep else "0",
"JSONConfig": "1" if Keep else "0"
}
from Configurables import LoKi__Hybrid__DictTransform_HEPDroneTransform_ as HEPDronetransform
from Configurables import LoKi__Hybrid__DictOfFunctors
MVAResponse.addTool(HEPDronetransform, "HEPDrone")
MVAResponse.HEPDrone.Options = Options
MVAResponse.HEPDrone.Source = "LoKi::Hybrid::DictOfFunctors/MVAdict"
MVAResponse.HEPDrone.addTool(LoKi__Hybrid__DictOfFunctors, "MVAdict")
MVAResponse.HEPDrone.MVAdict.Preambulo = Preambulo
MVAResponse.HEPDrone.MVAdict.Variables = Variables
# end of function
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment