diff --git a/.gitignore b/.gitignore index ee0f53dd..6090f9a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,139 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# PyCharm type checker +.idea/ + +# VScode type checker +.vscode/ + .github_meta.log */*.pyc */*/*.pyc @@ -13,5 +149,19 @@ tools/SampleAnalyzer/Test/Makefile_* */*/*.log doc/??????_mode.log doc/??????_mode.pdf +.ma5history +architecture.ma5 +setup.sh +setup.csh +tools/SampleAnalyzer/Commons/Makefile +tools/SampleAnalyzer/Configuration/Makefile +tools/SampleAnalyzer/Process/Makefile +PortabilityTags.h .DS_Store ANALYSIS_* +samples/* +tools/fastjet +tools/HEPTopTagger +tools/zlib +fastjet-config +tools/SampleAnalyzer/Bin \ No newline at end of file diff --git a/README.md b/README.md index 05605b84..3e7d6115 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ ![Python v3.8](https://img.shields.io/badge/python-3670A0?style=plastic&logo=python&logoColor=ffdd54&label=3.8&color=brightgreen) ![C++](https://img.shields.io/badge/c++-%2300599C.svg?style=plastic&logo=c%2B%2B&logoColor=white&label=11) +[![CI](https://github.com/MadAnalysis/madanalysis5/actions/workflows/quick_validation.yml/badge.svg?style=plastic)](https://github.com/MadAnalysis/madanalysis5/actions/workflows/quick_validation.yml) + ## Outline - [What is MadAnalysis 5?](#what-is-madanalysis-5) - [Requirements](#requirements) @@ -234,7 +236,8 @@ authors thank you for this. In the following you can find supported third party software that can be used within MadAnalysis 5. The [latest release](https://github.com/MadAnalysis/madanalysis5/releases) of MadAnalysis 5 has been tested with enlisted versions. -- [FastJet](http://fastjet.fr) v3.3.3 +- [FastJet](http://fastjet.fr) v3.4.0 +- [FastJet Contrib](https://fastjet.hepforge.org/contrib/) v1.048 - [Delphes](https://github.com/delphes/delphes) v3.5.0 - [ROOT](https://root.cern) v6.04.08 - [pyhf](https://github.com/scikit-hep/pyhf) v0.7.3 diff --git a/bin/ma5 b/bin/ma5 index ed3e9f7d..bb2d4739 100755 --- a/bin/ma5 +++ b/bin/ma5 @@ -74,8 +74,8 @@ sys.path.insert(0, servicedir) # Release version # Do not touch it !!!!! -version = "1.10.12" -date = "2023/09/13" +version = "2.0.8" +date = "2023/05/31" # Loading the MadAnalysis session import madanalysis.core.launcher diff --git a/doc/README.md b/doc/README.md index c805ce20..42d1eaac 100644 --- a/doc/README.md +++ b/doc/README.md @@ -16,3 +16,7 @@ Information can also be found in the following files. project from its early days to now. - [PAD](./PAD.md): guidelines to submit a new analysis to our Public Analysis Database (PAD). + +Further details on the usage of specific modules can be found in the following files: +- [Jet Substructure](../tools/SampleAnalyzer/Interfaces/substructure/README.md) +- [HEPTopTagger](../tools/SampleAnalyzer/Interfaces/HEPTopTagger/README.md) diff --git a/doc/makedoc b/doc/makedoc index 1fbcf3d8..e3fbabda 100755 --- a/doc/makedoc +++ b/doc/makedoc @@ -2,11 +2,11 @@ ################################################################################ # -# Copyright (C) 2012-2018 Eric Conte, Benjamin Fuks +# Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: -# +# # This file is part of MadAnalysis 5. -# Official website: +# Official website: # # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/doc/normal_mode/main_normal.tex b/doc/normal_mode/main_normal.tex index 9ef52bc3..37f69f16 100644 --- a/doc/normal_mode/main_normal.tex +++ b/doc/normal_mode/main_normal.tex @@ -48,14 +48,15 @@ \begin{document} \begin{center} -{\color{ao} \huge \textbf{\textsc{MadAnalysis} 5 v1.9}} \\ \vspace{0.25cm} +{\color{ao} \huge \textbf{\textsc{MadAnalysis} 5 v2.0}} \\ \vspace{0.25cm} {\color{ao} \huge \textbf{Normal-Mode reference card}} \\ \vspace{0.25cm} \vspace{0.1cm} \textsl{\today}\\ \vspace{0.1cm} \textsl{website: \url{http://madanalysis.irmp.ucl.ac.be/}}\\ \vspace{0.1cm} \textsl{References:\\ \href{https://arxiv.org/abs/1206.1599}{arXiv:1206.1599 [hep-ph]}, \href{https://arxiv.org/abs/1405.3982}{arXiv:1405.3982 [hep-ph]}, \href{https://arxiv.org/abs/1407.3278}{arXiv:1407.3278 [hep-ph]},\\ \href{https://arxiv.org/abs/1910.11418}{arXiv:1910.11418 [hep-ph]}, -\href{https://arxiv.org/abs/2006.09387}{arXiv2006.09387 [hep-ph]} +\href{https://arxiv.org/abs/2006.09387}{arXiv2006.09387 [hep-ph]}, +\href{https://arxiv.org/abs/2206.14870}{arXiv: 2206.14870 [hep-ph]} } \end{center} @@ -604,6 +605,15 @@ \section{\Large Using \FJnorm\ through \MAnorm}\label{sec:fastjet} procedure of the CDF reconstruction algorithms.\\ \color{ao} \verb?spacing? & Grid spacing in the grid jet algorithm.\\ \color{ao} \verb?ymax? & Maximum rapidity value in the grid jet algorithm.\\ + +\color{ao} \verb?electron_isocone_radius? & Creates an isolation cone around each electron relative to HCAL deposits.\\ +\color{ao} \verb?muon_isocone_radius? & Creates an isolation cone around each muon relative to HCAL deposits.\\ +\color{ao} \verb?photon_isocone_radius? & Creates an isolation cone around each photon relative to HCAL deposits.\\ +\color{ao} \verb?track_isocone_radius? & Creates an isolation cone around each track relative to HCAL deposits.\\ + +\color{ao} \verb?particle_propagator? & Enables particle propagator module. Default \verb?off?.\\ +\color{ao} \verb?magnetic_field? & Sets magnetic field strength in T. Default 3.8 T.\\ + \hline \end{tabular} \end{center} @@ -624,9 +634,15 @@ \section{\Large Using \FJnorm\ through \MAnorm}\label{sec:fastjet} a float.\\ \color{ao} \verb?bjet_id.misid_ljet? & Mistagging rate of a light jet as a $b$-jet, as a float.\\ + +\color{ao} \verb?cjet_id.status? & Enable advanced $c$-jet tagging and mistagging capabilities by setting the flag to \verb?on/off?. Default: \verb?off?.\\ +\color{ao} \verb?cjet_id.exclusive? & Allows several $c$-jets to be issued from a single charmed hadron. Only available if \verb?cjet_id.status? is on.\\ +\color{ao} \verb?cjet_id.matching_dr? & Angular distance parameter allowing us to match a $c$-jet with a given charmed hadron. Only available if \verb?cjet_id.status? is on.\\ + \color{ao} \verb?tau_id.efficiency? & Tau-tagging efficiency, as a float.\\ \color{ao} \verb?tau_id.misid_ljet? & Mistagging rate of a light jet as a hadronic tau, as a float.\\ + \color{ao} \verb?tau_id.reconstruction_method? & Method to use to reconstruct hadronic taus. Jet-based reconstruction allows for the matching of truth-level taus with jets. Hadron-based reconstruction first finds all hadronic taus in the event, and then uses them as tau objects. Default: \verb?hadron-based?.\\ \hline \end{tabular} \end{center} @@ -756,6 +772,9 @@ \section{\Large Multipartonic matrix element merging} object. \\ \color{ao} \verb?jes? & Generates a function to scale reconstructed jet energy. \\ \color{ao} \verb?energy_scaling? & Generates a function to scale reconstructed object energy. \\ + + \color{ao} \verb?jet_algorithm? & Defines a new jet object. \\ + \hline \end{tabular} \end{center} @@ -853,7 +872,20 @@ \section{\Large Multipartonic matrix element merging} \end{verbatim}} Define the rescaling corrections to apply to the energy of a reconstructed object {\tt }. The corresponding energy scaling function is given by {\tt }. -The bounds correspond to the domain that scaling function applies ({\tt PT > ..., ETA < ...}, etc.). +The bounds correspond to the domain on which the scaling function applies ({\tt PT > ..., ETA < ...}, etc.). + +The \verb?jet_algorithm? submodule can be used following the syntax +{\color{ao} \begin{verbatim} + define jet_algorithm +\end{verbatim}} +or +{\color{ao} \begin{verbatim} + define jet_algorithm + set . = +\end{verbatim}} +Here {\tt } stands for the identifier of this particular jet definition, and can take any value except the same names as event samples. \texttt{} refers to the desired clustering algorithm, and \texttt{} are the specific parameters defining the configuration of the clustering algorithm used. Details about the usage of this module both in normal mode and expert mode can be found in {\tt madanalysis5/tools/SampleAnalyzer/Interfaces/substructure/README.md}. + + %\vspace{3cm} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{shaded} diff --git a/doc/releases/changelog-v2.0.md b/doc/releases/changelog-v2.0.md new file mode 100644 index 00000000..f028a7ed --- /dev/null +++ b/doc/releases/changelog-v2.0.md @@ -0,0 +1,77 @@ +# Release 2.0.0-dev (development release) + +## New features since last release + +* A module allowing for jet substructure studies has been implemented in + MadAnalysis 5. [(#13)](https://github.com/MadAnalysis/madanalysis5/pull/13) + * It includes the following fastjet-contrib functionalities: + * VariableR: normal and expert mode + * SoftDrop: expert mode + * Clusterer: expert mode + * Jet Filtering: expert mode + * Reclustering: expert mode + * Nsubjettiness: expert mode + * Pruner: expert mode + * Energy Correlator: expert mode + * HEPTopTagger: expert mode + * `RecJetFormat` has been wrapped with a `PseudoJet` structure to accommodate + dynamic transition between two objects. + + All these methods can be used through the SFS interface. + +* Substructure and HEPTopTagger has been redesigned to be shared libraries, so + that MadAnalysis could be compiled without these modules as well. + [(#63)](https://github.com/MadAnalysis/madanalysis5/pull/63) + +* The tagger module has been redesigned to accommodate the features of + substructure module. + [(#86)](https://github.com/MadAnalysis/madanalysis5/pull/86) + +* Multi-level object tagging has been enabled through the SFS framework. + ([#97](https://github.com/MadAnalysis/madanalysis5/pull/97)) + * Option to activate charm-jet tagging has been introduced. + * Option to use jet-based hadronic tau matching has been introduced. + +* Command to fix random seed has been added. + [(#86)](https://github.com/MadAnalysis/madanalysis5/pull/86) + +## Improvements + +* The SFS libraries are now included in the file `analysisList.h`, instead of in + the main analysis file. This leads to much cleaner and independent analysis + construction. [(#86)](https://github.com/MadAnalysis/madanalysis5/pull/86) + +* Compilation time testing has been added for the jet Substructure and + HEPTopTagger interfaces + ([#86](https://github.com/MadAnalysis/madanalysis5/pull/86)). + +* `fatjet` and `genjet` collections have been merged into `jetcollection` map. + ([#135](https://github.com/MadAnalysis/madanalysis5/pull/135)) + +* Accessors of the `MABoost` class has been extended. + [(#13)](https://github.com/MadAnalysis/madanalysis5/pull/13) + +## Bug fixes + +* Various bugfixes for matching the numeric results to MA5 v1.10. + ([#97](https://github.com/MadAnalysis/madanalysis5/pull/97)) + +* $M_{eff}$ definition has been fixed. + [(#86)](https://github.com/MadAnalysis/madanalysis5/pull/86) + +* Jet collection accessor has been fixed in DelphesMa5Tune + ([#135](https://github.com/MadAnalysis/madanalysis5/pull/135)) + +* Submit function has been modified to eliminate issues with LHCO + reader mentioned in issue [#136](https://github.com/MadAnalysis/madanalysis5/issues/136). + ([#167](https://github.com/MadAnalysis/madanalysis5/pull/167)) + +* Delphes crash fixed due to miscommunication between libraries see issue [#204](https://github.com/MadAnalysis/madanalysis5/issues/204). + ([#208](https://github.com/MadAnalysis/madanalysis5/pull/208)) + +## Contributors + +This release contains contributions from (in alphabetical order): + +[Jack Y. Araz](https://github.com/jackaraz), +[Benjamin Fuks](https://github.com/BFuks) diff --git a/madanalysis/IOinterface/job_writer.py b/madanalysis/IOinterface/job_writer.py index c5fae488..cd178ea7 100644 --- a/madanalysis/IOinterface/job_writer.py +++ b/madanalysis/IOinterface/job_writer.py @@ -28,10 +28,15 @@ from shell_command import ShellCommand from madanalysis.enumeration.ma5_running_type import MA5RunningType import logging -import shutil import os +import shutil + import six +from madanalysis.IOinterface.folder_writer import FolderWriter +from madanalysis.selection.instance_name import InstanceName + + class JobWriter(object): def __init__(self,main,jobdir,resubmit=False): @@ -204,7 +209,7 @@ def Open(self): def CopyDelphesCard(self,input,output,cfg,theFile): TagTreeWriter=False TagExecutionPath=False - + # READING THE FILE for line in input: @@ -219,7 +224,7 @@ def CopyDelphesCard(self,input,output,cfg,theFile): if myline.startswith('#'): output.write(line) continue - + if len(words)>=2: if words[0].lower()=='set' and \ words[1].lower()=='executionpath': @@ -267,15 +272,15 @@ def CopyDelphesCard(self,input,output,cfg,theFile): if words[3].lower()=='eflowneutralhadron' and cfg.skim_eflow: output.write('#'+line) continue - + # Enter TreeWriter output.write(line) - + def CopyDelphesMA5Card(self,input,output,cfg,theFile): TagTreeWriter=False TagExecutionPath=False - + # READING THE FILE for line in input: @@ -323,12 +328,12 @@ def CreateDelphesCard(self): # Adding file if cfg.pileup.startswith('/'): theFile = cfg.pileup - else: + else: theFile = os.path.normpath(theDir+"/"+cfg.pileup) - + if self.main.fastsim.package=="delphes": self.CopyDelphesCard(input,output,cfg,theFile) - elif self.main.fastsim.package=="delphesMA5tune": + elif self.main.fastsim.package=="delphesMA5tune": self.CopyDelphesMA5Card(input,output,cfg,theFile) try: @@ -358,7 +363,7 @@ def CopyLHEAnalysis(self): except: logging.getLogger('MA5').error('Impossible to copy the file "newAnalyzer"') return False - try: + try: os.chmod(self.path+"/Build/SampleAnalyzer/newAnalyzer.py",0o755) except: logging.getLogger('MA5').error('Impossible to make executable the file "newAnalyzer"') @@ -388,7 +393,7 @@ def CreateHeader(self,file): def PrintIncludes(self,file): file.write('// SampleHeader header\n') file.write('#include "SampleAnalyzer/Process/Core/SampleAnalyzer.h"\n') - file.write('#include "SampleAnalyzer/User/Analyzer/analysisList.h"\n') + file.write('#include "SampleAnalyzer/User/Analyzer/analysisList.h"\n') file.write('using namespace MA5;\n\n') return @@ -461,18 +466,17 @@ def CreateMainFct(self,file,analysisName,outputName): # Fast-Simulation detector # + Case Fastsim + # + Case extra jet definitions if self.main.fastsim.package=="fastjet": file.write(' //Getting pointer to the clusterer\n') file.write(' std::map parametersC1;\n') parameters = self.main.fastsim.SampleAnalyzerConfigString() - for k,v in sorted(six.iteritems(parameters),\ - key=lambda k_v: (k_v[0],k_v[1])): - file.write(' parametersC1["'+k+'"]="'+v+'";\n') - + for k,v in sorted(six.iteritems(parameters),key=lambda k_v: (k_v[0],k_v[1])): + file.write(' parametersC1["' + (k + '"').ljust(30, " ") + '] = "' + v + '";\n') for obj in ["electron","muon","track","photon"]: if len(getattr(self.main.superfastsim, obj+"_isocone_radius")) != 0: file.write( - ' parametersC1["isolation.'+obj+'.radius"]="'+ ','.join( + ' parametersC1[' + ('"isolation.' + obj + '.radius"').ljust(30, " ") + '] = "' + ','.join( [str(x) for x in getattr(self.main.superfastsim, obj+"_isocone_radius")] )+'";\n' ) @@ -480,22 +484,43 @@ def CreateMainFct(self,file,analysisName,outputName): file.write(' manager.InitializeJetClusterer("'+\ self.main.fastsim.clustering.algorithm+'",parametersC1);\n') file.write(' if (cluster1==0) return 1;\n\n') + if len(self.main.jet_collection) > 0: + # Write configuration for other jets + for ix, (key, item) in enumerate(self.main.jet_collection.collection.items()): + map_name = "JetConfiguration"+str(ix+1) + file.write(' //Adding new jet with ID ' + key + '\n') + file.write(' std::map '+map_name+';\n') + for opt, val in item.__dict__.items(): + if opt in ['JetID','algorithm']: + file.write(' '+map_name+'["'+(opt+'"').ljust(20,' ') + '] = "'+str(val)+'";\n') + else: + # To follow old syntax add "cluster.". + # This is not necessary but makes sense for unified syntax + opt = opt.replace('radius','R') + opt = opt.replace('ptmin','PTmin') + valule = val if type(val) != bool else val*(1) + file.write(' '+map_name+'["'+('cluster.'+opt+'"').ljust(18,' ') +\ + '] = "'+str(valule)+'";\n') + file.write(' cluster1->LoadJetConfiguration('+map_name+');\n\n') if self.main.superfastsim.isNewSmearerOn(): file.write(' // Declaration of the smearer\n') file.write(' SmearerBase* mySmearer = new NewSmearer();\n') file.write(' cluster1->LoadSmearer(mySmearer);\n\n') if self.main.superfastsim.isTaggerOn(): file.write(' // Declaration of a generic tagger\n') - file.write(' NewTagger* tagger = new NewTagger();\n\n') + file.write(' NewTagger* myTagger = new NewTagger();\n') + file.write(' cluster1->LoadTagger(myTagger);\n\n') + # + Case Delphes if self.main.fastsim.package in ["delphes","delphesMA5tune"]: file.write(' //Getting pointer to fast-simulation package\n') file.write(' std::map parametersD1;\n') - if self.fastsim.package=="delphesMA5tune": - cfg=self.main.fastsim.delphesMA5tune - else: - cfg=self.main.fastsim.delphes + #@JACK: This variable is not used + #if self.fastsim.package=="delphesMA5tune": + # cfg=self.main.fastsim.delphesMA5tune + #else: + # cfg=self.main.fastsim.delphes parameters = self.main.fastsim.SampleAnalyzerConfigString() for k,v in sorted(six.iteritems(parameters),\ key=lambda k_v1: (k_v1[0],k_v1[1])): @@ -576,8 +601,6 @@ def CreateMainFct(self,file,analysisName,outputName): file.write(' if (!analyzer2->Execute(mySample,myEvent)) continue;\n') if self.main.fastsim.package=="fastjet": file.write(' cluster1->Execute(mySample,myEvent);\n') - if self.main.superfastsim.isTaggerOn(): - file.write(' tagger->Execute(mySample,myEvent);\n') elif self.main.fastsim.package=="delphes": file.write(' fastsim1->Execute(mySample,myEvent);\n') elif self.main.fastsim.package=="delphesMA5tune": @@ -676,6 +699,10 @@ def WriteSelectionSource(self,main): file.write('#include "SampleAnalyzer/Process/Analyzer/AnalyzerManager.h"\n') file.write('#include "SampleAnalyzer/User/Analyzer/user.h"\n') file.write('#include "SampleAnalyzer/Commons/Service/LogStream.h"\n') + if self.main.superfastsim.isTaggerOn(): + file.write('#include "new_tagger.h"\n') + if self.main.superfastsim.isNewSmearerOn(): + file.write('#include "new_smearer_reco.h"\n') file.write('\n') file.write('// ------------------------------------------' +\ '-----------------------------------\n') @@ -690,44 +717,10 @@ def WriteSelectionSource(self,main): file.close() return True - def WriteSampleAnalyzerMakefile(self,option=""): - - from madanalysis.build.makefile_writer import MakefileWriter - options=MakefileWriter.MakefileOptions() - - # Name of the Makefile - filename = self.path+"/Build/SampleAnalyzer/Makefile" - - # Header - title='User package' - toRemove = [] - - # Options - option.has_commons = True - options.has_process = True - if self.main.archi_info.has_root: - options.has_root_inc = True - options.has_root_lib = True - toRemove.extend(['compilation.log','linking.log','cleanup.log','mrproper.log']) - - # File to compile - cppfiles = package+'/*.cpp' - hfiles = package+'/*.h' - - # Files to produce - isLibrary=True - ProductName='libUserPackage_for_ma5.so' - ProductPath='../../Build/Lib/' - - # write makefile - MakefileWriter.Makefile(filename,title,ProductName,ProductPath,isLibrary,cppfiles,hfiles,options,self.main.archi_info,toRemove) - - # Ok - return True - - - def WriteMakefiles(self,option=""): + def WriteMakefiles(self, option="", **kwargs): + # kwargs: keyword arguments regarding additional mode options such as `ma5_fastjet_mode` + # this will protect Delphes based analyses in PAD from madanalysis.build.makefile_writer import MakefileWriter options=MakefileWriter.MakefileOptions() @@ -740,9 +733,26 @@ def WriteMakefiles(self,option=""): # Options options.has_commons = True options.has_process = True - if self.main.archi_info.has_root: - options.has_root_inc = True - options.has_root_lib = True + # @JACK enable usage of fastjet + # If there are any root files, fastjet clusterer should not run with MA5_FASTJET_MODE Flag + options.ma5_fastjet_mode = self.main.archi_info.has_fastjet and self.main.archi_info.has_fjcontrib + options.has_fastjet_lib = self.main.archi_info.has_fastjet + options.has_fastjet_ma5lib = self.main.archi_info.has_fastjet + # @JACK: fastjet_inc is required to be able to use the FJ files when FJ mode is on + options.has_fastjet_inc = self.main.archi_info.has_fastjet + # @Jack: add substructure library + options.has_substructure = self.main.archi_info.has_fastjet and self.main.archi_info.has_fjcontrib + # @Jack: add HTT library + options.has_heptoptagger = ( + self.main.archi_info.has_fastjet and \ + self.main.archi_info.has_fjcontrib and \ + self.main.archi_info.has_heptoptagger + ) + + options.has_root_inc = self.main.archi_info.has_root + options.has_root_lib = self.main.archi_info.has_root + # @jackaraz: to prevent seg-fault error with delphes + options.has_fastjet_tag = self.main.archi_info.has_root and self.main.archi_info.has_fastjet #options.has_userpackage = True toRemove=['Log/compilation.log','Log/linking.log','Log/cleanup.log','Log/mrproper.log'] @@ -763,7 +773,8 @@ def WriteMakefiles(self,option=""): from madanalysis.build.setup_writer import SetupWriter SetupWriter.WriteSetupFile(True, self.path+'/Build/',self.main.archi_info) SetupWriter.WriteSetupFile(False,self.path+'/Build/',self.main.archi_info) - + #@JACK: Why are we using C-shell this is not necessary anymore. + # Ok return True @@ -803,7 +814,7 @@ def CompileJob(self): # log file name logfile = folder+'/Log/compilation.log' - + # shell command commands = ['make','compile'] @@ -814,29 +825,7 @@ def CompileJob(self): if not result: logging.getLogger('MA5').error('impossible to compile the project. For more details, see the log file:') logging.getLogger('MA5').error(logfile) - - return result - - def MrproperJob(self): - - # folder - folder = self.path+'/Build' - - # log file name - logfile = folder+'/Log/mrproper.log' - - # shell command - commands = ['make','mrproper'] - - # call - result, out = ShellCommand.ExecuteWithLog(commands,logfile,folder) - - # return result - if not result: - logging.getLogger('MA5').error('impossible to clean the project. For more details, see the log file:') - logging.getLogger('MA5').error(logfile) - return result @@ -847,7 +836,7 @@ def MrproperJob(self): # log file name logfile = folder+'/Log/mrproper.log' - + # shell command commands = ['make','mrproper'] @@ -858,10 +847,11 @@ def MrproperJob(self): if not result: logging.getLogger('MA5').error('impossible to clean the project. For more details, see the log file:') logging.getLogger('MA5').error(logfile) - + return result + def LinkJob(self): # folder @@ -869,7 +859,7 @@ def LinkJob(self): # log file name logfile = folder+'/Log/linking.log' - + # shell command commands = ['make','link'] @@ -886,7 +876,7 @@ def LinkJob(self): def WriteHistory(self,history,firstdir): file = open(self.path+"/history.ma5","w") - file.write('set main.currentdir = '+firstdir+'\n') + file.write('set main.currentdir = '+firstdir+'\n') for line in history.history: items = line.split(';') for item in items : @@ -902,7 +892,7 @@ def WriteHistory(self,history,firstdir): else: file.write(item) file.write("\n") - file.close() + file.close() def WriteDatasetList(self,dataset): name=InstanceName.Get(dataset.name) @@ -910,7 +900,7 @@ def WriteDatasetList(self,dataset): for item in dataset: file.write(item) file.write("\n") - file.close() + file.close() def RunJob(self,dataset): @@ -947,8 +937,3 @@ def RunJob(self,dataset): result = ShellCommand.Execute(commands,folder) return result - - - def WriteTagger(self): - # header file - bla diff --git a/madanalysis/IOinterface/library_writer.py b/madanalysis/IOinterface/library_writer.py index eb3ff3ef..6dca5359 100644 --- a/madanalysis/IOinterface/library_writer.py +++ b/madanalysis/IOinterface/library_writer.py @@ -23,15 +23,10 @@ from __future__ import absolute_import -from madanalysis.selection.instance_name import InstanceName from madanalysis.IOinterface.folder_writer import FolderWriter -from madanalysis.IOinterface.job_writer import JobWriter -from string_tools import StringTools from shell_command import ShellCommand import logging -import shutil import os -import subprocess from six.moves import input @@ -126,6 +121,10 @@ def WriteMakefileForInterfaces(self,package): filename = self.path+"/SampleAnalyzer/Test/Makefile_zlib" elif package=='test_fastjet': filename = self.path+"/SampleAnalyzer/Test/Makefile_fastjet" + elif package=='test_substructure': + filename = self.path+"/SampleAnalyzer/Test/Makefile_substructure" + elif package=='test_htt': + filename = self.path+"/SampleAnalyzer/Test/Makefile_htt" elif package=='test_delphes': filename = self.path+"/SampleAnalyzer/Test/Makefile_delphes" elif package=='test_delphesMA5tune': @@ -149,6 +148,10 @@ def WriteMakefileForInterfaces(self,package): title='*zlib-interface* test' elif package=='test_fastjet': title='*fastjet-interface* test' + elif package=='test_substructure': + title='*substructure-interface* test' + elif package=='test_htt': + title='*htt-interface* test' elif package=='test_delphes': title='*delphes-interface* test' elif package=='test_delphesMA5tune': @@ -164,16 +167,79 @@ def WriteMakefileForInterfaces(self,package): options.has_commons=True options.has_fastjet_inc=True options.has_fastjet_lib=True + # @JACK: To be able to use fastjet in Ma5 data structure + options.ma5_fastjet_mode=True toRemove.extend(['compilation_fastjet.log','linking_fastjet.log','cleanup_fastjet.log','mrproper_fastjet.log']) elif package=='test_fastjet': options.has_commons=True options.has_fastjet_ma5lib=True + options.has_fastjet_inc=True # options.has_fastjet_lib=True - toRemove.extend(['compilation_fastjet.log','linking_fastjet.log','cleanup_fastjet.log',\ - 'mrproper_fastjet.log','../Bin/TestFastjet.log']) + toRemove.extend(['compilation_fastjet.log','linking_fastjet.log','cleanup_fastjet.log','mrproper_fastjet.log','../Bin/TestFastjet.log']) + elif package == "substructure": + options.has_commons=True + options.has_fastjet_inc=True + options.has_fastjet_lib=True + # @JACK: To be able to use fastjet in Ma5 data structure + options.ma5_fastjet_mode=True + options.has_fjcontrib = True + options.has_nsubjettiness = True + toRemove.extend( + ['compilation_substructure.log', + 'linking_substructure.log', + 'cleanup_substructure.log', + 'mrproper_substructure.log'] + ) + elif package == "test_substructure": + options.has_commons = True + options.has_fastjet_inc = True + options.has_fastjet_lib = True + options.ma5_fastjet_mode = True + options.has_fastjet_ma5lib = True + options.has_substructure = True + toRemove.extend( + ['compilation_test_substructure.log', + 'linking_test_substructure.log', + 'cleanup_test_substructure.log', + 'mrproper_test_substructure.log'] + ) + elif package == "HEPTopTagger": + options.has_commons=True + options.has_fastjet_inc=True + options.has_fastjet_lib=True + # @JACK: To be able to use fastjet in Ma5 data structure + options.ma5_fastjet_mode=True + options.has_nsubjettiness = True + options.has_substructure = True + toRemove.extend( + ['compilation_heptoptagger.log', + 'linking_heptoptagger.log', + 'cleanup_heptoptagger.log', + 'mrproper_heptoptagger.log'] + ) + elif package == "test_htt": + options.has_commons=True + options.has_fastjet_inc=True + options.has_fastjet_lib=True + # @JACK: To be able to use fastjet in Ma5 data structure + options.ma5_fastjet_mode=True + options.has_fastjet_ma5lib = True + options.has_substructure = True + options.has_heptoptagger = True + toRemove.extend( + ['compilation_test_heptoptagger.log', + 'linking_test_heptoptagger.log', + 'cleanup_test_heptoptagger.log', + 'mrproper_test_heptoptagger.log'] + ) elif package=='configuration': toRemove.extend(['compilation.log','linking.log','cleanup.log','mrproper.log']) elif package=='commons': + # @JACK: This will allow us to dynamically use the FJ libraries in commons + options.ma5_fastjet_mode = self.main.archi_info.has_fastjet + options.has_fastjet_inc = self.main.archi_info.has_fastjet + options.has_fastjet_lib = self.main.archi_info.has_fastjet + # options.has_fastjet_ma5lib = self.main.archi_info.has_fastjet toRemove.extend(['compilation.log','linking.log','cleanup.log','mrproper.log']) elif package=='test_commons': options.has_commons = True @@ -197,6 +263,7 @@ def WriteMakefileForInterfaces(self,package): options.has_root = True options.has_root_inc = True options.has_root_lib = True + options.ma5_fastjet_mode = self.main.archi_info.has_root and self.main.archi_info.has_fastjet toRemove.extend(['compilation_delphes.log','linking_delphes.log',\ 'cleanup_delphes.log','mrproper_delphes.log']) elif package=='test_delphes': @@ -260,6 +327,12 @@ def WriteMakefileForInterfaces(self,package): options.has_zlib_tag = self.main.archi_info.has_zlib options.has_root_tag = self.main.archi_info.has_root options.has_root_ma5lib = self.main.archi_info.has_root + # @JACK: For fastjet to be accessible through ma5 datastructure + options.has_fastjet_inc = self.main.archi_info.has_fastjet + options.has_fastjet_lib = self.main.archi_info.has_fastjet + options.ma5_fastjet_mode = self.main.archi_info.has_fastjet + options.has_substructure = self.main.archi_info.has_fjcontrib and self.main.archi_info.has_fastjet + toRemove.extend(['compilation.log','linking.log','cleanup.log','mrproper.log']) elif package=='test_process': options.has_commons = True @@ -295,6 +368,12 @@ def WriteMakefileForInterfaces(self,package): elif package=='test_fastjet': cppfiles = ['Fastjet/*.cpp'] hfiles = ['Fastjet/*.h'] + elif package=='test_substructure': + cppfiles = ['Substructure/*.cpp'] + hfiles = [] + elif package=='test_htt': + cppfiles = ['HEPTopTagger/*.cpp'] + hfiles = [] elif package=='test_delphes': cppfiles = ['Delphes/*.cpp'] hfiles = ['Delphes/*.h'] @@ -329,6 +408,14 @@ def WriteMakefileForInterfaces(self,package): isLibrary=False ProductName='TestFastjet' ProductPath='../Bin/' + elif package=='test_substructure': + isLibrary=False + ProductName='TestSubstructure' + ProductPath='../Bin/' + elif package=='test_htt': + isLibrary=False + ProductName='TestHEPTopTagger' + ProductPath='../Bin/' elif package=='test_root': isLibrary=False ProductName='TestRoot' @@ -363,18 +450,18 @@ def Compile(self,ncores,package,folder): # log file name if package in ['process','commons','test','configuration']: logfile = folder+'/compilation.log' - elif package in ['test_process','test_commons','test_zlib','test_fastjet',\ - 'test_root','test_delphes','test_delphesMA5tune']: - logfile = folder+'/compilation_'+package[5:]+'.log' + elif package in ['test_process', 'test_commons', 'test_zlib', 'test_fastjet', "test_substructure", "test_htt", + 'test_root', 'test_delphes', 'test_delphesMA5tune']: + logfile = folder + '/compilation_' + package[5:] + '.log' else: logfile = folder+'/compilation_'+package+'.log' # makefile if package in ['process','commons','test','configuration']: makefile = 'Makefile' - elif package in ['test_process','test_commons','test_zlib','test_fastjet',\ - 'test_root','test_delphes','test_delphesMA5tune']: - makefile = 'Makefile_'+package[5:] + elif package in ['test_process', 'test_commons', 'test_zlib', 'test_fastjet', "test_substructure", "test_htt", + 'test_root', 'test_delphes', 'test_delphesMA5tune']: + makefile = 'Makefile_' + package[5:] else: makefile = 'Makefile_'+package @@ -400,8 +487,8 @@ def Link(self,package,folder): # log file name if package in ['process','commons','test','configuration']: logfile = folder+'/linking.log' - elif package in ['test_process','test_commons','test_zlib','test_fastjet',\ - 'test_root','test_delphes','test_delphesMA5tune']: + elif package in ['test_process', 'test_commons', 'test_zlib', 'test_fastjet', "test_substructure", "test_htt", + 'test_root', 'test_delphes', 'test_delphesMA5tune']: logfile = folder+'/linking_'+package[5:]+'.log' else: logfile = folder+'/linking_'+package+'.log' @@ -409,8 +496,8 @@ def Link(self,package,folder): # makefile if package in ['process','commons','test','configuration']: makefile = 'Makefile' - elif package in ['test_process','test_commons','test_zlib','test_fastjet',\ - 'test_root','test_delphes','test_delphesMA5tune']: + elif package in ['test_process', 'test_commons', 'test_zlib', 'test_fastjet', "test_substructure", "test_htt", + 'test_root', 'test_delphes', 'test_delphesMA5tune']: makefile = 'Makefile_'+package[5:] else: makefile = 'Makefile_'+package @@ -434,8 +521,8 @@ def Clean(self,package,folder): # log file name if package in ['process','commons','configuration','test']: logfile = folder+'/cleanup.log' - elif package in ['test_process','test_commons','test_zlib','test_fastjet',\ - 'test_root','test_delphes','test_delphesMA5tune']: + elif package in ['test_process', 'test_commons', 'test_zlib', 'test_fastjet', "test_substructure", "test_htt", + 'test_root', 'test_delphes', 'test_delphesMA5tune']: logfile = folder+'/cleanup_'+package[5:]+'.log' else: logfile = folder+'/cleanup_'+package+'.log' @@ -443,8 +530,8 @@ def Clean(self,package,folder): # makefile if package in ['process','commons','test','configuration']: makefile = 'Makefile' - elif package in ['test_process','test_commons','test_zlib','test_fastjet',\ - 'test_root','test_delphes','test_delphesMA5tune']: + elif package in ['test_process', 'test_commons', 'test_zlib', 'test_fastjet', "test_substructure", "test_htt", + 'test_root', 'test_delphes', 'test_delphesMA5tune']: makefile = 'Makefile_'+package[5:] else: makefile = 'Makefile_'+package @@ -468,8 +555,8 @@ def MrProper(self,package,folder): # log file name if package in ['process','commons','configuration']: logfile = folder+'/mrproper.log' - elif package in ['test_process','test_commons','test_zlib','test_root','test_fastjet',\ - 'test_delphes','test_delphesMA5tune']: + elif package in ['test_process', 'test_commons', 'test_zlib', 'test_root', 'test_fastjet', "test_substructure", + "test_htt", 'test_delphes', 'test_delphesMA5tune']: logfile = folder+'/mrproper_'+package[5:]+'.log' else: logfile = folder+'/mrproper_'+package+'.log' @@ -479,8 +566,8 @@ def MrProper(self,package,folder): # makefile if package in ['process','commons','test','configuration']: makefile = 'Makefile' - elif package in ['test_process','test_commons','test_zlib','test_root','test_fastjet',\ - 'test_delphes','test_delphesMA5tune']: + elif package in ['test_process', 'test_commons', 'test_zlib', 'test_root', 'test_fastjet', "test_substructure", + "test_htt", 'test_delphes', 'test_delphesMA5tune']: makefile = 'Makefile_'+package[5:] else: makefile = 'Makefile_'+package diff --git a/madanalysis/UpdateNotes.txt b/madanalysis/UpdateNotes.txt index 737b7a87..6d657ae5 100644 --- a/madanalysis/UpdateNotes.txt +++ b/madanalysis/UpdateNotes.txt @@ -1,153 +1,152 @@ Update notes for MadAnalysis 5 (in reverse time order) -133 1.10.1 (2021/12/15) ma5team: - Minimum python version requirement has been increased to 3.8. - - Minimum GCC compiler requirement has been increased to `std=c++11` compatible. - - Update in expert mode structure, several new functionalities like filter - functions, region dependent reweigthing, ability to input command line options. - For details [see PR input](#link-PR-here). - -132 1.9 (2021/12/13) ma5team: - Adding support for LLP (also in the SFS) [2112.05163]. - - Particle propagation module [2112.05163]. - - PYHF/simplified likelihood interface. - - TACO methods available. - - Python3 support. - - Connection of the PAD to the MA5 dataverse + reorganisation of how it works. - - Many minor bug fixes. - - Update to newer Delphes/Root versions - -128 1.8 (2020/07/03) ma5team: - New simplified fast simulation (SFS) module for event reconstruction - (arxiv:2006.09387) - - Update of the recasting functionalities to handle SFS detector simulations - - Including extralolations and uncertainties in the CLs extraction module - (arxiv:1910.11418) - - Modification of the structure of the SAF output - - Modification and improvement of the interface with MG5 - - Improvement of the code efficiency (especialyl in the recast mode) - - New analyses added to the PAD - - Various bug fixes including compatibility with recent MACOS versions - -125 1.7 (2019/02/07) ma5team: - Simplification of the multiple PAD management (externalisation) - - Simplification of the multiple delphes management - - Restoring compatibility with the older PAD4MA5tune (root6) - - Upgrading the RecJetFormat class - - Various bug fixes - -122 1.6 (2018/05/04) ma5team: - Finalization of the interface with mg5 - - Two jet collections are now allowed in the expert mode - - Support for multiple signal regions in the normal mode - - Refactorization of the recastig module - - Multiweight support (LHE3, HPEMC3) - - Extension of the LHC analysis database - - Various bug fixes - -116 1.5 (2016/11/14) ma5team: - embedded into MadGraph - - FIFO mode for MadGraph - - No more RecastingTools - - review isolation definitions - - all loggers become logging.getLogger("MA5") - - display error message if not-supported file extension - - improve gzip installation / detection - - protections added for PADMA5tune and delphesMA5tune -> not - compatible with root 6 - - extend the list of recasted analyses - -111 1.4 (2016/07/20) ma5team: - Root is now optional and Pyroot is not a requirement anymore - - matplotlib can be used for the histograms - - Improvement of the plot layout - - Improvement of the recasting module + PAD - - Developments for the madGraph5 interface - - A few bug fixes - -109 1.3. (2016/03/01) ma5team: - New structure for the PAD; automated recasting methods - - Compatiblity with delphes 3.3 - - Several system-dependent bug fixes - - Bug fixes: selections, report writer - - Development: new observables, better debugging mode, Delphes3 handling - pythia8 compatiblitity for the merging plots - - 91 1.2 (2015/10/28) ma5team: - Bug fixes (LHE writer, HepMC reader, merging plots, etc.) - - PAD features - - 82 1.1.11 (2014/07/17) ma5team: - new structure for the detection of the user system - - new structure for installing the external packages - - the user can choose which package to use via the user_isntall.dat file - - first steps for the externalization of extra modules such as root, numpy, etc... - - first steps for a dedicated interface to root, gnuplot and matplotlib - - official release of the MA5Tune for Delphes - - interface to the recasting package - - many bug fixes - - improved portability with mac OS - - 81 1.1.10 (2014/05/17) ma5team: - new compilation procedure for library and job - - adding job test to check the compilation procedure - - adding restart command and possibility to restart MA5 after - the installation of a package - - adding new simulation detector package = tuned release of Delphes - - compatible with the "new" STDHEP format - - new structure for plots/cuts in the expert mode for - recasting analysis - - revisiting physics services - - adding Transverse Observable services with MT2, MTW variables - -80 1.1.9 (2013/10/28) ma5team: - adding Delphes interface + CMS/ATLAS cards - - adding Delphes cards including pile-up - - the electric charge is now an integer at the reco level - - modifying the default range for the sdphi and dphi observables - - wrong normalization of the LHE file constructed by madgraph5 once - pythia6 has been run (bug 1183739) - - compatibility with mac improved - - Fixing the computation of observables with differences - -84 1.1.8 (2013/08/06) ma5team: - installing Delphes3 from MadAnalysis5 console : install delphes - - reading default Delphes3 ROOT file - - identifying generator or shower program used when reading a sample - - improving the compatibility with samples produced by HERWIG - - improving the simplified LHE output (mother-daughter relations - between reco objects and MC particles) - - adding MT_MET observable required for computing the W transverse mass - - fixing a bug related to the reading of the MET in simplified LHE file - - fixing a bug related to histogram normalization - - fixing minor other bugs - -60 1.1.7 (2013/06/13) ma5team: - LHCO output - - Compatibility with pythia-8 output - - Improvement of the jet clustering / object identification - - Few bug fixes - - Photons added in the reco mode - -54 1.1.6 (2013/05/17) ma5team: - Many bug fixes (special thanks to Adam Alloul and Jose Ruiz). - - Simplified LHE output added, LHCO writer at the beta level. - - Clustering and b, c and tau (mis)ident. improved. - - zlib updated to the most recent version. - - New version of the expert mode. - - Adding the photons in the reco mode. - - New structure for the working directory. - - Adding alpha_T in the observable lists. - - Screen output improved. - - Event weights included in the HEPmc reader. - -737 1.1.5 (2012/11/28) ma5team: Compilation bug fixes. - -729 1.1.4 (2012/11/28) ma5team: New treatment of the plots. - New structure for the generated directory. - New routines to check the integrity of StdHep files. - Layout improvements (screen output, HTML, TeX). - Possiblity to write the history in a file. - Several bug fixes - -666 1.1.3 (2012/11/10) ma5team: MA5 can now use fastjet if installed on the system (usr/lib, ...) - Positive and negative weighted events supported. - New layout for the HTML report. - Simplified submission/resubmission procedure (submit and resumbmit). - Simplification of the usage of the command 'open'. - No more 'generate_xxx' commands (included now in 'submit'/'resubmit'). - Checks at startup if pdflatex, latex and dvipdf are installed. - -591 1.1.0 (2012/09/29) ma5team: Official release of version 1.1.0 - - Interface with FastJet - - Jet clustering from HAD-level events - - Merging check plots - -471 1.0.0 (2012/06/08) ma5team: Official release of version 1.0.0 - +1.10.2 (2021/12/15) ma5team: - Minimum python version requirement has been increased to 3.8. + - Minimum GCC compiler requirement has been increased to `std=c++11` compatible. + - Update in the structure of the expert mode: new functionalities like filter + functions, region dependent re-weigthing, ability to input command line options. + For details [see PR input](#link-PR-here). + +1.9 (2021/12/13) ma5team: - Adding support for LLP (also in the SFS) [2112.05163]. + - Particle propagation module [2112.05163]. + - PYHF/simplified likelihood interface. + - TACO methods available. + - Python3 support. + - Connection of the PAD to the MA5 dataverse + reorganisation of how it works. + - Many minor bug fixes. + - Update to newer Delphes/Root versions + +1.8 (2020/07/03) ma5team: - New simplified fast simulation (SFS) module for event reconstruction + (arxiv:2006.09387) + - Update of the recasting functionalities to handle SFS detector simulations + - Including extralolations and uncertainties in the CLs extraction module + (arxiv:1910.11418) + - Modification of the structure of the SAF output + - Modification and improvement of the interface with MG5 + - Improvement of the code efficiency (especialyl in the recast mode) + - New analyses added to the PAD + - Various bug fixes including compatibility with recent MACOS versions + +1.7 (2019/02/07) ma5team: - Simplification of the multiple PAD management (externalisation) + - Simplification of the multiple delphes management + - Restoring compatibility with the older PAD4MA5tune (root6) + - Upgrading the RecJetFormat class + - Various bug fixes + +1.6 (2018/05/04) ma5team: - Finalization of the interface with mg5 + - Two jet collections are now allowed in the expert mode + - Support for multiple signal regions in the normal mode + - Refactorization of the recastig module + - Multiweight support (LHE3, HPEMC3) + - Extension of the LHC analysis database + - Various bug fixes + +1.5 (2016/11/14) ma5team: - embedded into MadGraph + - FIFO mode for MadGraph + - No more RecastingTools + - review isolation definitions + - all loggers become logging.getLogger("MA5") + - display error message if not-supported file extension + - improve gzip installation / detection + - protections added for PADMA5tune and delphesMA5tune -> not + compatible with root 6 + - extend the list of recasted analyses + +1.4 (2016/07/20) ma5team: - Root is now optional and Pyroot is not a requirement anymore + - matplotlib can be used for the histograms + - Improvement of the plot layout + - Improvement of the recasting module + PAD + - Developments for the madGraph5 interface + - A few bug fixes + +1.3. (2016/03/01) ma5team: - New structure for the PAD; automated recasting methods + - Compatiblity with delphes 3.3 + - Several system-dependent bug fixes + - Bug fixes: selections, report writer + - Development: new observables, better debugging mode, Delphes3 handling + pythia8 compatiblitity for the merging plots + +1.2 (2015/10/28) ma5team: - Bug fixes (LHE writer, HepMC reader, merging plots, etc.) + - PAD features + +1.1.11 (2014/07/17) ma5team: - new structure for the detection of the user system + - new structure for installing the external packages + - the user can choose which package to use via the user_isntall.dat file + - first steps for the externalization of extra modules such as root, numpy, etc... + - first steps for a dedicated interface to root, gnuplot and matplotlib + - official release of the MA5Tune for Delphes + - interface to the recasting package + - many bug fixes + - improved portability with mac OS + +1.1.10 (2014/05/17) ma5team: - new compilation procedure for library and job + - adding job test to check the compilation procedure + - adding restart command and possibility to restart MA5 after + the installation of a package + - adding new simulation detector package = tuned release of Delphes + - compatible with the "new" STDHEP format + - new structure for plots/cuts in the expert mode for + recasting analysis + - revisiting physics services + - adding Transverse Observable services with MT2, MTW variables + +1.1.9 (2013/10/28) ma5team: - adding Delphes interface + CMS/ATLAS cards + - adding Delphes cards including pile-up + - the electric charge is now an integer at the reco level + - modifying the default range for the sdphi and dphi observables + - wrong normalization of the LHE file constructed by madgraph5 once + pythia6 has been run (bug 1183739) + - compatibility with mac improved + - Fixing the computation of observables with differences + +1.1.8 (2013/08/06) ma5team: - installing Delphes3 from MadAnalysis5 console : install delphes + - reading default Delphes3 ROOT file + - identifying generator or shower program used when reading a sample + - improving the compatibility with samples produced by HERWIG + - improving the simplified LHE output (mother-daughter relations + between reco objects and MC particles) + - adding MT_MET observable required for computing the W transverse mass + - fixing a bug related to the reading of the MET in simplified LHE file + - fixing a bug related to histogram normalization + - fixing minor other bugs + +1.1.7 (2013/06/13) ma5team: - LHCO output + - Compatibility with pythia-8 output + - Improvement of the jet clustering / object identification + - Few bug fixes + - Photons added in the reco mode + +1.1.6 (2013/05/17) ma5team: - Many bug fixes (special thanks to Adam Alloul and Jose Ruiz). + - Simplified LHE output added, LHCO writer at the beta level. + - Clustering and b, c and tau (mis)ident. improved. + - zlib updated to the most recent version. + - New version of the expert mode. + - Adding the photons in the reco mode. + - New structure for the working directory. + - Adding alpha_T in the observable lists. + - Screen output improved. + - Event weights included in the HEPmc reader. + +1.1.5 (2012/11/28) ma5team: Compilation bug fixes. + +1.1.4 (2012/11/28) ma5team: New treatment of the plots. + New structure for the generated directory. + New routines to check the integrity of StdHep files. + Layout improvements (screen output, HTML, TeX). + Possiblity to write the history in a file. + Several bug fixes + +1.1.3 (2012/11/10) ma5team: MA5 can now use fastjet if installed on the system (usr/lib, ...) + Positive and negative weighted events supported. + New layout for the HTML report. + Simplified submission/resubmission procedure (submit and resumbmit). + Simplification of the usage of the command 'open'. + No more 'generate_xxx' commands (included now in 'submit'/'resubmit'). + Checks at startup if pdflatex, latex and dvipdf are installed. + +1.1.0 (2012/09/29) ma5team: Official release of version 1.1.0 + - Interface with FastJet + - Jet clustering from HAD-level events + - Merging check plots + +1.0.0 (2012/06/08) ma5team: Official release of version 1.0.0 diff --git a/madanalysis/build/makefile_writer.py b/madanalysis/build/makefile_writer.py index 1c1513ba..1790d809 100644 --- a/madanalysis/build/makefile_writer.py +++ b/madanalysis/build/makefile_writer.py @@ -23,10 +23,11 @@ from __future__ import absolute_import + import logging -from shell_command import ShellCommand -from string_tools import StringTools + from six.moves import range +from string_tools import StringTools class MakefileWriter(): @@ -165,6 +166,13 @@ def __init__(self): self.has_commons = False self.has_process = False self.has_fastjet_tag = False + # @JACK: cant use FASTJET_USE tag, it clashes with ROOT + self.ma5_fastjet_mode = False + self.has_fjcontrib = False + self.has_substructure = False + self.has_heptoptagger = False + self.has_nsubjettiness = False + self.has_delphes_tag = False self.has_delphesMA5tune_tag = False self.has_root_tag = False @@ -188,10 +196,13 @@ def __init__(self): self.has_root_ma5lib = False + @staticmethod - def Makefile(MakefileName,title,ProductName,ProductPath,isLibrary,cppfiles,hfiles,options,archi_info,toRemove,moreIncludes=[]): + def Makefile( + MakefileName, title, ProductName, ProductPath, isLibrary, cppfiles, hfiles, + options, archi_info, toRemove, moreIncludes = [] + ): - import os # Open the Makefile try: file = open(MakefileName,"w") @@ -218,7 +229,7 @@ def Makefile(MakefileName,title,ProductName,ProductPath,isLibrary,cppfiles,hfile # - general cxxflags=[] - cxxflags.extend(['-Wall','-std=c++11','-O3','-fPIC', '-I$(MA5_BASE)/tools/']) # general + cxxflags.extend(['-Wall', '-std=c++11', '-O3', '-fPIC', '-I$(MA5_BASE)/tools/']) # general file.write('CXXFLAGS = '+' '.join(cxxflags)+'\n') for item in moreIncludes: file.write('CXXFLAGS += '+' -I'+item+'\n') @@ -317,6 +328,10 @@ def Makefile(MakefileName,title,ProductName,ProductPath,isLibrary,cppfiles,hfile cxxflags.extend(['-DROOT_USE']) if options.has_fastjet_tag: cxxflags.extend(['-DFASTJET_USE']) + if options.ma5_fastjet_mode: + # @JACK: This flag enables usage of certain modules in SampleAnalyzer which + # depends on availablity of FastJet library. + cxxflags.extend(["$(FASTJET_FLAG)"]) if options.has_zlib_tag: cxxflags.extend(['-DZIP_USE']) if options.has_delphes_tag: @@ -353,7 +368,6 @@ def Makefile(MakefileName,title,ProductName,ProductPath,isLibrary,cppfiles,hfile if options.has_zlib_ma5lib: libs.extend(['-lzlib_for_ma5']) if options.has_zlib_lib: -# libs.extend(['-L'+archi_info.zlib_lib_path,'-lz']) libs.extend(['-lz']) file.write('LIBFLAGS += '+' '.join(libs)+'\n') @@ -376,10 +390,18 @@ def Makefile(MakefileName,title,ProductName,ProductPath,isLibrary,cppfiles,hfile if options.has_fastjet_ma5lib: libs.extend(['-lfastjet_for_ma5']) if options.has_fastjet_lib: -# libs.extend(['$(shell fastjet-config --libs --plugins)']) # --rpath=no)']) - libs.extend(['$(shell $(MA5_BASE)/tools/SampleAnalyzer/ExternalSymLink/Bin/fastjet-config '+\ - '--libs --plugins)']) # --rpath=no)']) + libs.extend(['$(shell $(MA5_BASE)/tools/SampleAnalyzer/ExternalSymLink/Bin/fastjet-config --libs --plugins)']) file.write('LIBFLAGS += '+' '.join(libs)+'\n') + libs=[] + if options.has_fjcontrib: + # Add fjcontrib libraries + libs.extend(["-lRecursiveTools"]) # SoftDrop + libs.extend(["-lVariableR"]) # VariableR + libs.extend(["-lEnergyCorrelator"]) # -lEnergyCorrelator + if options.has_nsubjettiness: + libs.extend(["-lNsubjettiness"]) # Nsubjettiness + if options.has_nsubjettiness or options.has_fjcontrib: + file.write('LIBFLAGS += '+' '.join(libs)+'\n') # - delphes if options.has_delphes_ma5lib or options.has_delphes_lib: @@ -387,7 +409,6 @@ def Makefile(MakefileName,title,ProductName,ProductPath,isLibrary,cppfiles,hfile if options.has_delphes_ma5lib: libs.extend(['-ldelphes_for_ma5']) if options.has_delphes_lib: -# libs.extend(['-L'+archi_info.delphes_lib_paths[0],'-lDelphes']) libs.extend(['-lDelphes']) file.write('LIBFLAGS += '+' '.join(libs)+'\n') @@ -397,10 +418,17 @@ def Makefile(MakefileName,title,ProductName,ProductPath,isLibrary,cppfiles,hfile if options.has_delphesMA5tune_ma5lib: libs.extend(['-ldelphesMA5tune_for_ma5']) if options.has_delphesMA5tune_lib: -# libs.extend(['-L'+archi_info.delphesMA5tune_lib_paths[0],'-lDelphesMA5tune']) libs.extend(['-lDelphesMA5tune']) file.write('LIBFLAGS += '+' '.join(libs)+'\n') + # Substructure module + if options.has_substructure: + file.write('LIBFLAGS += -lsubstructure_for_ma5\n') + + # HEPTopTagger module + if options.has_heptoptagger: + file.write('LIBFLAGS += -lHEPTopTagger_for_ma5\n') + # - Commons if options.has_commons: libs=[] @@ -435,6 +463,10 @@ def Makefile(MakefileName,title,ProductName,ProductPath,isLibrary,cppfiles,hfile libs.append('$(MA5_BASE)/tools/SampleAnalyzer/Lib/libdelphesMA5tune_for_ma5.so') if options.has_fastjet_ma5lib: libs.append('$(MA5_BASE)/tools/SampleAnalyzer/Lib/libfastjet_for_ma5.so') + if options.has_substructure: + libs.append('$(MA5_BASE)/tools/SampleAnalyzer/Lib/libsubstructure_for_ma5.so') + if options.has_heptoptagger: + libs.append('$(MA5_BASE)/tools/SampleAnalyzer/Lib/libHEPTopTagger_for_ma5.so') if len(libs)!=0: file.write('# Requirements to check before building\n') for ind in range(0,len(libs)): diff --git a/madanalysis/build/setup_writer.py b/madanalysis/build/setup_writer.py index a40a2a63..2d9baffe 100644 --- a/madanalysis/build/setup_writer.py +++ b/madanalysis/build/setup_writer.py @@ -1,24 +1,24 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: -# +# # This file is part of MadAnalysis 5. # Official website: -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see -# +# ################################################################################ @@ -28,56 +28,56 @@ from six.moves import range -class SetupWriter(): - - +class SetupWriter: @staticmethod - def OrderPath(paths1,middle,paths2,ma5dir): - all=[] - allsh=[] - allcsh=[] + def OrderPath(paths1, middle, paths2, ma5dir): + all = [] + allsh = [] + allcsh = [] for item in paths1: - path=item.replace(ma5dir,'$MA5_BASE') + path = item.replace(ma5dir, "$MA5_BASE") all.append(path) allsh.append(path) allcsh.append(path) allsh.append(middle) - allcsh.append('"'+middle+'"') + allcsh.append('"' + middle + '"') for item in paths2: - path=item.replace(ma5dir,'$MA5_BASE') + path = item.replace(ma5dir, "$MA5_BASE") all.append(path) allsh.append(path) allcsh.append(path) return all, allsh, allcsh - @staticmethod - def WriteSetupFile(bash,path,archi_info): + def WriteSetupFile(bash, path, archi_info): # Variable to check at the end - toCheck=[] + toCheck = [] # Opening file in write-only mode import os + if bash: - filename = os.path.normpath(path+"/setup.sh") + filename = os.path.normpath(path + "/setup.sh") else: - filename = os.path.normpath(path+"/setup.csh") + filename = os.path.normpath(path + "/setup.csh") try: - file = open(filename,"w") + file = open(filename, "w") except: - logging.getLogger('MA5').error('Impossible to create the file "' + filename +'"') + logging.getLogger("MA5").error( + 'Impossible to create the file "' + filename + '"' + ) return False # Calling the good shell if bash: - file.write('#!/bin/sh\n') + file.write("#!/bin/sh\n") else: - file.write('#!/bin/csh -f\n') - file.write('\n') + file.write("#!/bin/csh -f\n") + file.write("\n") # Defining colours - file.write('# Defining colours for shell\n') + file.write("# Defining colours for shell\n") if bash: file.write('GREEN="\\\\033[1;32m"\n') file.write('RED="\\\\033[1;31m"\n') @@ -85,10 +85,64 @@ def WriteSetupFile(bash,path,archi_info): file.write('BLUE="\\\\033[1;34m"\n') file.write('YELLOW="\\\\033[1;33m"\n') file.write('CYAN="\\\\033[1;36m"\n') - file.write('NORMAL="\\\\033[0;39m"\n') + file.write('NORMAL="\\\\033[0;39m"\n\n') # using ' ' could be more convenient to code # but in this case, the colour code are interpreted # by the linux command 'more' + + # @jackaraz: by default fastjet flag should be set otherwise recjetformat complains + + # file.write('export WITH_FASTJET="0"\n') + # file.write('export WITH_DELPHES="0"\n') + file.write('export FASTJET_FLAG="-DMA5_FASTJET_MODE"\n') + # file.write('user=" "\n\n') + + # file.write('function usage() {\n') + # file.write(' echo -e "Usage: source setup.sh [options]"\n') + # file.write(' echo -e " -h OR --help : Prints this very useful text."\n') + # file.write(' echo -e " --with-fastjet : Enables the usage of FastJet interface within the analysis."\n') + # file.write(' echo -e " --with-delphes : Enables the usage of Delphes interface within the analysis."\n') + # file.write('}\n\n') + + # file.write('for user in "$@"\n') + # file.write('do\n') + # file.write(' if [[ $user == "--with-fastjet" ]]\n') + # file.write(' then\n') + # file.write(' export WITH_FASTJET="1"\n') + # file.write(' elif [[ $user == "--with-delphes" ]]\n') + # file.write(' then\n') + # file.write(' export WITH_DELPHES="1"\n') + # file.write(' elif [[ $user == "-h" ]] || [[ $user == "--help" ]]\n') + # file.write(' then\n') + # file.write(' usage\n') + # file.write(' return 0\n') + # file.write(' else\n') + # file.write(' echo -e $RED"ERROR: Invalid commandline option."\n') + # file.write(' usage\n') + # file.write(' echo -e $NORMAL\n') + # file.write(' return 1\n') + # file.write(' fi\n') + # file.write('done\n\n') + + # file.write('if [[ $WITH_FASTJET -eq "1" ]] && [[ $WITH_DELPHES -eq "1" ]]\n') + # file.write('then\n') + # file.write(' echo -e $RED"ERROR: FastJet and Delphes cannot be executed within the same analysis."$NORMAL\n') + # file.write(' return 1\n') + # file.write('fi\n\n') + + # file.write('if [[ $WITH_FASTJET -eq "1" ]]\n') + # file.write('then\n') + # file.write(' export FASTJET_FLAG="-DMA5_FASTJET_MODE"\n') + # file.write(' echo -e $BLUE" * The SFS-FastJet mode has been initiated."$NORMAL\n') + # file.write('fi\n\n') + + # file.write('if [[ $WITH_DELPHES -eq "1" ]] || [[ $WITH_FASTJET -eq "0" ]]\n') + # file.write('then\n') + # file.write(' echo -e $BLUE" * Tge SFS-FastJet mode has been turned off."\n') + # file.write(' usage\n') + # file.write(' echo -e $NORMAL\n') + # file.write('fi\n\n') + else: file.write('set GREEN = "\\033[1;32m"\n') file.write('set RED = "\\033[1;31m"\n') @@ -97,220 +151,157 @@ def WriteSetupFile(bash,path,archi_info): file.write('set YELLOW = "\\033[1;33m"\n') file.write('set CYAN = "\\033[1;36m"\n') file.write('set NORMAL = "\\033[0;39m"\n') - file.write('\n') + file.write('setenv FASTJET_FLAG "-DMA5_FASTJET_MODE"\n') + file.write("\n") # Treating ma5dir - ma5dir=archi_info.ma5dir - if ma5dir.endswith('/'): - ma5dir=ma5dir[:-1] + ma5dir = archi_info.ma5dir + if ma5dir.endswith("/"): + ma5dir = ma5dir[:-1] # Configuring PATH environment variable - file.write('# Configuring MA5 environment variable\n') + file.write("# Configuring MA5 environment variable\n") if bash: - file.write('export MA5_BASE=' + (ma5dir)+'\n') + file.write("export MA5_BASE=" + (ma5dir) + "\n") else: - file.write('setenv MA5_BASE ' + (ma5dir)+'\n') - toCheck.append('MA5_BASE') - file.write('\n') + file.write("setenv MA5_BASE " + (ma5dir) + "\n") + toCheck.append("MA5_BASE") + file.write("\n") # Treating PATH - toPATH, toPATHsh, toPATHcsh = SetupWriter.OrderPath(archi_info.toPATH1,\ - '$PATH',archi_info.toPATH2,\ - ma5dir) - toLDPATH, toLDPATHsh, toLDPATHcsh = SetupWriter.OrderPath(archi_info.toLDPATH1,\ - '$LD_LIBRARY_PATH',\ - archi_info.toLDPATH2,ma5dir) - toDYLDPATH, toDYLDPATHsh, toDYLDPATHcsh = SetupWriter.OrderPath(archi_info.toLDPATH1,\ - '$DYLD_LIBRARY_PATH',\ - archi_info.toLDPATH2,ma5dir) - + toPATH, toPATHsh, toPATHcsh = SetupWriter.OrderPath( + archi_info.toPATH1, "$PATH", archi_info.toPATH2, ma5dir + ) + toLDPATH, toLDPATHsh, toLDPATHcsh = SetupWriter.OrderPath( + archi_info.toLDPATH1, "$LD_LIBRARY_PATH", archi_info.toLDPATH2, ma5dir + ) + toDYLDPATH, toDYLDPATHsh, toDYLDPATHcsh = SetupWriter.OrderPath( + archi_info.toLDPATH1, "$DYLD_LIBRARY_PATH", archi_info.toLDPATH2, ma5dir + ) + # Configuring PATH environment variable - if len(toPATH)!=0: - file.write('# Configuring PATH environment variable\n') + if len(toPATH) != 0: + file.write("# Configuring PATH environment variable\n") if bash: - file.write('if [ $PATH ]; then\n') - file.write('export PATH='+(':'.join(toPATHsh))+'\n') - file.write('else\n') - file.write('export PATH='+(':'.join(toPATH))+'\n') - file.write('fi\n') + file.write("if [ $PATH ]; then\n") + file.write(" export PATH=" + (":".join(toPATHsh)) + "\n") + file.write("else\n") + file.write(" export PATH=" + (":".join(toPATH)) + "\n") + file.write("fi\n") else: - file.write('if ( $?PATH ) then\n') - file.write('setenv PATH '+(':'.join(toPATHcsh))+'\n') - file.write('else\n') - file.write('setenv PATH '+(':'.join(toPATH))+'\n') - file.write('endif\n') - toCheck.append('PATH') - file.write('\n') + file.write("if ( $?PATH ) then\n") + file.write(" setenv PATH " + (":".join(toPATHcsh)) + "\n") + file.write("else\n") + file.write(" setenv PATH " + (":".join(toPATH)) + "\n") + file.write("endif\n") + toCheck.append("PATH") + file.write("\n") + + if len(toLDPATH) != 0: - if len(toLDPATH)!=0: - # Configuring LD_LIBRARY_PATH environment variable - file.write('# Configuring LD_LIBRARY_PATH environment variable\n') + file.write("# Configuring LD_LIBRARY_PATH environment variable\n") if bash: - file.write('if [ $LD_LIBRARY_PATH ]; then\n') - file.write('export LD_LIBRARY_PATH='+(':'.join(toLDPATHsh))+'\n') - file.write('else\n') - file.write('export LD_LIBRARY_PATH='+(':'.join(toLDPATH))+'\n') - file.write('fi\n') + file.write("if [ $LD_LIBRARY_PATH ]; then\n") + file.write(" export LD_LIBRARY_PATH=" + (":".join(toLDPATHsh)) + "\n") + file.write("else\n") + file.write(" export LD_LIBRARY_PATH=" + (":".join(toLDPATH)) + "\n") + file.write("fi\n") else: - file.write('if ( $?LD_LIBRARY_PATH ) then\n') - file.write('setenv LD_LIBRARY_PATH '+(':'.join(toLDPATHcsh))+'\n') - file.write('else\n') - file.write('setenv LD_LIBRARY_PATH '+(':'.join(toLDPATH))+'\n') - file.write('endif\n') - toCheck.append('LD_LIBRARY_PATH') - file.write('\n') + file.write("if ( $?LD_LIBRARY_PATH ) then\n") + file.write(" setenv LD_LIBRARY_PATH " + (":".join(toLDPATHcsh)) + "\n") + file.write("else\n") + file.write(" setenv LD_LIBRARY_PATH " + (":".join(toLDPATH)) + "\n") + file.write("endif\n") + toCheck.append("LD_LIBRARY_PATH") + file.write("\n") # Configuring LIBRARY_PATH environment variable - #file.write('# Configuring LIBRARY_PATH environment variable\n') - #if bash: + # file.write('# Configuring LIBRARY_PATH environment variable\n') + # if bash: # file.write('export LIBRARY_PATH=' + (os.environ['LD_LIBRARY_PATH'])+'\n') - #else: + # else: # file.write('setenv LIBRARY_PATH ' + (os.environ['LD_LIBRARY_PATH'])+'\n') - #file.write('\n') + # file.write('\n') # Configuring DYLD_LIBRARY_PATH environment variable if archi_info.isMac: - file.write('# Configuring DYLD_LIBRARY_PATH environment variable\n') + file.write("# Configuring DYLD_LIBRARY_PATH environment variable\n") if bash: - file.write('if [ $DYLD_LIBRARY_PATH ]; then\n') - file.write('export DYLD_LIBRARY_PATH='+ (':'.join(toDYLDPATHsh))+'\n') - file.write('else\n') - file.write('export DYLD_LIBRARY_PATH='+ (':'.join(toLDPATH))+'\n') - file.write('fi\n') + file.write("if [ $DYLD_LIBRARY_PATH ]; then\n") + file.write( + " export DYLD_LIBRARY_PATH=" + (":".join(toDYLDPATHsh)) + "\n" + ) + file.write("else\n") + file.write( + " export DYLD_LIBRARY_PATH=" + (":".join(toLDPATH)) + "\n" + ) + file.write("fi\n") else: - file.write('if ( $?DYLD_LIBRARY_PATH ) then\n') - file.write('setenv DYLD_LIBRARY_PATH '+(':'.join(toDYLDPATHcsh))+'\n') - file.write('else\n') - file.write('setenv DYLD_LIBRARY_PATH '+(':'.join(toLDPATH))+'\n') - file.write('endif\n') - toCheck.append('DYLD_LIBRARY_PATH') - file.write('\n') + file.write("if ( $?DYLD_LIBRARY_PATH ) then\n") + file.write( + " setenv DYLD_LIBRARY_PATH " + (":".join(toDYLDPATHcsh)) + "\n" + ) + file.write("else\n") + file.write( + " setenv DYLD_LIBRARY_PATH " + (":".join(toLDPATH)) + "\n" + ) + file.write("endif\n") + toCheck.append("DYLD_LIBRARY_PATH") + file.write("\n") # Configuring CPLUS_INCLUDE_PATH environment variable - #file.write('# Configuring CPLUS_INCLUDE_PATH environment variable\n') - #if bash: + # file.write('# Configuring CPLUS_INCLUDE_PATH environment variable\n') + # if bash: # file.write('export CPLUS_INCLUDE_PATH=' + (os.environ['CPLUS_INCLUDE_PATH'])+'\n') - #else: + # else: # file.write('setenv CPLUS_INCLUDE_PATH ' + (os.environ['CPLUS_INCLUDE_PATH'])+'\n') - #file.write('\n') + # file.write('\n') # Checking that all environment variables are defined - file.write('# Checking that all environment variables are defined\n') - if bash: - file.write('if [[ ') - for ind in range(0,len(toCheck)): - if ind!=0: - file.write(' && ') - file.write('$'+toCheck[ind]) - file.write(' ]]; then\n') - file.write('echo -e $YELLOW"'+StringTools.Fill('-',56)+'"\n') - file.write('echo -e "'+StringTools.Center('Your environment is properly configured for MA5',56)+'"\n') - file.write('echo -e "'+StringTools.Fill('-',56)+'"$NORMAL\n') - file.write('fi\n') - else: - file.write('if ( ') - for ind in range(0,len(toCheck)): - if ind!=0: - file.write(' && ') - file.write('$?'+toCheck[ind]) - file.write(' ) then\n') - file.write('echo $YELLOW"'+StringTools.Fill('-',56)+'"\n') - file.write('echo "'+StringTools.Center('Your environment is properly configured for MA5',56)+'"\n') - file.write('echo "'+StringTools.Fill('-',56)+'"$NORMAL\n') - file.write('endif\n') - - # Closing the file - try: - file.close() - except: - logging.getLogger('MA5').error('Impossible to close the file "'+filename+'"') - return False - - return True - - - @staticmethod - def WriteSetupFileForJob(bash,path,archi_info): - - # Variable to check at the end - toCheck=[] - - # Opening file in write-only mode - import os - if bash: - filename = os.path.normpath(path+"/setup.sh") - else: - filename = os.path.normpath(path+"/setup.csh") - try: - file = open(filename,"w") - except: - logging.getLogger('MA5').error('Impossible to create the file "' + filename +'"') - return False - - # Calling the good shell + file.write("# Checking that all environment variables are defined\n") if bash: - file.write('#!/bin/sh\n') + file.write("if [[ ") + for ind in range(0, len(toCheck)): + if ind != 0: + file.write(" && ") + file.write("$" + toCheck[ind]) + file.write(" ]]; then\n") + file.write(' echo -e $YELLOW"' + StringTools.Fill("-", 56) + '"\n') + file.write( + ' echo -e "' + + StringTools.Center( + "Your environment is properly configured for MA5", 56 + ) + + '"\n' + ) + file.write(' echo -e "' + StringTools.Fill("-", 56) + '"$NORMAL\n') + file.write("fi\n") else: - file.write('#!/bin/csh -f\n') - file.write('\n') - - # Defining colours - file.write('# Defining colours for shell\n') - if bash: - file.write('GREEN="\\\\033[1;32m"\n') - file.write('RED="\\\\033[1;31m"\n') - file.write('PINK="\\\\033[1;35m"\n') - file.write('BLUE="\\\\033[1;34m"\n') - file.write('YELLOW="\\\\033[1;33m"\n') - file.write('CYAN="\\\\033[1;36m"\n') - file.write('NORMAL="\\\\033[0;39m"\n') - # using ' ' could be more convenient to code - # but in this case, the colour code are interpreted - # by the linux command 'more' - else: - file.write('set GREEN = "\\033[1;32m"\n') - file.write('set RED = "\\033[1;31m"\n') - file.write('set PINK = "\\033[1;35m"\n') - file.write('set BLUE = "\\033[1;34m"\n') - file.write('set YELLOW = "\\033[1;33m"\n') - file.write('set CYAN = "\\033[1;36m"\n') - file.write('set NORMAL = "\\033[0;39m"\n') - file.write('\n') - - # Treating ma5dir - ma5dir=archi_info.ma5dir - if ma5dir.endswith('/'): - ma5dir=ma5dir[:-1] - - # Configuring PATH environment variable - file.write('# Configuring MA5 environment variable\n') - if bash: - file.write('export MA5_BASE=' + (ma5dir)+'\n') - else: - file.write('setenv MA5_BASE ' + (ma5dir)+'\n') - toCheck.append('MA5_BASE') - file.write('\n') - - # Launching MadAnalysis with empty script - file.write('# Launching MA5 to check if the libraries need to be rebuild\n') - file.write('$MA5_BASE/bin/ma5 --script $MA5_BASE/madanalysis/input/init.ma5\n') - file.write('\n') - - # Loading the SampleAnalyzer setup files - file.write('# Loading the setup files\n') - if bash: - file.write('source $MA5_BASE/tools/SampleAnalyzer/setup.sh\n') - else: - file.write('source $MA5_BASE/tools/SampleAnalyzer/setup.csh\n') + file.write("if ( ") + for ind in range(0, len(toCheck)): + if ind != 0: + file.write(" && ") + file.write("$?" + toCheck[ind]) + file.write(" ) then\n") + file.write(' printf $YELLOW"' + StringTools.Fill("-", 56) + '"$NORMAL\n') + file.write( + ' printf $YELLOW"' + + StringTools.Center( + "Your environment is properly configured for MA5", 56 + ) + + '"$NORMAL\n' + ) + file.write(' printf $YELLOW"' + StringTools.Fill("-", 56) + '"$NORMAL\n') + file.write("endif\n") # Closing the file try: file.close() except: - logging.getLogger('MA5').error('Impossible to close the file "'+filename+'"') + logging.getLogger("MA5").error( + 'Impossible to close the file "' + filename + '"' + ) return False return True - - diff --git a/madanalysis/configuration/beauty_identification.py b/madanalysis/configuration/beauty_identification.py index b15fca16..71da4925 100644 --- a/madanalysis/configuration/beauty_identification.py +++ b/madanalysis/configuration/beauty_identification.py @@ -2,186 +2,122 @@ # # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: -# +# # This file is part of MadAnalysis 5. # Official website: -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see -# +# ################################################################################ from __future__ import absolute_import import logging -class BeautyIdentification(): + + +class BeautyIdentification: default_matching_dr = 0.5 - default_exclusive = True - default_efficiency = 1. - default_misid_cjet = 0. - default_misid_ljet = 0. - - - userVariables = { "bjet_id.matching_dr" : [str(default_matching_dr)],\ - "bjet_id.exclusive" : [str(default_exclusive)],\ - "bjet_id.efficiency" : [str(default_efficiency)],\ - "bjet_id.misid_cjet" : [str(default_misid_cjet)],\ - "bjet_id.misid_ljet" : [str(default_misid_ljet)]\ - } + default_exclusive = True + default_efficiency = 1.0 + default_misid_cjet = 0.0 + default_misid_ljet = 0.0 + + userVariables = { + "bjet_id.matching_dr": [str(default_matching_dr)], + "bjet_id.exclusive": ["True", "False"], + } def __init__(self): self.matching_dr = BeautyIdentification.default_matching_dr - self.exclusive = BeautyIdentification.default_exclusive - self.efficiency = BeautyIdentification.default_efficiency - self.misid_cjet = BeautyIdentification.default_misid_cjet - self.misid_ljet = BeautyIdentification.default_misid_ljet + self.exclusive = BeautyIdentification.default_exclusive + self.efficiency = BeautyIdentification.default_efficiency + self.misid_cjet = BeautyIdentification.default_misid_cjet + self.misid_ljet = BeautyIdentification.default_misid_ljet - def Display(self): - logging.getLogger('MA5').info(" + b-jet identification:") + logging.getLogger("MA5").info(" + b-jet identification:") self.user_DisplayParameter("bjet_id.matching_dr") self.user_DisplayParameter("bjet_id.exclusive") - self.user_DisplayParameter("bjet_id.efficiency") - self.user_DisplayParameter("bjet_id.misid_cjet") - self.user_DisplayParameter("bjet_id.misid_ljet") - - - def user_DisplayParameter(self,parameter): - if parameter=="bjet_id.matching_dr": - logging.getLogger('MA5').info(" + DeltaR matching = "+str(self.matching_dr)) - elif parameter=="bjet_id.exclusive": - msg="false" - if self.exclusive: - msg="true" - logging.getLogger('MA5').info(" + exclusive algo = "+msg) - elif parameter=="bjet_id.efficiency": - logging.getLogger('MA5').info(" + id efficiency = "+str(self.efficiency)) - elif parameter=="bjet_id.misid_cjet": - logging.getLogger('MA5').info(" + mis-id efficiency (c-quark) = "+str(self.misid_cjet)) - elif parameter=="bjet_id.misid_ljet": - logging.getLogger('MA5').info(" + mis-id efficiency (light quarks) = "+str(self.misid_ljet)) - else: - logging.getLogger('MA5').error("'clustering' has no parameter called '"+parameter+"'") + def user_DisplayParameter(self, parameter): + if parameter == "bjet_id.matching_dr": + logging.getLogger("MA5").info(" + DeltaR matching = " + str(self.matching_dr)) + elif parameter == "bjet_id.exclusive": + logging.getLogger("MA5").info( + f" + exclusive algo = {'true' if self.exclusive else 'false'}" + ) + else: + logging.getLogger("MA5").error( + "'clustering' has no parameter called '" + parameter + "'" + ) def SampleAnalyzerConfigString(self): - mydict = {} - mydict['bjet_id.matching_dr'] = str(self.matching_dr) - mydict['bjet_id.efficiency'] = str(self.efficiency) - if self.exclusive: - mydict['bjet_id.exclusive'] = '1' - else: - mydict['bjet_id.exclusive'] = '0' - mydict['bjet_id.misid_cjet'] = str(self.misid_cjet) - mydict['bjet_id.misid_ljet'] = str(self.misid_ljet) - return mydict - - - def user_GetValues(self,variable): - try: - return BeautyIdentification.userVariables[variable] - except: - return [] - - + return { + "bjet_id.matching_dr": str(self.matching_dr), + "bjet_id.exclusive": "1" if self.exclusive else "0", + } + + def user_GetValues(self, variable): + return BeautyIdentification.userVariables.get(variable, []) + def user_GetParameters(self): return list(BeautyIdentification.userVariables.keys()) - - def user_SetParameter(self,parameter,value): + def user_SetParameter(self, parameter: str, value: str) -> bool: # matching deltar - if parameter=="bjet_id.matching_dr": + if parameter == "bjet_id.matching_dr": try: number = float(value) - except: - logging.getLogger('MA5').error("the 'matching deltaR' must be a float value.") + except Exception as err: + logging.getLogger("MA5").error("the 'matching deltaR' must be a float value.") return False - if number<=0: - logging.getLogger('MA5').error("the 'matching deltaR' cannot be negative or null.") + if number <= 0: + logging.getLogger("MA5").error("the 'matching deltaR' cannot be negative or null.") return False - self.matching_dr=number + self.matching_dr = number # exclusive - elif parameter=="bjet_id.exclusive": - if value == "true": - self.exclusive=True - elif value == "false": - self.exclusive=False - else: - logging.getLogger('MA5').error("'exclusive' possible values are : 'true', 'false'") - return False - - # efficiency - elif parameter=="bjet_id.efficiency": - try: - number = float(value) - except: - logging.getLogger('MA5').error("the efficiency must be a float value.") - return False - if number<0: - logging.getLogger('MA5').error("the efficiency cannot be negative.") - return False - if number>1: - logging.getLogger('MA5').error("the efficiency cannot not greater to 1.") + elif parameter == "bjet_id.exclusive": + if value.lower() not in ["true", "false"]: + logging.getLogger("MA5").error("'exclusive' possible values are : 'true', 'false'") return False - self.efficiency=number + self.exclusive = value == "true" # efficiency - elif parameter=="bjet_id.efficiency": - try: - number = float(value) - except: - logging.getLogger('MA5').error("the efficiency must be a float value.") - return False - if number<0: - logging.getLogger('MA5').error("the efficiency cannot be negative.") - return False - if number>1: - logging.getLogger('MA5').error("the efficiency cannot be greater to 1.") - return False - self.efficiency=number + elif parameter == "bjet_id.efficiency": + logging.getLogger("MA5").error("This function is deprecated; please use the corresponding SFS functionality instead.") + logging.getLogger("MA5").error("This can be achieved by typing the following command:") + logging.getLogger("MA5").error(f" -> define tagger b as b {value}") + return False # mis efficiency (cjet) - elif parameter=="bjet_id.misid_cjet": - try: - number = float(value) - except: - logging.getLogger('MA5').error("the mis-id efficiency must be a float value.") - return False - if number<0: - logging.getLogger('MA5').error("the mis-id efficiency cannot be negative.") - return False - if number>1: - logging.getLogger('MA5').error("the mis-id efficiency cannot be greater to 1.") - return False - self.misid_cjet=number + elif parameter == "bjet_id.misid_cjet": + logging.getLogger("MA5").error("This function is deprecated; please use the corresponding SFS functionality instead.") + logging.getLogger("MA5").error("This can be achieved by typing the following command:") + logging.getLogger("MA5").error(f" -> define tagger b as c {value}") + return False # mis efficiency (ljet) - elif parameter=="bjet_id.misid_ljet": - try: - number = float(value) - except: - logging.getLogger('MA5').error("the mis-id efficiency must be a float value.") - return False - if number<0: - logging.getLogger('MA5').error("the mis-id efficiency cannot be negative.") - return False - if number>1: - logging.getLogger('MA5').error("the mis-id efficiency cannot be greater to 1.") - return False - self.misid_ljet=number + elif parameter == "bjet_id.misid_ljet": + logging.getLogger("MA5").error("This function is deprecated; please use the corresponding SFS functionality instead.") + logging.getLogger("MA5").error("This can be achieved by typing the following command:") + logging.getLogger("MA5").error(f" -> define tagger b as j {value}") + return False - # other + # other else: - logging.getLogger('MA5').error("'clustering' has no parameter called '"+parameter+"'") + logging.getLogger("MA5").error( + "'clustering' has no parameter called '" + parameter + "'" + ) diff --git a/madanalysis/configuration/charm_identification.py b/madanalysis/configuration/charm_identification.py new file mode 100644 index 00000000..1d83aa57 --- /dev/null +++ b/madanalysis/configuration/charm_identification.py @@ -0,0 +1,114 @@ +################################################################################ +# +# Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +# The MadAnalysis development team, email: +# +# This file is part of MadAnalysis 5. +# Official website: +# +# MadAnalysis 5 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MadAnalysis 5 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MadAnalysis 5. If not, see +# +################################################################################ + + +from __future__ import absolute_import +import logging + + +class CharmIdentification: + + default_matching_dr = 0.5 + default_exclusive = True + + userVariables = {"cjet_id.status": ["on", "off"]} + + def __init__(self): + self.matching_dr = CharmIdentification.default_matching_dr + self.exclusive = CharmIdentification.default_exclusive + self.status = False + + def Display(self): + logging.getLogger("MA5").info(" + c-jet identification:") + if self.status: + self.user_DisplayParameter("cjet_id.matching_dr") + self.user_DisplayParameter("cjet_id.exclusive") + else: + logging.getLogger("MA5").info(" + Disabled") + + def user_DisplayParameter(self, parameter): + if parameter == "cjet_id.matching_dr": + logging.getLogger("MA5").info(" + DeltaR matching = " + str(self.matching_dr)) + elif parameter == "cjet_id.exclusive": + logging.getLogger("MA5").info( + f" + exclusive algo = {'true' if self.exclusive else 'false'}" + ) + else: + logging.getLogger("MA5").error( + "'clustering' has no parameter called '" + parameter + "'" + ) + + def SampleAnalyzerConfigString(self): + return { + "cjet_id.matching_dr": str(self.matching_dr), + "cjet_id.exclusive": "1" if self.exclusive else "0", + "cjet_id.enable_ctagging": "1" if self.status else "0", + } + + def user_GetValues(self, variable): + return CharmIdentification.userVariables.get(variable, []) + + def user_GetParameters(self): + return list(CharmIdentification.userVariables.keys()) + + def user_SetParameter(self, parameter, value: str) -> bool: + # matching deltar + if parameter == "cjet_id.matching_dr": + try: + number = float(value) + except Exception as err: + logging.getLogger("MA5").error("the 'matching deltaR' must be a float value.") + return False + if number <= 0: + logging.getLogger("MA5").error("the 'matching deltaR' cannot be negative or null.") + return False + self.matching_dr = number + + # Enable ctagger + elif parameter == "cjet_id.status": + if value.lower() not in ["on", "off"]: + logging.getLogger("MA5").error("C-Jet tagging status can only be `on` or `off`.") + return False + self.status = value.lower() == "on" + if self.status and "cjet_id.matching_dr" not in CharmIdentification.userVariables.keys(): + CharmIdentification.userVariables.update( + { + "cjet_id.matching_dr": [str(CharmIdentification.default_matching_dr)], + "cjet_id.exclusive": ["True", "False"], + } + ) + else: + CharmIdentification.userVariables = {"cjet_id.status": ["on", "off"]} + + # exclusive + elif parameter == "cjet_id.exclusive": + if value not in ["true", "false"]: + logging.getLogger("MA5").error("'exclusive' possible values are : 'true', 'false'") + return False + self.exclusive = value == "true" + + # other + else: + logging.getLogger("MA5").error( + "'clustering' has no parameter called '" + parameter + "'" + ) diff --git a/madanalysis/configuration/clustering_configuration.py b/madanalysis/configuration/clustering_configuration.py index df7c8272..4e683ddb 100644 --- a/madanalysis/configuration/clustering_configuration.py +++ b/madanalysis/configuration/clustering_configuration.py @@ -2,131 +2,146 @@ # # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: -# +# # This file is part of MadAnalysis 5. # Official website: -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.configuration.clustering_kt import ClusteringKt -from madanalysis.configuration.clustering_antikt import ClusteringAntiKt -from madanalysis.configuration.clustering_genkt import ClusteringGenKt -from madanalysis.configuration.clustering_cambridge import ClusteringCambridge -from madanalysis.configuration.clustering_gridjet import ClusteringGridJet +from madanalysis.configuration.clustering_kt import ClusteringKt +from madanalysis.configuration.clustering_antikt import ClusteringAntiKt +from madanalysis.configuration.clustering_genkt import ClusteringGenKt +from madanalysis.configuration.clustering_cambridge import ClusteringCambridge +from madanalysis.configuration.clustering_gridjet import ClusteringGridJet from madanalysis.configuration.clustering_cdfmidpoint import ClusteringCDFMidPoint -from madanalysis.configuration.clustering_cdfjetclu import ClusteringCDFJetClu -from madanalysis.configuration.clustering_siscone import ClusteringSisCone -from madanalysis.configuration.beauty_identification import BeautyIdentification -from madanalysis.configuration.tau_identification import TauIdentification -from madanalysis.enumeration.ma5_running_type import MA5RunningType +from madanalysis.configuration.clustering_cdfjetclu import ClusteringCDFJetClu +from madanalysis.configuration.clustering_siscone import ClusteringSisCone +from madanalysis.configuration.beauty_identification import BeautyIdentification +from madanalysis.configuration.charm_identification import CharmIdentification +from madanalysis.configuration.tau_identification import TauIdentification +from madanalysis.enumeration.ma5_running_type import MA5RunningType import logging + class ClusteringConfiguration: - userVariables = { "algorithm" : ["kt","antikt","genkt",\ - "cambridge","gridjet",\ - "siscone",\ - "cdfjetclu", "cdfmidpoint",\ - "none"], - "exclusive_id" : ["true","false"], - "jetrecomode" : ["jets","constituents"], - "magnetic_field" : ["3.8"], - # "tracker_radius" : ["1.29"], - # "half_length" : ["3.0"], - "particle_propagator" : ["on","off"], - "track_isocone_radius" : ["0.5"], - "electron_isocone_radius" : ["0.5"], - "muon_isocone_radius" : ["0.5"], - "photon_isocone_radius" : ["0.5"], - - } + userVariables = { + "algorithm": [ + "kt", + "antikt", + "genkt", + "cambridge", + "gridjet", + "siscone", + "cdfjetclu", + "cdfmidpoint", + "none", + ], + "exclusive_id": ["true", "false"], + "jetrecomode": ["jets", "constituents"], + "magnetic_field": ["3.8"], + # "tracker_radius" : ["1.29"], @JACK these are not available atm + # "half_length" : ["3.0"], + "particle_propagator": ["on", "off"], + "JetID": ["Ma5Jet"], + "track_isocone_radius": ["0.5"], + "electron_isocone_radius": ["0.5"], + "muon_isocone_radius": ["0.5"], + "photon_isocone_radius": ["0.5"], + } def __init__(self): - self.algorithm = "antikt" - self.clustering = ClusteringAntiKt() - self.beauty = BeautyIdentification() - self.tau = TauIdentification() + self.algorithm = "antikt" + self.clustering = ClusteringAntiKt() + self.beauty = BeautyIdentification() + self.charm = CharmIdentification() + self.tau = TauIdentification() self.exclusive_id = True + self.JetID = "Ma5Jet" - def Display(self): self.user_DisplayParameter("algorithm") - if self.algorithm!="none": + if self.algorithm != "none": + logging.getLogger("MA5").info(" + Jet ID : " + self.JetID) self.clustering.Display() self.user_DisplayParameter("exclusive_id") self.beauty.Display() + self.charm.Display() self.tau.Display() - - def user_DisplayParameter(self,parameter): - if parameter=="algorithm": - logging.getLogger('MA5').info(" clustering algorithm : "+self.algorithm) + def user_DisplayParameter(self, parameter): + if parameter == "algorithm": + logging.getLogger("MA5").info(" clustering algorithm : " + self.algorithm) return - if self.algorithm!="none": - if parameter=="exclusive_id": - word="" + if self.algorithm != "none": + if parameter == "exclusive_id": + word = "" if self.exclusive_id: - word="true" + word = "true" else: - word="false" - logging.getLogger('MA5').info(" + exclusive identification = "+word) - elif parameter.startswith('bjet_id.'): + word = "false" + logging.getLogger("MA5").info(" + exclusive identification = " + word) + elif parameter.startswith("bjet_id."): self.beauty.user_DisplayParameter(parameter) - elif parameter.startswith('tau_id.'): + elif parameter.startswith("cjet_id."): + self.charm.user_DisplayParameter(parameter) + elif parameter.startswith("tau_id."): self.tau.user_DisplayParameter(parameter) else: self.clustering.user_DisplayParameter(parameter) - def SampleAnalyzerConfigString(self): - if self.algorithm!="none": + if self.algorithm != "none": mydict = {} + mydict["JetID"] = self.JetID if self.exclusive_id: - mydict['exclusive_id'] = '1' + mydict["exclusive_id"] = "1" else: - mydict['exclusive_id'] = '0' + mydict["exclusive_id"] = "0" mydict.update(self.clustering.SampleAnalyzerConfigString()) mydict.update(self.beauty.SampleAnalyzerConfigString()) + mydict.update(self.charm.SampleAnalyzerConfigString()) mydict.update(self.tau.SampleAnalyzerConfigString()) return mydict else: return {} + def user_SetParameter(self, parameter, value, datasets, level): - def user_SetParameter(self,parameter,value,datasets,level): - # algorithm - if parameter=="algorithm": + if parameter == "algorithm": # Switch off the clustering - if value=="none": - test=True + if value == "none": + test = True for dataset in datasets: if not test: break for file in dataset.filenames: - if file.endswith('lhe') or \ - file.endswith('lhe.gz') or \ - file.endswith('hep') or \ - file.endswith('hep.gz') or \ - file.endswith('hepmc') or \ - file.endswith('hepmc.gz'): - test=False + if ( + file.endswith("lhe") + or file.endswith("lhe.gz") + or file.endswith("hep") + or file.endswith("hep.gz") + or file.endswith("hepmc") + or file.endswith("hepmc.gz") + ): + test = False break if not test: logging.getLogger('MA5').error("some datasets contain partonic/hadronic file format. "+\ @@ -134,118 +149,140 @@ def user_SetParameter(self,parameter,value,datasets,level): return # Switch on the clustering - elif value in ["kt","antikt","cambridge","genkt",\ - "gridjet","cdfmidpoint","cdfjetclu",\ - "siscone"]: + elif value in [ + "kt", + "antikt", + "cambridge", + "genkt", + "gridjet", + "cdfmidpoint", + "cdfjetclu", + "siscone", + ]: # Only in reco mode - if level!=MA5RunningType.RECO: - logging.getLogger('MA5').error("clustering algorithm is only available in RECO mode") + if level != MA5RunningType.RECO: + logging.getLogger("MA5").error( + "clustering algorithm is only available in RECO mode" + ) return - - test=True + + test = True for dataset in datasets: if not test: break for file in dataset.filenames: - if file.endswith('lhco') or \ - file.endswith('lhco.gz') or \ - file.endswith('root'): - test=False + if ( + file.endswith("lhco") + or file.endswith("lhco.gz") + or file.endswith("root") + ): + test = False break if not test: logging.getLogger('MA5').error("some datasets contain reconstructed file format. "+\ "Clustering algorithm cannot be switched on.") return - - if value=="kt": - self.algorithm="kt" + + if value == "kt": + self.algorithm = "kt" self.clustering = ClusteringKt() - elif value=="antikt": - self.algorithm="antikt" + elif value == "antikt": + self.algorithm = "antikt" self.clustering = ClusteringAntiKt() - elif value=="cambridge": - self.algorithm="cambridge" + elif value == "cambridge": + self.algorithm = "cambridge" self.clustering = ClusteringCambridge() - elif value=="genkt": - self.algorithm="genkt" + elif value == "genkt": + self.algorithm = "genkt" self.clustering = ClusteringGenKt() - elif value=="gridjet": - self.algorithm="gridjet" + elif value == "gridjet": + self.algorithm = "gridjet" self.clustering = ClusteringGridJet() - elif value=="cdfmidpoint": - self.algorithm="cdfmidpoint" + elif value == "cdfmidpoint": + self.algorithm = "cdfmidpoint" self.clustering = ClusteringCDFMidPoint() - elif value=="cdfjetclu": - self.algorithm="cdfjetclu" + elif value == "cdfjetclu": + self.algorithm = "cdfjetclu" self.clustering = ClusteringCDFJetClu() - elif value=="siscone": - self.algorithm="siscone" + elif value == "siscone": + self.algorithm = "siscone" self.clustering = ClusteringSisCone() - elif value=="none": - self.algorithm="none" + elif value == "none": + self.algorithm = "none" self.clustering = 0 else: - logging.getLogger('MA5').error("algorithm called '"+value+"' is not found.") - return + logging.getLogger("MA5").error("algorithm called '" + value + "' is not found.") + return # other rejection if no algo specified - if self.algorithm=="none": - logging.getLogger('MA5').error("'clustering' has no parameter called '"+parameter+"'") + if self.algorithm == "none": + logging.getLogger("MA5").error( + "'clustering' has no parameter called '" + parameter + "'" + ) return # exclusive_id - if parameter=="exclusive_id": - if value=="true": - self.exclusive_id=True - elif value=="false": - self.exclusive_id=False + if parameter == "exclusive_id": + if value == "true": + self.exclusive_id = True + elif value == "false": + self.exclusive_id = False else: - logging.getLogger('MA5').error("The allowed values for 'exclusive_id' " +\ - "parameter are 'true' or 'false'.") - return + logging.getLogger("MA5").error( + "The allowed values for 'exclusive_id' " + "parameter are 'true' or 'false'." + ) + return # other - elif parameter.startswith('bjet_id.'): - return self.beauty.user_SetParameter(parameter,value) - elif parameter.startswith('tau_id.'): - return self.tau.user_SetParameter(parameter,value) + elif parameter.startswith("bjet_id."): + return self.beauty.user_SetParameter(parameter, value) + elif parameter.startswith("cjet_id."): + return self.charm.user_SetParameter(parameter, value) + elif parameter.startswith("tau_id."): + return self.tau.user_SetParameter(parameter, value) + elif parameter.lower() == "jetid": + self.JetID = str(value) else: - return self.clustering.user_SetParameter(parameter,value) + return self.clustering.user_SetParameter(parameter, value) + - def user_GetParameters(self): - if self.algorithm!="none": + if self.algorithm != "none": table = list(ClusteringConfiguration.userVariables.keys()) table.extend(self.clustering.user_GetParameters()) table.extend(self.beauty.user_GetParameters()) + table.extend(self.charm.user_GetParameters()) table.extend(self.tau.user_GetParameters()) else: table = ["algorithm"] return table - - def user_GetValues(self,variable): + def user_GetValues(self, variable): table = [] - if self.algorithm!="none": + if self.algorithm != "none": try: table.extend(ClusteringConfiguration.userVariables[variable]) - except: + except Exception as err: pass try: table.extend(self.clustering.user_GetValues(variable)) - except: + except Exception as err: pass try: table.extend(self.beauty.user_GetValues(variable)) - except: + except Exception as err: + pass + try: + table.extend(self.charm.user_GetValues(variable)) + except Exception as err: pass try: table.extend(self.tau.user_GetValues(variable)) - except: + except Exception as err: pass else: - if variable=="algorithm": + if variable == "algorithm": table.extend(ClusteringConfiguration.userVariables["algorithm"]) return table - + return table diff --git a/madanalysis/configuration/tau_identification.py b/madanalysis/configuration/tau_identification.py index df842928..2e451d81 100644 --- a/madanalysis/configuration/tau_identification.py +++ b/madanalysis/configuration/tau_identification.py @@ -2,7 +2,7 @@ # # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: -# +# # This file is part of MadAnalysis 5. # Official website: # @@ -10,101 +10,136 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see -# +# ################################################################################ from __future__ import absolute_import import logging -class TauIdentification(): - default_matching_dr = 0.5 - default_exclusive = True - default_efficiency = 1. - default_misid_ljet = 0. - userVariables = { "tau_id.efficiency" : [str(default_efficiency)],\ - "tau_id.misid_ljet" : [str(default_misid_ljet)]\ - } +class TauIdentification: + + default_matching_dr = 0.3 + default_exclusive = False + default_reconstruction_method = "hadron-based" + userVariables = { + "tau_id.reconstruction_method": ["jet-based", "hadron-based"], + } def __init__(self): - self.efficiency = TauIdentification.default_efficiency - self.misid_ljet = TauIdentification.default_misid_ljet + self.matching_dr = TauIdentification.default_matching_dr + self.reconstruction_method = TauIdentification.default_reconstruction_method + self.exclusive = TauIdentification.default_exclusive - def Display(self): - logging.getLogger('MA5').info(" + hadronic-tau identification:") - self.user_DisplayParameter("tau_id.efficiency") - self.user_DisplayParameter("tau_id.misid_ljet") - - - def user_DisplayParameter(self,parameter): - if parameter=="tau_id.efficiency": - logging.getLogger('MA5').info(" + id efficiency = "+str(self.efficiency)) - elif parameter=="tau_id.misid_ljet": - logging.getLogger('MA5').info(" + mis-id efficiency (light quarks) = "+str(self.misid_ljet)) + logging.getLogger("MA5").info(" + hadronic-tau identification:") + if self.reconstruction_method == "jet-based": + self.user_DisplayParameter("tau_id.matching_dr") + self.user_DisplayParameter("tau_id.reconstruction_method") + + def user_DisplayParameter(self, parameter): + if parameter == "tau_id.matching_dr": + logging.getLogger("MA5").info(f" + DeltaR matching = {self.matching_dr:.2f}") + elif parameter == "tau_id.reconstruction_method": + logging.getLogger("MA5").info( + f" + Reconstruction method: {self.reconstruction_method}" + ) + elif parameter == "tau_id.exclusive": + logging.getLogger("MA5").info( + f" + exclusive algo = {'true' if self.exclusive else 'false'}" + ) else: - logging.getLogger('MA5').error("'clustering' has no parameter called '"+parameter+"'") - + logging.getLogger("MA5").error( + "'clustering' has no parameter called '" + parameter + "'" + ) def SampleAnalyzerConfigString(self): - mydict = {} - mydict['tau_id.efficiency'] = str(self.efficiency) - mydict['tau_id.misid_ljet'] = str(self.misid_ljet) - return mydict - - - def user_GetValues(self,variable): - try: - return TauIdentification.userVariables[variable] - except: - return [] - - + return { + "tau_id.matching_dr": str(self.matching_dr), + "tau_id.reconstruction_method": "1" if self.reconstruction_method == "jet-based" else "0", + "tau_id.exclusive": "1" if self.exclusive else "0", + } + + def user_GetValues(self, variable): + return TauIdentification.userVariables.get(variable, []) + def user_GetParameters(self): return list(TauIdentification.userVariables.keys()) - - def user_SetParameter(self,parameter,value): - # efficiency - if parameter=="tau_id.efficiency": + def user_SetParameter(self, parameter, value): + # matching deltar + if parameter == "tau_id.matching_dr": try: number = float(value) except: - logging.getLogger('MA5').error("the efficiency must be a float value.") + logging.getLogger("MA5").error("the 'matching deltaR' parameter must be a float.") + return False + if number <= 0: + logging.getLogger("MA5").error("the 'matching deltaR' parameter cannot be negative or zero.") return False - if number<0: - logging.getLogger('MA5').error("the efficiency cannot be negative.") + if self.reconstruction_method == "hadron-based": + logging.getLogger("MA5").warning("Hadronic tau matching is only available in the jet-based tagging mode.") + logging.getLogger("MA5").warning("To activate jet-based tagging, please type:" + "`set main.fastsim.tau_id.reconstruction_method = jet-based`") + self.matching_dr = number + + # Exclusive algorithm + elif parameter == "tau_id.exclusive": + if value not in ["true", "false"]: + logging.getLogger('MA5').error("'exclusive' possible values are : 'true', 'false'") return False - if number>1: - logging.getLogger('MA5').error("the efficiency cannot not greater to 1.") + if self.reconstruction_method == "hadron-based": + logging.getLogger("MA5").warning("Exclusive Hadronic tau matching is only available in the jet-based tagging mode.") + logging.getLogger("MA5").warning("To activate jet-based tagging, please type:" + "`set main.fastsim.tau_id.reconstruction_method = jet-based`") + self.exclusive = (value == "true") + + # reconstruction method + if parameter == "tau_id.reconstruction_method": + if value in TauIdentification.userVariables["tau_id.reconstruction_method"]: + self.reconstruction_method = value + else: + logging.getLogger("MA5").error( + "Available reconstruction methods are: " + + ", ".join(TauIdentification.userVariables["tau_id.reconstruction_method"]) + ) return False - self.efficiency=number + if self.reconstruction_method == "jet-based": + TauIdentification.userVariables.update( + {"tau_id.matching_dr": [str(TauIdentification.default_matching_dr)], + "tau_id.exclusive": ["True", "False"]} + ) + else: + TauIdentification.userVariables = { + "tau_id.reconstruction_method": ["jet-based", "hadron-based"] + } + + # efficiency + elif parameter == "tau_id.efficiency": + logging.getLogger("MA5").error("This function is deprecated; please use the corresponding SFS functionality instead.") + logging.getLogger("MA5").error("This can be achieved by typing the following command:") + logging.getLogger("MA5").error(f" -> define tagger ta as ta {value}") + return False # mis efficiency (ljet) - elif parameter=="tau_id.misid_ljet": - try: - number = float(value) - except: - logging.getLogger('MA5').error("the mis-id efficiency must be a float value.") - return False - if number<0: - logging.getLogger('MA5').error("the mis-id efficiency cannot be negative.") - return False - if number>1: - logging.getLogger('MA5').error("the mis-id efficiency cannot be greater to 1.") - return False - self.misid_ljet=number + elif parameter == "tau_id.misid_ljet": + logging.getLogger("MA5").error("This function is deprecated; please use the corresponding SFS functionality instead.") + logging.getLogger("MA5").error("This can be achieved by typing the following command:") + logging.getLogger("MA5").error(f" -> define tagger ta as j {value}") + return False - # other + # other else: - logging.getLogger('MA5').error("'clustering' has no parameter called '"+parameter+"'") + logging.getLogger("MA5").error( + "'clustering' has no parameter called '" + parameter + "'" + ) diff --git a/madanalysis/core/expert_mode.py b/madanalysis/core/expert_mode.py index 268470e9..f071a066 100644 --- a/madanalysis/core/expert_mode.py +++ b/madanalysis/core/expert_mode.py @@ -155,15 +155,18 @@ def Copy(self,name,config=''): # if fastsim functionalities are needed if config!='': - with open(self.path+'/Build/SampleAnalyzer/User/Analyzer/'+title+'.h','r') as f: + with open(self.path+'/Build/SampleAnalyzer/User/Analyzer/analysisList.h','r') as f: header = f.readlines() - to_include = [x for x in os.listdir(self.path+'/Build/SampleAnalyzer/User/Analyzer/') if x in ['new_smearer_reco.h', - 'new_tagger.h']] - top_header = header[:header.index('namespace MA5\n')] - bottom_header = header[header.index('namespace MA5\n'):] - for inc in to_include: + to_include = [x for x in os.listdir(self.path + '/Build/SampleAnalyzer/User/Analyzer/') if + x in ['new_smearer_reco.h', 'new_tagger.h']] + + top_header = header[:header.index('// -----------------------------------------------------------------------------\n')] + bottom_header = header[header.index('// -----------------------------------------------------------------------------\n'):] + for idx, inc in enumerate(to_include): + if idx == 0: + top_header.append("/// SFS Headers\n") top_header.append('#include "'+inc+'"\n') - open(self.path+'/Build/SampleAnalyzer/User/Analyzer/'+title+'.h','w').writelines(top_header+bottom_header) + open(self.path+'/Build/SampleAnalyzer/User/Analyzer/analysisList.h','w').writelines(top_header+bottom_header) return True diff --git a/madanalysis/core/main.py b/madanalysis/core/main.py index 8d417c65..09ae3c84 100644 --- a/madanalysis/core/main.py +++ b/madanalysis/core/main.py @@ -29,6 +29,7 @@ from madanalysis.interpreter.cmd_base import CmdBase from madanalysis.region.region_collection import RegionCollection from madanalysis.fastsim.fastsim import SuperFastSim +from madanalysis.jet_clustering.jet_collection import JetCollection from madanalysis.system.session_info import SessionInfo from madanalysis.system.architecture_info import ArchitectureInfo from madanalysis.core.library_builder import LibraryBuilder @@ -98,6 +99,7 @@ def ResetParameters(self): self.merging = MergingConfiguration() self.fastsim = FastsimConfiguration() self.superfastsim = SuperFastSim() + self.jet_collection = JetCollection() self.recasting = RecastConfiguration() self.fom = FomConfiguration() self.lumi = 10 @@ -516,11 +518,11 @@ def BuildLibrary(self,forced=False): if not os.path.isfile(self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/TestSampleAnalyzer'): FirstUse=True - precompiler = LibraryWriter('lib',self) - if not precompiler.Run('TestSampleAnalyzer',\ - [self.archi_info.ma5dir+'/tools/SampleAnalyzer/Test/Process/dummy_list.txt'],\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/',silent=True): - UpdateNeed=True + precompiler = LibraryWriter('lib', self) + if not precompiler.Run('TestSampleAnalyzer', + [self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/Process/dummy_list.txt'], + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/', silent=True): + UpdateNeed = True if not precompiler.CheckRun('TestSampleAnalyzer',self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/',silent=True): UpdateNeed=True @@ -554,65 +556,83 @@ def BuildLibrary(self,forced=False): # |- [4] = folder # |- [5] = False=Library, True=Executable libraries = [] - libraries.append(['configuration','SampleAnalyzer configuration', 'configuration', \ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/PortabilityCheckup',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Configuration',True]) - libraries.append(['commons','SampleAnalyzer commons', 'commons', \ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Lib/libcommons_for_ma5.so',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Commons',False]) - libraries.append(['test_commons','SampleAnalyzer commons', 'test_commons', \ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/TestCommons',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Test/',True]) + libraries.append(['configuration', 'SampleAnalyzer configuration', 'configuration', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/PortabilityCheckup', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Configuration', True]) + libraries.append(['commons', 'SampleAnalyzer commons', 'commons', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Lib/libcommons_for_ma5.so', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Commons', False]) + libraries.append(['test_commons', 'SampleAnalyzer commons', 'test_commons', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/TestCommons', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/', True]) # Zlib if self.archi_info.has_zlib: - libraries.append(['zlib', 'interface to zlib', 'zlib',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Lib/libzlib_for_ma5.so',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Interfaces',False]) - libraries.append(['test_zlib','interface to zlib', 'test_zlib',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/TestZlib',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Test/',True]) + libraries.append(['zlib', 'interface to zlib', 'zlib', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Lib/libzlib_for_ma5.so', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Interfaces', False]) + libraries.append(['test_zlib', 'interface to zlib', 'test_zlib', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/TestZlib', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/', True]) # Fastjet if self.archi_info.has_fastjet: - libraries.append(['FastJet', 'interface to FastJet', 'fastjet',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Lib/libfastjet_for_ma5.so',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Interfaces',False]) - libraries.append(['test_fastjet','interface to Fastjet', 'test_fastjet',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/TestFastjet',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Test/',True]) + os.environ["FASTJET_FLAG"] = "-DMA5_FASTJET_MODE" + libraries.append(['FastJet', 'interface to FastJet', 'fastjet', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Lib/libfastjet_for_ma5.so', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Interfaces', False]) + libraries.append(['test_fastjet', 'interface to Fastjet', 'test_fastjet', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/TestFastjet', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/', True]) + if self.archi_info.has_fjcontrib: + libraries.append(['substructure', 'interface to Jet Substructure module', 'substructure', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Lib/libsubstructure_for_ma5.so', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Interfaces', False]) + libraries.append(['test_substructure', 'interface to Jet Substructure module', 'test_substructure', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/TestSubstructure', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/', True]) + if self.archi_info.has_heptoptagger: + libraries.append(['HEPTopTagger', 'interface to HEPTopTagger module', 'HEPTopTagger', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Lib/libHEPTopTagger_for_ma5.so', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Interfaces', False]) + libraries.append(['test_htt', 'interface to HEPTopTagger module', 'test_htt', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/TestHEPTopTagger', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/', True]) + else: + os.environ["FASTJET_FLAG"] = "" + # Delphes if self.archi_info.has_delphes: - libraries.append(['Delphes', 'interface to Delphes', 'delphes',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Lib/libdelphes_for_ma5.so',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Interfaces',False]) - libraries.append(['test_delphes','interface to Delphes', 'test_delphes',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/TestDelphes',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Test/',True]) + libraries.append(['Delphes', 'interface to Delphes', 'delphes', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Lib/libdelphes_for_ma5.so', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Interfaces', False]) + libraries.append(['test_delphes', 'interface to Delphes', 'test_delphes', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/TestDelphes', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/', True]) # DelphesMA5tune if self.archi_info.has_delphesMA5tune: - libraries.append(['Delphes-MA5tune', 'interface to Delphes-MA5tune', 'delphesMA5tune',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Lib/libdelphesMA5tune_for_ma5.so',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Interfaces',False]) - libraries.append(['test_delphesMA5tune','interface to DelphesMA5tune', 'test_delphesMA5tune',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/TestDelphesMA5tune',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Test/',True]) + libraries.append(['Delphes-MA5tune', 'interface to Delphes-MA5tune', 'delphesMA5tune', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Lib/libdelphesMA5tune_for_ma5.so', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Interfaces', False]) + libraries.append(['test_delphesMA5tune', 'interface to DelphesMA5tune', 'test_delphesMA5tune', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/TestDelphesMA5tune', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/', True]) # Root if self.archi_info.has_root: - libraries.append(['Root', 'interface to Root', 'root',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Lib/libroot_for_ma5.so',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Interfaces',False]) - libraries.append(['test_root','interface to Root', 'test_root',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/TestRoot',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Test/',True]) + libraries.append(['Root', 'interface to Root', 'root', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Lib/libroot_for_ma5.so', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Interfaces', False]) + libraries.append(['test_root', 'interface to Root', 'test_root', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/TestRoot', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/', True]) # Process - libraries.append(['process', 'SampleAnalyzer core', 'process',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Lib/libprocess_for_ma5.so',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Process',False]) - libraries.append(['test_process','SampleAnalyzer core', 'test_process',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Bin/TestSampleAnalyzer',\ - self.archi_info.ma5dir+'/tools/SampleAnalyzer/Test/',True]) + libraries.append(['process', 'SampleAnalyzer core', 'process', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Lib/libprocess_for_ma5.so', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Process', False]) + libraries.append(['test_process', 'SampleAnalyzer core', 'test_process', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Bin/TestSampleAnalyzer', + self.archi_info.ma5dir + '/tools/SampleAnalyzer/Test/', True]) # Writing the Makefiles diff --git a/madanalysis/fastsim/ast.py b/madanalysis/fastsim/ast.py index ab361b60..4c97f9ca 100644 --- a/madanalysis/fastsim/ast.py +++ b/madanalysis/fastsim/ast.py @@ -269,9 +269,9 @@ def tocpp(self,cpp_type,name): # Setting the c++ in text initialization - def tocpp_call(self,obj,name): + def tocpp_call(self,obj,name, pointer="->"): obs = list(set([x.name for x in self.leaves if x.type=='var'])) result = ' fct_' + name + '(' - result += ', '.join([obj+'->'+obs_list.__dict__[x].code_reco for x in obs]) + result += ', '.join([obj+pointer+obs_list.__dict__[x].code_reco for x in obs]) result += ') ' return result diff --git a/madanalysis/fastsim/fastsim.py b/madanalysis/fastsim/fastsim.py index 9e53496b..8e9cb764 100644 --- a/madanalysis/fastsim/fastsim.py +++ b/madanalysis/fastsim/fastsim.py @@ -25,7 +25,7 @@ from __future__ import absolute_import import logging from madanalysis.fastsim.ast import AST -from madanalysis.fastsim.tagger import Tagger +from madanalysis.fastsim.tagger import Tagger, TaggerStatus from madanalysis.fastsim.smearer import Smearer from madanalysis.fastsim.recoefficiency import RecoEfficiency from madanalysis.fastsim.scaling import Scaling @@ -71,11 +71,11 @@ def Reset(self): self.photon_isocone_radius = [] # Definition of a new tagging/smearing rule - def define(self,args,prts): - prts.Add('c',[4]) - prts.Add('track',[]) # PDGID is not important - prts.Add('JES', []) # PDGID is not important - prts_remove = ['c','track','JES'] + def define(self, args, prts): + prts.Add('c', [4]) + prts.Add('track', []) # PDGID is not important + prts.Add('JES', []) # PDGID is not important + prts_remove = ['c', 'track', 'JES'] ## remove all initializations when this session is over def remove_prts_def(prts_remove,prts): @@ -87,11 +87,11 @@ def is_pdgcode(prt): return (prt[0] in ('-','+') and prt[1:].isdigit()) or prt.isdigit() ## Checking the length of the argument list - if (args[0]=='tagger' and len(args)<5) or (args[0]=='smearer' and len(args)<3) \ - or (args[0]=='reco_efficiency' and len(args)<3) or (args[0]=='jes' and len(args)<2) \ - or (args[0]=='energy_scaling' and len(args)<3) or (args[0]=='scaling' and len(args)<4): + if (args[0] == 'tagger' and len(args) < 5) or (args[0] == 'smearer' and len(args) < 3) \ + or (args[0] == 'reco_efficiency' and len(args) < 3) or (args[0] == 'jes' and len(args) < 2) \ + or (args[0] == 'energy_scaling' and len(args) < 3) or (args[0] == 'scaling' and len(args) < 4): self.logger.error('Not enough arguments for tagging/smearing/reconstruction/scaling') - remove_prts_def(prts_remove,prts) + remove_prts_def(prts_remove, prts) return ## Checking the first argument @@ -176,39 +176,43 @@ def is_pdgcode(prt): to_decode=args[4:] ## Getting the bounds and the function - function, bounds = self.decode_args(to_decode) + function, bounds, tags = self.decode_args(to_decode) if function=='': self.logger.error('Cannot decode the function or the bounds - ' + args[0] + ' ignored.') remove_prts_def(prts_remove,prts) return ## Adding a rule to a tagger/smearer - if args[0]=='tagger': - self.tagger.add_rule(true_id,reco_id,function,bounds) - elif args[0]=='smearer': - self.smearer.add_rule(true_id,obs,function,bounds) - elif args[0]=='reco_efficiency': - self.reco.add_rule(true_id,function,bounds) - elif args[0] in ['jes','energy_scaling','scaling']: - self.scaling.add_rule(true_id,obs,function,bounds) - remove_prts_def(prts_remove,prts) + if args[0] == 'tagger': + self.tagger.add_rule(true_id, reco_id, function, bounds, TaggerStatus.get_status(tags)) + elif args[0] == 'smearer': + self.smearer.add_rule(true_id, obs, function, bounds) + elif args[0] == 'reco_efficiency': + self.reco.add_rule(true_id, function, bounds) + elif args[0] in ['jes', 'energy_scaling', 'scaling']: + self.scaling.add_rule(true_id, obs, function, bounds) + remove_prts_def(prts_remove, prts) return # Transform the arguments passed in the interpreter in the right format def decode_args(self,myargs): # Special formating for the power operator - args = ' '.join(myargs).replace('^',' ^ ') - for symb in ['< =','> =','= =']: + args = ' '.join(myargs).replace('^', ' ^ ') + for symb in ['< =', '> =', '= =']: args = args.replace(symb, ''.join(symb.split())) args = args.split() ## To get the difference pieces of the command Nbracket1 = 0 Nbracket2 = 0 + Nbracket3 = 0 beginOptions = len(args) endOptions = -1 foundOptions = False + beginTags = len(args) + endTags = -1 + foundTags = False ## Extraction of the arguments for i in range(0,len(args)): @@ -225,14 +229,35 @@ def decode_args(self,myargs): Nbracket2-=1 if Nbracket1==0: endOptions = i + # Look for tagging options + elif args[i] == "{": + Nbracket3+=1 + if Nbracket1 == 0 and Nbracket2 == 0: + beginTags = i + foundTags = True + elif args[i] == "}": + Nbracket3-=1 + if Nbracket1 == 0 and Nbracket2 == 0: + endTags = i + ## Sanity if Nbracket1!=0: self.logger.error("number of opening '(' and closing ')' does not match.") - return '', [] + return '', [], None if Nbracket2!=0: self.logger.error("number of opening '[' and closing ']' does not match.") - return '', [] + return '', [], None + if Nbracket3!=0: + self.logger.error("number of opening '{' and closing '}' does not match.") + return '', [], None + + ## Find tags + tags = args[beginTags + 1:endTags] + if len(tags) > 1: + self.logger.error("Can not process more than one tag.") + return '', [], None + tags = tags[0] if len(tags) == 1 else "" ## Putting the bounds into an AST bounds = ' '.join(args[beginOptions+1:endOptions]) @@ -242,10 +267,14 @@ def decode_args(self,myargs): ast_bounds.feed(bounds) ## Putting the efficiency into an AST - efficiency = ' ' .join(args[:beginOptions]) + start_from = beginOptions if foundOptions else beginTags + efficiency = ' ' .join(args[:start_from]) ast_eff = AST(1, self.observables.full_list) ast_eff.feed(efficiency) - return ast_eff, ast_bounds + + self.logger.debug(f"Tags: {tags}\nBounds: {bounds}\nefficiency: {efficiency}") + + return ast_eff, ast_bounds, tags diff --git a/madanalysis/fastsim/tagger.py b/madanalysis/fastsim/tagger.py index ad9644d9..1df81820 100644 --- a/madanalysis/fastsim/tagger.py +++ b/madanalysis/fastsim/tagger.py @@ -24,33 +24,82 @@ from __future__ import absolute_import import logging -class Tagger: +from typing import Any, Optional +from enum import Enum, auto + +AST = Any + +class TaggerStatus(Enum): + NONE = auto() + LOOSE = auto() + MID = auto() + TIGHT = auto() + + @staticmethod + def get_status(status: str): + """Convert string to tagger criterion""" + if status.lower() == "loose": + return TaggerStatus.LOOSE + elif status.lower() in ["med", "mid", "medium"]: + return TaggerStatus.MID + elif status.lower() == "tight": + return TaggerStatus.TIGHT + else: + return TaggerStatus.NONE + @staticmethod + def to_str(status): + if status == TaggerStatus.LOOSE: + return "loose" + elif status == TaggerStatus.MID: + return "medium" + elif status == TaggerStatus.TIGHT: + return "tight" + else: + return "" + + +class Tagger: # Initialization def __init__(self): - self.logger = logging.getLogger('MA5'); + self.logger = logging.getLogger('MA5') self.rules = {} + def add_rule(self, id_true: str, id_reco: str, function: AST, bounds: AST, tag: Optional[TaggerStatus] = None) -> None: + """ + Adding a rule to the tagger. The bounds and function are written as ASTs + + :param id_true: true particle id + :param id_reco: particle id to be reconstructed + :param function: efficiency function + :param bounds: bounds of the function + :param tag: loose/medium/tight criterion of the tagger + :return: + """ - # Adding a rule to the tagger - # The bounds and function are written as ASTs - def add_rule(self,id_true, id_reco, function, bounds): ## Checking wether the tagger is supported - if not self.is_supported(id_true, id_reco): + if not self.is_supported(id_true, id_reco, tag): return + ## Default tag for jets and taus is loose tag. If tag is not given convert to loose + if id_reco in ["21", "4", "5", "15"] and id_true in ["21", "4", "5", "15"]: + tag = tag if tag != TaggerStatus.NONE else TaggerStatus.LOOSE ## Checking whether the reco/true pair already exists - key_number=len(list(self.rules.keys()))+1 + key_number = len(list(self.rules.keys())) + 1 for key, value in self.rules.items(): - if value['id_true']==id_true and value['id_reco']==id_reco: + if value['id_true'] == id_true and value['id_reco'] == id_reco and value["tag"] == tag: key_number = key if not key_number in list(self.rules.keys()): - self.rules[key_number] = { 'id_true':id_true, 'id_reco':id_reco, - 'efficiencies':{} } + self.rules[key_number] = dict( + id_true=id_true, + id_reco=id_reco, + efficiencies=dict(), + tag=tag + ) ## Defining a new rule ID for an existing tagger - eff_key = len(self.rules[key_number]['efficiencies'])+1 - self.rules[key_number]['efficiencies'][eff_key] = { 'function':function, - 'bounds': bounds } + eff_key = len(self.rules[key_number]['efficiencies']) + 1 + self.rules[key_number]['efficiencies'][eff_key] = {'function': function, + 'bounds': bounds} def display(self): @@ -59,8 +108,8 @@ def display(self): self.logger.info('*********************************') for key in self.rules.keys(): myrule = self.rules[key] - self.logger.info(str(key) + ' - Tagging a true PDG-' + str(myrule['id_true']) + \ - ' as a PDG-' + str(myrule['id_reco'])) + self.logger.info(f"{key} - Tagging a true PDG-{myrule['id_true']} as a PDG-{myrule['id_reco']}" \ + + (myrule["tag"] != TaggerStatus.NONE)*f" with {TaggerStatus.to_str(myrule['tag'])} tag.") for eff_key in myrule['efficiencies'].keys(): cpp_name = 'eff_'+str(myrule['id_true'])+'_'+str(myrule['id_reco'])+\ '_'+str(eff_key) @@ -77,11 +126,20 @@ def display(self): self.logger.info(' --------------------') - def is_supported(self,id_true, id_reco): - supported = { '5':['21','4','5'], '4':['21','4','5'], '15':['15','21'], - '21' : ['11','13','22'], '11' : ['13','22', '21'], - '13' : ['11','22'], '22' : ['11','13', '21']} + def is_supported(self,id_true: str, id_reco: str, tag: TaggerStatus): + supported = {'5': ['21', '4', '5'], '4': ['21', '4', '5'], '15': ['15', '21'], + '21': ['11', '13', '22'], '11': ['13', '22', '21'], + '13': ['11', '22'], '22': ['11', '13', '21']} if id_reco not in list(supported.keys()) or id_true not in supported[id_reco]: - self.logger.error('This tagger is currently not supported (tagging '+ id_true + ' as ' + id_reco + '). Tagger ignored.') + self.logger.error( + f"This tagger is currently not supported (tagging {id_true} as {id_reco}). Tagger ignored." + ) return False + if tag in [TaggerStatus.LOOSE, TaggerStatus.MID, TaggerStatus.TIGHT]: + if id_reco not in ["21", "4", "5", "15"] or id_true not in ["21", "4", "5", "15"]: + self.logger.error( + f"This tagger is currently not supported. {id_true} can not be tagged as {id_reco} with " + f"{TaggerStatus.to_str(tag)} tag." + ) + return False return True diff --git a/madanalysis/install/install_fastjet.py b/madanalysis/install/install_fastjet.py index 929c5777..673e27e3 100644 --- a/madanalysis/install/install_fastjet.py +++ b/madanalysis/install/install_fastjet.py @@ -39,14 +39,6 @@ def __init__(self,main): self.downloaddir = self.main.session_info.downloaddir self.untardir = os.path.normpath(self.tmpdir + '/MA5_fastjet/') self.ncores = 1 -# self.files = {"fastjet.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fastjet-3.0.6.tar.gz"} -# self.files = {"fastjet.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fastjet-3.1.3.tar.gz"} -# self.files = {"fastjet.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fastjet-3.2.0.tar.gz"} -# self.files = {"fastjet.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fastjet-3.2.1.tar.gz"} -# self.files = {"fastjet.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fastjet-3.3.0.tar.gz"} -# self.files = {"fastjet.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fastjet-3.3.2.tar.gz"} -# self.files = {"fastjet.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fastjet-3.3.3.tar.gz"} -# self.files = {"fastjet.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fastjet-3.4.0.tar.gz"} self.files = {"fastjet.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fastjet-3.4.1.tar.gz"} def Detect(self): @@ -109,7 +101,9 @@ def Unpack(self): def Configure(self): # Input - theCommands=['./configure','--prefix='+self.installdir] + initial_env = os.environ.get("CXXFLAGS", "") + os.environ["CXXFLAGS"] = initial_env + " -std=c++11 -fPIC " + theCommands = ['./configure', '--prefix=' + self.installdir, "--enable-allplugins"] logname=os.path.normpath(self.installdir+'/configuration.log') # Execute logging.getLogger('MA5').debug('shell command: '+' '.join(theCommands)) @@ -117,6 +111,11 @@ def Configure(self): logname,\ self.tmpdir,\ silent=False) + # reset CXXFLAGS + if initial_env == "": + os.environ.pop("CXXFLAGS") + else: + os.environ["CXXFLAGS"] = initial_env # return result if not ok: logging.getLogger('MA5').error('impossible to configure the project. For more details, see the log file:') diff --git a/madanalysis/install/install_fastjetcontrib.py b/madanalysis/install/install_fastjetcontrib.py index 89e92aa2..18659029 100644 --- a/madanalysis/install/install_fastjetcontrib.py +++ b/madanalysis/install/install_fastjetcontrib.py @@ -40,13 +40,6 @@ def __init__(self,main): self.downloaddir = self.main.session_info.downloaddir self.untardir = os.path.normpath(self.tmpdir + '/MA5_fastjetcontrib/') self.ncores = 1 -# self.files = {"fastjetcontrib.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fjcontrib-1.012.tar.gz"} -# self.files = {"fastjetcontrib.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fjcontrib-1.017.tar.gz"} -# self.files = {"fastjetcontrib.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fjcontrib-1.024.tar.gz"} -# self.files = {"fastjetcontrib.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fjcontrib-1.027.tar.gz"} -# self.files = {"fastjetcontrib.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fjcontrib-1.039.tar.gz"} -# self.files = {"fastjetcontrib.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fjcontrib-1.042.tar.gz"} -# self.files = {"fastjetcontrib.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fjcontrib-1.045.tar.gz"} self.files = {"fastjetcontrib.tar.gz" : "http://madanalysis.irmp.ucl.ac.be/raw-attachment/wiki/WikiStart/fjcontrib-1.052.tar.gz"} def GetNcores(self): @@ -86,7 +79,9 @@ def Unpack(self): def Configure(self): # Input - theCommands=['./configure','--fastjet-config='+self.bindir] + # TODO: figure out how to give `-std=c++11 -fPIC` together to CXXFLAGS + # using " or ' doesn't work on linux systems + theCommands = ['./configure', '--fastjet-config=' + self.bindir, 'CXXFLAGS=-fPIC'] logname=os.path.normpath(self.installdir+'/configuration_contrib.log') # Execute logging.getLogger('MA5').debug('shell command: '+' '.join(theCommands)) diff --git a/madanalysis/install/install_heptoptagger.py b/madanalysis/install/install_heptoptagger.py new file mode 100644 index 00000000..6ad855dd --- /dev/null +++ b/madanalysis/install/install_heptoptagger.py @@ -0,0 +1,161 @@ +################################################################################ +# +# Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +# The MadAnalysis development team, email: +# +# This file is part of MadAnalysis 5. +# Official website: +# +# MadAnalysis 5 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MadAnalysis 5 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MadAnalysis 5. If not, see +# +################################################################################ + +from __future__ import absolute_import +from madanalysis.install.install_service import InstallService +from shell_command import ShellCommand +import os, json +import logging + + +class InstallHEPTopTagger: + def __init__(self, main): + self.main = main + self.installdir = os.path.normpath(self.main.archi_info.ma5dir + "/tools/HEPTopTagger/") + self.toolsdir = os.path.normpath(self.main.archi_info.ma5dir + "/tools") + self.tmpdir = self.main.session_info.tmpdir + self.downloaddir = self.main.session_info.downloaddir + self.untardir = os.path.normpath(self.tmpdir + "/MA5_heptoptagger/") + self.github_repo = "https://api.github.com/repos/MadAnalysis/HEPTopTagger/releases/latest" + self.meta = {} + + def Detect(self): + if not os.path.isdir(self.toolsdir): + logging.getLogger("MA5").debug("The folder '" + self.toolsdir + "' is not found") + return False + if not os.path.isdir(self.installdir): + logging.getLogger("MA5").debug("The folder " + self.installdir + "' is not found") + return False + return True + + def Remove(self, question=True): + from madanalysis.IOinterface.folder_writer import FolderWriter + return FolderWriter.RemoveDirectory(self.installdir, question) + + def CreatePackageFolder(self): + if not InstallService.create_tools_folder(self.toolsdir): + return False + if not InstallService.create_package_folder(self.toolsdir, "HEPTopTagger"): + return False + return True + + def CreateTmpFolder(self): + ok = InstallService.prepare_tmp(self.untardir, self.downloaddir) + if ok: + self.tmpdir = self.untardir + return ok + + def Download(self): + # Checking the link to GitHub + theCommands=['curl', '-s', self.github_repo] + logging.getLogger('MA5').debug('shell command: '+' '.join(theCommands)) + ok, out = ShellCommand.ExecuteWithLog( + theCommands, os.path.normpath(self.installdir + "/github_meta.log"), ".", silent=False + ) + if not ok: + return False + + self.meta = json.loads(out) + + # Downloading the package from GitHub + logging.getLogger('MA5').debug(f" -> HEPTopTagger {self.meta['tag_name']}") + logging.getLogger('MA5').debug(f" -> Published at {self.meta['published_at']}") + theCommands = [ + 'curl', '-s', "-L", "--create-dirs", "-o", + os.path.join(self.downloaddir, self.meta['tag_name'] + ".tar.gz"), + self.meta["tarball_url"] + ] + ok, out = ShellCommand.ExecuteWithLog( + theCommands, os.path.normpath(self.installdir + "/curl.log"), ".", silent=False + ) + logging.getLogger('MA5').debug(f"is download ok? {ok} :: {out}") + + return ok + + def Unpack(self): + # Logname + logname = os.path.normpath(self.installdir + "/unpack.log") + # Unpacking the tarball + logging.getLogger("MA5").debug(f"Unpack : {self.meta['tag_name']+'.tar.gz'}") + ok, packagedir = InstallService.untar( + logname, self.downloaddir, self.installdir, self.meta['tag_name']+'.tar.gz' + ) + logging.getLogger("MA5").debug(f"Unpack : {packagedir} is ok? {ok}") + if not ok: + return False + + # Checking where all files are + from glob import glob + content = glob(self.installdir + "/*") + if len(content) == 0: + return False + + found = False + main_folder = None + for file in content: + if os.path.isdir(file) and "MadAnalysis-HEPTopTagger" in file: + content = glob(os.path.join(file, "*")) + found = True + main_folder = file + break + + if not found: + return False + + # Copying all files where relevant + import shutil + for htt_file in content: + logging.getLogger("MA5").debug(f"copy {htt_file} to {self.installdir}") + shutil.copyfile(htt_file, os.path.join(self.installdir, os.path.basename(htt_file))) + + if main_folder is not None: + try: + shutil.rmtree(main_folder, ignore_errors=True) + except Exception as err: + logging.getLogger('MA5').debug(err) + + with open(os.path.join(self.installdir, "metadata.json"), "w") as meta: + json.dump(self.meta, meta, indent=4) + + # Ok: returning the good folder + self.tmpdir = packagedir + return True + + def Check(self): + # Check HTT files + for htt_file in ["HEPTopTagger.hh", "HEPTopTagger.cc"]: + if not os.path.isfile(os.path.join(self.installdir, htt_file)): + logging.getLogger("MA5").error(f"{htt_file} is missing.") + self.display_log() + return False + + return True + + def display_log(self): + logging.getLogger("MA5").error("More details can be found into the log files:") + logging.getLogger("MA5").error(" - " + os.path.normpath(self.installdir + "/github_meta.log")) + logging.getLogger("MA5").error(" - " + os.path.normpath(self.installdir + "/curl.log")) + logging.getLogger("MA5").error(" - " + os.path.normpath(self.installdir + "/unpack.log")) + + def NeedToRestart(self): + return True diff --git a/madanalysis/install/install_manager.py b/madanalysis/install/install_manager.py index 17651f52..de4895e6 100644 --- a/madanalysis/install/install_manager.py +++ b/madanalysis/install/install_manager.py @@ -24,7 +24,6 @@ from __future__ import absolute_import import logging -import sys from string_tools import StringTools from chronometer import Chronometer @@ -49,6 +48,13 @@ def Execute(self, rawpackage): elif package=='fastjet-contrib': from madanalysis.install.install_fastjetcontrib import InstallFastjetContrib installer=InstallFastjetContrib(self.main) + elif package=='heptoptagger': + if self.main.archi_info.has_fastjet and self.main.archi_info.has_fjcontrib: + from madanalysis.install.install_heptoptagger import InstallHEPTopTagger + installer=InstallHEPTopTagger(self.main) + else: + self.logger.error("HEPTopTagger requires FastJet and the FJContrib libraries to be installed. Installation skipped") + return True elif package in ['delphes', 'delphesma5tune']: if self.main.archi_info.has_root: from madanalysis.install.install_delphes import InstallDelphes diff --git a/madanalysis/interpreter/cmd_define.py b/madanalysis/interpreter/cmd_define.py index dc4d3dd7..f796cab4 100644 --- a/madanalysis/interpreter/cmd_define.py +++ b/madanalysis/interpreter/cmd_define.py @@ -47,6 +47,23 @@ def do(self,args): self.main.superfastsim.define(args,self.main.multiparticles) return + # Jet Definition + if args[0] == 'jet_algorithm': + if self.main.mode != MA5RunningType.RECO: + logging.getLogger('MA5').error("Jet algorithms are only available in the RECO mode") + logging.getLogger('MA5').error("Please restart the program with './bin/ma5 -R '") + return + if self.main.fastsim.package != 'fastjet': + logging.getLogger('MA5').error("Jet algorithms requires FastJet as a fastsim package. ") + return + ok = self.main.jet_collection.define(args,self.main.datasets.GetNames()+\ + [self.main.fastsim.clustering.JetID]) + if ok and len(self.main.jet_collection)==1: + # Multi-cluster protection + logging.getLogger('MA5').warning("Constituent-based smearing will be applied.") + self.main.superfastsim.jetrecomode = 'constituents' + return + #Checking argument number if not len(args) > 2: logging.getLogger('MA5').error("wrong number of arguments for the command 'define'.") @@ -136,14 +153,19 @@ def help(help): logging.getLogger('MA5').info(" The corresponding energy scaling function is given by .") logging.getLogger('MA5').info(" The bounds correspond to the domain that scaling function applies (pt > ..., eta < ..., etc.).") # For the future: - # logging.getLogger('MA5').info("") - # logging.getLogger('MA5').info(" Syntax: define scaling for []") - # logging.getLogger('MA5').info(" Define rescaling corrections to apply to a variable "+\ - # "for a reconstructed object .") - # logging.getLogger('MA5').info(" The corresponding scaling function is given by .") - # logging.getLogger('MA5').info(" The bounds correspond to the domain that scaling function applies "+\ - # "(pt > ..., eta < ..., etc.).") - + logging.getLogger('MA5').info("") + logging.getLogger('MA5').info(" Syntax: define scaling for []") + logging.getLogger('MA5').info(" Define rescaling corrections to apply to a variable for a reconstructed object .") + logging.getLogger('MA5').info(" The corresponding scaling function is given by .") + logging.getLogger('MA5').info(" The bounds correspond to the domain that scaling function applies (pt > ..., eta < ..., etc.).") + logging.getLogger('MA5').info("") + algorithms = ['antikt','cambridge', 'genkt','gridjet','kt','genkt', 'cdfjetclu','cdfmidpoint','siscone'] + logging.getLogger('MA5').info(' Syntax: define jet_algorithm ') + logging.getLogger('MA5').info(' - : Name to be assigned to the jet.') + logging.getLogger('MA5').info(' - : Clustering algorithm of the jet. Available algorithms are: ') + logging.getLogger('MA5').info(' '+', '.join(algorithms)) + logging.getLogger('MA5').info(' - : (Optional) depending on the nature of the algorithm.') + logging.getLogger('MA5').info(" it can be radius=0.4, ptmin=20 etc.") def complete(self,text,line,begidx,endidx): @@ -154,7 +176,8 @@ def complete(self,text,line,begidx,endidx): nargs += 1 if nargs==2: - output=['tagger', 'smearer', 'reco_efficiency', "jes", "energy_scaling"] + output=['tagger', 'smearer', 'reco_efficiency', "jes", + "energy_scaling", "scaling", "jet_algorithm"] return self.finalize_complete(text,output) elif nargs==3 or (nargs==5 and args[1] == 'tagger'): diff --git a/madanalysis/interpreter/cmd_display.py b/madanalysis/interpreter/cmd_display.py index 241140a2..ee03cbe4 100644 --- a/madanalysis/interpreter/cmd_display.py +++ b/madanalysis/interpreter/cmd_display.py @@ -151,6 +151,15 @@ def do(self,args): # Checking argument number if len(args)>0 and args[0].lower() in ['tagger','smearer', 'reco_efficiency', 'jes', 'energy_scaling', 'scaling']: return self.main.superfastsim.display(args) + elif len(args)>0 and args[0].lower() in ['jet_algorithm']: + logging.getLogger('MA5').info('* Primary Jet Definition :') + self.main.fastsim.Display() + if len(self.main.jet_collection) > 0: + logging.getLogger('MA5').info(' '+'-'*20) + logging.getLogger('MA5').info('* Other Jet Definitions: ') + return self.main.jet_collection.Display() + else: + return elif len(args)==1: return self.do_other(args[0]) elif len(args)==5 or len(args)==4: @@ -203,7 +212,7 @@ def complete_name(self,text,object,variable): # Only object name if variable==None: - output = ["main","selection","tagger","smearer", 'reco_efficiency', 'jes', 'energy_scaling', 'scaling'] + output = ["main","selection","tagger","smearer", 'reco_efficiency', 'jes', 'energy_scaling', 'scaling', 'jet_algorithm'] output.extend(self.main.datasets.GetNames()) output.extend(self.main.multiparticles.GetNames()) output.extend(self.main.regions.GetNames()) diff --git a/madanalysis/interpreter/cmd_import.py b/madanalysis/interpreter/cmd_import.py index e98698b3..d03af2a2 100644 --- a/madanalysis/interpreter/cmd_import.py +++ b/madanalysis/interpreter/cmd_import.py @@ -303,6 +303,11 @@ def extract(self,dirname,layout): def ImportDataset(self,filename,name): + # Dont allow usage of same identifier for jets and samples + if name in self.main.jet_collection.GetNames(): + self.logger.error(str(name)+" has been used as a jet identifier") + return + # Creating dataset if not exist newdataset=False if not self.main.datasets.Find(name): diff --git a/madanalysis/interpreter/cmd_install.py b/madanalysis/interpreter/cmd_install.py index 9168bd29..7c25d83f 100644 --- a/madanalysis/interpreter/cmd_install.py +++ b/madanalysis/interpreter/cmd_install.py @@ -124,6 +124,8 @@ def UpdatePaths(): if installer.Execute('fastjet')==False: return False return installer.Execute('fastjet-contrib') + elif args[0]=='HEPTopTagger': + return installer.Execute('HEPTopTagger') elif args[0]=='gnuplot': return installer.Execute('gnuplot') elif args[0]=='matplotlib': @@ -224,7 +226,7 @@ def complete(self,text,args,begidx,endidx): else: output = ["samples","zlib","fastjet", "delphes", "delphesMA5tune",\ "gnuplot", "matplotlib", "root" , "numpy", "PAD", "PADForMA5tune",\ - "PADForSFS", "pyhf"] + "PADForSFS", "pyhf", "HEPTopTagger"] return self.finalize_complete(text,output) diff --git a/madanalysis/interpreter/cmd_remove.py b/madanalysis/interpreter/cmd_remove.py index 57ef8cf5..2abc948e 100644 --- a/madanalysis/interpreter/cmd_remove.py +++ b/madanalysis/interpreter/cmd_remove.py @@ -53,7 +53,12 @@ def remove_input(self,name): logging.getLogger('MA5').error(" - "+self.main.selection[item].GetStringDisplay()) logging.getLogger('MA5').error("Please remove these plots/cuts before removing the Particle/Multiparticle "+ name +".") return - + + # Jet collection removal + if name in self.main.jet_collection.GetNames(): + self.main.jet_collection.Delete(name) + return + # No object found logging.getLogger('MA5').error("No object called '"+name+"' found.") @@ -97,6 +102,7 @@ def complete(self,text,line,begidx,endidx): output = [ "selection["+str(ind+1)+"]" \ for ind in range(0,len(self.main.selection)) ] output.extend(self.main.datasets.GetNames()) + output.extend(self.main.jet_collection.GetNames()) output.extend(self.main.multiparticles.GetNames()) # Cannot possible to remove invis diff --git a/madanalysis/interpreter/cmd_set.py b/madanalysis/interpreter/cmd_set.py index 8bb1fb76..fc1eef6c 100644 --- a/madanalysis/interpreter/cmd_set.py +++ b/madanalysis/interpreter/cmd_set.py @@ -80,6 +80,11 @@ def do_other(self,object,operator,value): self.main.datasets.Get(objs[0]).user_SetParameter(objs[1],theValue,theValue2,theValue3) return + # Set the properties of jet object within the jet collection if given jetID exists. + elif objs[0] in self.main.jet_collection.GetNames(): + self.main.jet_collection.Set(objs,value) + return + # Anything else else : logging.getLogger('MA5').error("no object called '"+objs[0]+"' is found") @@ -98,6 +103,7 @@ def do_main(self,args): object = args[0] # object = object.lower() object = object.replace('fastsim.bjet_id.','fastsim.bjet_idXXX') + object = object.replace('fastsim.cjet_id.','fastsim.cjet_idXXX') object = object.replace('fastsim.tau_id.','fastsim.tau_idXXX') objs = object.split('.') for i in range(len(objs)): @@ -143,7 +149,11 @@ def do_main(self,args): self.main.merging.user_SetParameter(objs[2],args[2],self.main.mode,self.main.archi_info.has_fastjet) elif len(objs)==3 and objs[0].lower()=='main' and objs[1].lower()=='fastsim': if objs[2] == 'jetrecomode': - if args[2] in ['jets', 'constituents']: + # Multi-cluster protection + if len(self.main.jet_collection)>0 and args[2].lower() == 'jets': + logging.getLogger('MA5').error("Jet smearing can not be based on clustered jets when multi-cluster is in effect.") + logging.getLogger('MA5').error("Jet smearing will be based on constituents") + elif args[2] in ['jets', 'constituents']: self.main.superfastsim.jetrecomode = args[2] else: logging.getLogger('MA5').error("Jet smearing can only be based on the jet ('jets') or "+\ @@ -154,23 +164,37 @@ def do_main(self,args): self.main.superfastsim.propagator = True except: logging.getLogger('MA5').error("The magnetic field has to be numerical (in Tesla).") + + # @JACK: Tracker radius & halflength are ineffective atm elif objs[2] == 'tracker_radius': try: self.main.superfastsim.radius = float(args[2]) self.main.superfastsim.propagator = True except: logging.getLogger('MA5').error("The tracker cylinder radius has to be numerical (in meters).") + elif objs[2] == 'half_length': try: self.main.superfastsim.half_length = float(args[2]) self.main.superfastsim.propagator = True except: logging.getLogger('MA5').error("The tracker cylinder half length needs to numerical (in meters).") + elif objs[2] == 'particle_propagator': if args[2] in ['on', 'off']: self.main.superfastsim.propagator = (args[2]=='on') else: logging.getLogger('MA5').error("Particle propagation can be either on or off (default: off).") + + elif objs[2].lower() == 'jetid': + if self.main.fastsim.package == 'fastjet': + if args[2] not in self.main.jet_collection.GetNames(): + self.main.fastsim.clustering.JetID = args[2] + else: + logging.getLogger('MA5').error("Jet ID '"+args[2]+"' is already in use.") + else: + logging.getLogger('MA5').error("Jet ID is only available while fastjet package is in use.") + elif objs[2] in [x+"_isocone_radius" for x in ["electron","muon","track","photon"]]: tmp = [] for x in args[2:]: @@ -346,6 +370,7 @@ def complete_name(self,text,object,variable,withValue): if variable==None: output = ["main"] output.extend(self.main.datasets.GetNames()) + output.extend(self.main.jet_collection.GetNames()) output.extend( [ "selection["+str(ind+1)+"]" \ for ind in \ range(0,len(self.main.selection)) ] ) @@ -398,6 +423,15 @@ def complete_name(self,text,object,variable,withValue): else: return self.finalize_complete(text,self.main.datasets.Get(object).user_GetValues(variable)) + # Jet Collection object + elif object in self.main.jet_collection.GetNames(): + if not withValue: + output = [ object+"."+ item \ + for item in \ + self.main.jet_collection.Get(object).user_GetParameters() ] + return self.finalize_complete(text,output) + return self.finalize_complete(text,self.main.jet_collection.Get(object).user_GetValues(variable)) + # Other cases else: return [] diff --git a/madanalysis/interpreter/cmd_submit.py b/madanalysis/interpreter/cmd_submit.py index bb19f3ca..4d35beb6 100644 --- a/madanalysis/interpreter/cmd_submit.py +++ b/madanalysis/interpreter/cmd_submit.py @@ -1,84 +1,89 @@ ################################################################################ -# +# # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: -# +# # This file is part of MadAnalysis 5. # Official website: -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see -# +# ################################################################################ from __future__ import absolute_import -from madanalysis.interpreter.cmd_base import CmdBase -from madanalysis.IOinterface.job_writer import JobWriter -from madanalysis.IOinterface.layout_writer import LayoutWriter -from madanalysis.IOinterface.job_reader import JobReader -from madanalysis.IOinterface.folder_writer import FolderWriter -from madanalysis.enumeration.report_format_type import ReportFormatType -from madanalysis.layout.layout import Layout -from madanalysis.install.install_manager import InstallManager -from madanalysis.install.detector_manager import DetectorManager -from madanalysis.misc.run_recast import RunRecast -from madanalysis.IOinterface.delphescard_checker import DelphesCardChecker - - -from chronometer import Chronometer -from string_tools import StringTools +from madanalysis.interpreter.cmd_base import CmdBase +from madanalysis.IOinterface.job_writer import JobWriter +from madanalysis.IOinterface.layout_writer import LayoutWriter +from madanalysis.IOinterface.job_reader import JobReader +from madanalysis.IOinterface.folder_writer import FolderWriter +from madanalysis.enumeration.report_format_type import ReportFormatType +from madanalysis.layout.layout import Layout +from madanalysis.install.install_manager import InstallManager +from madanalysis.install.detector_manager import DetectorManager +from madanalysis.misc.run_recast import RunRecast +from madanalysis.IOinterface.delphescard_checker import DelphesCardChecker + + +from chronometer import Chronometer +from string_tools import StringTools import logging import glob import os import shutil from six.moves import range + class CmdSubmit(CmdBase): """Command SUBMIT""" - def __init__(self,main,resubmit=False): - self.resubmit=resubmit + def __init__(self, main, resubmit=False): + self.resubmit = resubmit if not resubmit: - CmdBase.__init__(self,main,"submit") + CmdBase.__init__(self, main, "submit") else: - CmdBase.__init__(self,main,"resubmit") - self.forbiddenpaths=[] - self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir+'/lib')) - self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir+'/bin')) - self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir+'/madanalysis')) - - - def do(self,args,history): + CmdBase.__init__(self, main, "resubmit") + self.forbiddenpaths = [] + self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir + "/lib")) + self.forbiddenpaths.append(os.path.normpath(self.main.archi_info.ma5dir + "/bin")) + self.forbiddenpaths.append( + os.path.normpath(self.main.archi_info.ma5dir + "/madanalysis") + ) + + def do(self, args, history): if not self.resubmit: - return self.do_submit(args,history) + return self.do_submit(args, history) else: - return self.do_resubmit(args,history) - + return self.do_resubmit(args, history) - def do_resubmit(self,args,history): + def do_resubmit(self, args, history): # Start time chrono = Chronometer() chrono.Start() # Checking argument number - if len(args)!=0: - self.logger.warning("Command 'resubmit' takes no argument. Any argument will be skipped.") + if len(args) != 0: + self.logger.warning( + "Command 'resubmit' takes no argument. Any argument will be skipped." + ) # Checking presence of a valid job if self.main.lastjob_name == "": - self.logger.error("an analysis must be defined and ran before using the resubmit command.") + self.logger.error( + "an analysis must be defined and ran before using the resubmit command." + ) return False self.main.lastjob_status = False @@ -88,20 +93,28 @@ def do_resubmit(self,args,history): # Look for the last submit and resubmit last_submit_cmd = -1 - for i in range(len(history)-1): # Last history entry should be resubmit - if history[i].startswith('submit') or history[i].startswith('resubmit'): + for i in range(len(history) - 1): # Last history entry should be resubmit + if history[i].startswith("submit") or history[i].startswith("resubmit"): last_submit_cmd = i newhistory = [] - if last_submit_cmd==-1: + if last_submit_cmd == -1: ToReAnalyze = True else: - for i in range(last_submit_cmd+1,len(history)): + for i in range(last_submit_cmd + 1, len(history)): newhistory.append(history[i]) - ReAnalyzeCmdList = ['plot','select','reject','set main.clustering', - 'set main.merging', 'define', 'set main.recast', - 'import', 'set main.isolation'] + ReAnalyzeCmdList = [ + "plot", + "select", + "reject", + "set main.clustering", + "set main.merging", + "define", + "set main.recast", + "import", + "set main.isolation", + ] # Determining if we have to resubmit the job for cmd in newhistory: @@ -110,14 +123,14 @@ def do_resubmit(self,args,history): words = cmd.split() # Creating a line with one whitespace between each word - cmd2 = '' + cmd2 = "" for word in words: - if word!='': - cmd2+=word+' ' + if word != "": + cmd2 += word + " " # Looping over patterns for pattern in ReAnalyzeCmdList: - if cmd2.startswith(pattern): + if cmd2.startswith(pattern): ToReAnalyze = True break @@ -126,17 +139,21 @@ def do_resubmit(self,args,history): break if ToReAnalyze: - self.logger.info(" Creating the new histograms and/or applying the new cuts...") + self.logger.info( + " Creating the new histograms and/or applying the new cuts..." + ) # Submission - if not self.submit(self.main.lastjob_name,history): + if not self.submit(self.main.lastjob_name, history): return self.logger.info(" Updating the reports...") else: - self.logger.info(" No new histogram / cut to account for. Updating the reports...") + self.logger.info( + " No new histogram / cut to account for. Updating the reports..." + ) # Reading info from job output layout = Layout(self.main) - if not self.extract(self.main.lastjob_name,layout): + if not self.extract(self.main.lastjob_name, layout): return # Status = GOOD @@ -145,49 +162,55 @@ def do_resubmit(self,args,history): layout.Initialize() # Creating the reports - self.CreateReports([self.main.lastjob_name],history,layout) + self.CreateReports([self.main.lastjob_name], history, layout) - # End of time + # End of time chrono.Stop() - self.logger.info(" Well done! Elapsed time = "+chrono.Display()) + self.logger.info(" Well done! Elapsed time = " + chrono.Display()) - def do_submit(self,args,history): + def do_submit(self, args, history): # Start time chrono = Chronometer() chrono.Start() # No arguments - if len(args)==0: + if len(args) == 0: dirlist = os.listdir(self.main.currentdir) ii = 0 - while ('ANALYSIS_'+str(ii) in dirlist): - ii = ii+1 - args.append(self.main.currentdir+'/ANALYSIS_'+str(ii)) + while "ANALYSIS_" + str(ii) in dirlist: + ii = ii + 1 + args.append(self.main.currentdir + "/ANALYSIS_" + str(ii)) # Checking argument number - if len(args)>1: - self.logger.error("wrong number of arguments for the command 'submit'.") - self.help() - return + if len(args) > 1: + self.logger.error("wrong number of arguments for the command 'submit'.") + self.help() + return # Checking if a dataset has been defined - if len(self.main.datasets)==0: - self.logger.error("no dataset found; please define a dataset (via the command import).") + if len(self.main.datasets) == 0: + self.logger.error( + "no dataset found; please define a dataset (via the command import)." + ) self.logger.error("job submission aborted.") return # Treat the filename filename = os.path.expanduser(args[0]) - if not filename.startswith('/'): + if not filename.startswith("/"): filename = self.main.currentdir + "/" + filename filename = os.path.normpath(filename) # Checking folder if filename in self.forbiddenpaths: - self.logger.error("the folder '"+filename+"' is a MadAnalysis folder. " + \ - "You cannot overwrite it. Please choose another folder.") + self.logger.error( + "the folder '" + + filename + + "' is a MadAnalysis folder. " + + "You cannot overwrite it. Please choose another folder." + ) return # Saving job name as global variable @@ -195,14 +218,14 @@ def do_submit(self,args,history): self.main.lastjob_status = False # Submission - self.logger.debug('Launching SampleAnalyzer ...') - if not self.submit(filename,history): + self.logger.debug("Launching SampleAnalyzer ...") + if not self.submit(filename, history): return # Reading info from job output - self.logger.debug('Go back to the Python interface ...') + self.logger.debug("Go back to the Python interface ...") layout = Layout(self.main) - if not self.extract(filename,layout): + if not self.extract(filename, layout): return # Status = GOOD @@ -213,34 +236,35 @@ def do_submit(self,args,history): layout.Initialize() # Creating the reports - if not self.main.recasting.status=="on": - self.CreateReports(args,history,layout) + if not self.main.recasting.status == "on": + self.CreateReports(args, history, layout) - # End of time + # End of time chrono.Stop() - self.logger.info(" Well done! Elapsed time = "+chrono.Display()) - + self.logger.info(" Well done! Elapsed time = " + chrono.Display()) # Generating the reports - def CreateReports(self,args,history,layout): + def CreateReports(self, args, history, layout): output_paths = [] - modes = [] + modes = [] # Getting output filename for histo folder - i=0 - while(os.path.isdir(args[0]+"/Output/Histos/MadAnalysis5job_"+str(i))): - i+=1 - - histopath = os.path.expanduser(args[0]+'/Output/Histos/MadAnalysis5job_'+str(i)) - if not histopath.startswith('/'): + i = 0 + while os.path.isdir(args[0] + "/Output/Histos/MadAnalysis5job_" + str(i)): + i += 1 + + histopath = os.path.expanduser( + args[0] + "/Output/Histos/MadAnalysis5job_" + str(i) + ) + if not histopath.startswith("/"): histopath = self.main.currentdir + "/" + histopath histopath = os.path.normpath(histopath) # Getting output filename for HTML report - htmlpath = os.path.expanduser(args[0]+'/Output/HTML/MadAnalysis5job_'+str(i)) - if not htmlpath.startswith('/'): + htmlpath = os.path.expanduser(args[0] + "/Output/HTML/MadAnalysis5job_" + str(i)) + if not htmlpath.startswith("/"): htmlpath = self.main.currentdir + "/" + htmlpath htmlpath = os.path.normpath(htmlpath) output_paths.append(htmlpath) @@ -248,8 +272,10 @@ def CreateReports(self,args,history,layout): # Getting output filename for PDF report if self.main.session_info.has_pdflatex: - pdfpath = os.path.expanduser(args[0]+'/Output/PDF/MadAnalysis5job_'+str(i)) - if not pdfpath.startswith('/'): + pdfpath = os.path.expanduser( + args[0] + "/Output/PDF/MadAnalysis5job_" + str(i) + ) + if not pdfpath.startswith("/"): pdfpath = self.main.currentdir + "/" + pdfpath pdfpath = os.path.normpath(pdfpath) output_paths.append(pdfpath) @@ -257,25 +283,27 @@ def CreateReports(self,args,history,layout): # Getting output filename for DVI report if self.main.session_info.has_latex: - dvipath = os.path.expanduser(args[0]+'/Output/DVI/MadAnalysis5job_'+str(i)) - if not dvipath.startswith('/'): + dvipath = os.path.expanduser( + args[0] + "/Output/DVI/MadAnalysis5job_" + str(i) + ) + if not dvipath.startswith("/"): dvipath = self.main.currentdir + "/" + dvipath dvipath = os.path.normpath(dvipath) output_paths.append(dvipath) modes.append(ReportFormatType.LATEX) # Creating folders - if not layout.CreateFolders(histopath,output_paths,modes): + if not layout.CreateFolders(histopath, output_paths, modes): return # Draw plots self.logger.info(" Generating all plots ...") - if not layout.DoPlots(histopath,modes,output_paths): + if not layout.DoPlots(histopath, modes, output_paths): return # Generating the HTML report self.logger.info(" Generating the HMTL report ...") - layout.GenerateReport(history,htmlpath,ReportFormatType.HTML) + layout.GenerateReport(history, htmlpath, ReportFormatType.HTML) self.logger.info(" -> To open this HTML report, please type 'open'.") # PDF report @@ -283,15 +311,17 @@ def CreateReports(self,args,history,layout): # Generating the PDF report self.logger.info(" Generating the PDF report ...") - layout.GenerateReport(history,pdfpath,ReportFormatType.PDFLATEX) - layout.CompileReport(ReportFormatType.PDFLATEX,pdfpath) + layout.GenerateReport(history, pdfpath, ReportFormatType.PDFLATEX) + layout.CompileReport(ReportFormatType.PDFLATEX, pdfpath) # Displaying message for opening PDF if self.main.currentdir in pdfpath: - pdfpath = pdfpath[len(self.main.currentdir):] - if pdfpath[0]=='/': - pdfpath=pdfpath[1:] - self.logger.info(" -> To open this PDF report, please type 'open " + pdfpath + "'.") + pdfpath = pdfpath[len(self.main.currentdir) :] + if pdfpath[0] == "/": + pdfpath = pdfpath[1:] + self.logger.info( + " -> To open this PDF report, please type 'open " + pdfpath + "'." + ) else: self.logger.warning("pdflatex not installed -> no PDF report.") @@ -301,59 +331,69 @@ def CreateReports(self,args,history,layout): # Warning message for DVI -> PDF self.logger.info(" Generating the DVI report ...") -# if not self.main.session_info.has_dvipdf: -# self.logger.warning("dvipdf not installed -> the DVI report will not be converted to a PDF file.") + # if not self.main.session_info.has_dvipdf: + # self.logger.warning("dvipdf not installed -> the DVI report will not be converted to a PDF file.") # Generating the DVI report - layout.GenerateReport(history,dvipath,ReportFormatType.LATEX) - layout.CompileReport(ReportFormatType.LATEX,dvipath) + layout.GenerateReport(history, dvipath, ReportFormatType.LATEX) + layout.CompileReport(ReportFormatType.LATEX, dvipath) # Displaying message for opening DVI if self.main.session_info.has_dvipdf: - pdfpath = os.path.expanduser(args[0]+'/Output/DVI/MadAnalysis5job_'+str(i)) + pdfpath = os.path.expanduser( + args[0] + "/Output/DVI/MadAnalysis5job_" + str(i) + ) if self.main.currentdir in pdfpath: - pdfpath = pdfpath[len(self.main.currentdir):] - if pdfpath[0]=='/': - pdfpath=pdfpath[1:] - self.logger.info(" -> To open the corresponding Latex file, please type 'open " + pdfpath + "'.") + pdfpath = pdfpath[len(self.main.currentdir) :] + if pdfpath[0] == "/": + pdfpath = pdfpath[1:] + self.logger.info( + " -> To open the corresponding Latex file, please type 'open " + + pdfpath + + "'." + ) else: self.logger.warning("latex not installed -> no DVI/PDF report.") - - - def submit(self,dirname,history): + def submit(self, dirname, history): # checking if delphes is needed and installing/activating it if relevant detector_handler = DetectorManager(self.main) - if not detector_handler.manage('delphes'): - logging.getLogger('MA5').error('Problem with the handling of delphes/delphesMA5tune') + if not detector_handler.manage("delphes"): + logging.getLogger("MA5").error( + "Problem with the handling of delphes/delphesMA5tune" + ) return False - if not detector_handler.manage('delphesMA5tune'): - logging.getLogger('MA5').error('Problem with the handling of delphes/delphesMA5tune') + if not detector_handler.manage("delphesMA5tune"): + logging.getLogger("MA5").error( + "Problem with the handling of delphes/delphesMA5tune" + ) return False # Initializing the JobWriter - jobber = JobWriter(self.main,dirname,self.resubmit) + jobber = JobWriter(self.main, dirname, self.resubmit) # Writing process if not self.resubmit: - self.logger.info(" Creating folder '"+dirname.split('/')[-1] \ - +"'...") + self.logger.info(" Creating folder '" + dirname.split("/")[-1] + "'...") else: - self.logger.info(" Checking the structure of the folder '"+\ - dirname.split('/')[-1]+"'...") + self.logger.info( + " Checking the structure of the folder '" + + dirname.split("/")[-1] + + "'..." + ) if not jobber.Open(): self.logger.error("job submission aborted.") return False if not self.resubmit: - if self.main.recasting.status != 'on': + if self.main.recasting.status != "on": self.logger.info(" Copying 'SampleAnalyzer' source files...") if not jobber.CopyLHEAnalysis(): self.logger.error(" job submission aborted.") return False - if self.main.recasting.status != 'on' and not jobber.CreateBldDir(): + if self.main.recasting.status != "on" and not jobber.CreateBldDir(): self.logger.error(" job submission aborted.") return False @@ -383,26 +423,31 @@ def submit(self,dirname,history): jobber.WriteDatasetList(item) self.logger.info(" Writing the command line history...") - jobber.WriteHistory(history,self.main.firstdir) + jobber.WriteHistory(history, self.main.firstdir) if self.main.recasting.status == "on": - self.main.recasting.collect_outputs(dirname,self.main.datasets) - self.logger.info(' -> the results can be found in:') - self.logger.info(' '+ dirname + '/Output/SAF/CLs_output_summary.dat') + self.main.recasting.collect_outputs(dirname, self.main.datasets) + self.logger.info(" -> the results can be found in:") + self.logger.info(" " + dirname + "/Output/SAF/CLs_output_summary.dat") for item in self.main.datasets: - self.logger.info(' '+ dirname + '/Output/SAF/'+ item.name + '/CLs_output.dat') + self.logger.info( + " " + dirname + "/Output/SAF/" + item.name + "/CLs_output.dat" + ) else: layouter = LayoutWriter(self.main, dirname) layouter.WriteLayoutConfig() - if not self.main.recasting.status=='on' and not self.resubmit: + if not self.main.recasting.status == "on" and not self.resubmit: self.logger.info(" Creating Makefiles...") if not jobber.WriteMakefiles(): self.logger.error("job submission aborted.") return False # Edit & check the delphes or recasting cards - if self.main.fastsim.package in ["delphes","delphesMA5tune"] and not self.main.recasting.status=='on': - delphesCheck = DelphesCardChecker(dirname,self.main) + if ( + self.main.fastsim.package in ["delphes", "delphesMA5tune"] + and not self.main.recasting.status == "on" + ): + delphesCheck = DelphesCardChecker(dirname, self.main) if not delphesCheck.checkPresenceCard(): self.logger.error("job submission aborted.") return False @@ -414,13 +459,39 @@ def submit(self,dirname,history): self.logger.error("job submission aborted.") return False - if self.resubmit and not self.main.recasting.status=='on': + # @Jack: new setup configuration. In order to run the code in the + # SFS-FastJet mode, the analysis has to be compiled with the + # `-DMA5_FASTJET_MODE` flag. This however needs to be deactivated for + # Delphes-ROOT based analyses. + root_dataset, hepmc_dataset, lhco_dataset = False, False, False + for dataset in self.main.datasets: + for sample in dataset: + if "hepmc" in sample: + hepmc_dataset = True + elif "root" in sample: + root_dataset = True + elif "lhco" in sample: + lhco_dataset = True + # if self.main.fastsim.package in ["delphes","delphesMA5tune"] or root_dataset: + # os.environ["FASTJET_FLAG"] = "" + if self.main.fastsim.package in ["fastjet"] and hepmc_dataset: + if root_dataset and hepmc_dataset: + self.logger.error( + "ROOT input files not allowed for SFS-FastJet based analyses." + ) + return False + # elif self.main.fastsim.package == 'none' and self.main.archi_info.has_fastjet and lhco_dataset: + # os.environ["FASTJET_FLAG"] = "-DMA5_FASTJET_MODE" + if self.main.archi_info.has_fastjet: + os.environ["FASTJET_FLAG"] = "-DMA5_FASTJET_MODE" + + if self.resubmit and not self.main.recasting.status == "on": self.logger.info(" Cleaning 'SampleAnalyzer'...") if not jobber.MrproperJob(): self.logger.error("job submission aborted.") return False - if not self.main.recasting.status=='on': + if not self.main.recasting.status == "on": self.logger.info(" Compiling 'SampleAnalyzer'...") if not jobber.CompileJob(): self.logger.error("job submission aborted.") @@ -432,16 +503,20 @@ def submit(self,dirname,history): return False for item in self.main.datasets: - self.logger.info(" Running 'SampleAnalyzer' over dataset '" - +item.name+"'...") - self.logger.info(" *******************************************************") + self.logger.info( + " Running 'SampleAnalyzer' over dataset '" + item.name + "'..." + ) + self.logger.info( + " *******************************************************" + ) if not jobber.RunJob(item): - self.logger.error("run over '"+item.name+"' aborted.") - self.logger.info(" *******************************************************") + self.logger.error("run over '" + item.name + "' aborted.") + self.logger.info( + " *******************************************************" + ) return True - - def extract(self,dirname,layout): + def extract(self, dirname, layout): self.logger.info(" Checking SampleAnalyzer output...") jobber = JobReader(dirname) if not jobber.CheckDir(): @@ -449,54 +524,58 @@ def extract(self,dirname,layout): return False for item in self.main.datasets: - if self.main.recasting.status=='on': - if not self.main.recasting.CheckFile(dirname,item): + if self.main.recasting.status == "on": + if not self.main.recasting.CheckFile(dirname, item): return False elif not jobber.CheckFile(item): self.logger.error("errors have occured during the analysis.") return False - if self.main.recasting.status!='on': + if self.main.recasting.status != "on": self.logger.info(" Extracting data from the output files...") - for i in range(0,len(self.main.datasets)): + for i in range(0, len(self.main.datasets)): jobber.ExtractGeneral(self.main.datasets[i]) - jobber.ExtractHistos(self.main.datasets[i],layout.plotflow.detail[i]) - jobber.ExtractCuts(self.main.datasets[i],layout.cutflow.detail[i]) + jobber.ExtractHistos(self.main.datasets[i], layout.plotflow.detail[i]) + jobber.ExtractCuts(self.main.datasets[i], layout.cutflow.detail[i]) if self.main.merging.enable: - jobber.ExtractHistos(self.main.datasets[i],layout.merging.detail[i],merging=True) + jobber.ExtractHistos( + self.main.datasets[i], layout.merging.detail[i], merging=True + ) return True - def help(self): if not self.resubmit: self.logger.info(" Syntax: submit ") - self.logger.info(" Performs an analysis over a list of datasets. Output is stored into the directory .") - self.logger.info(" If the optional argument is omitted, MadAnalysis creates a fresh directory automatically.") + self.logger.info( + " Performs an analysis over a list of datasets. Output is stored into the directory ." + ) + self.logger.info( + " If the optional argument is omitted, MadAnalysis creates a fresh directory automatically." + ) self.logger.info(" HTML and PDF reports are automatically created.") else: self.logger.info(" Syntax: resubmit") self.logger.info(" Update of an analysis already performed, if relevant.") self.logger.info(" In all cases, the HTML and PDF reports are regenerated.") + def complete(self, text, line, begidx, endidx): - def complete(self,text,line,begidx,endidx): - - #Resubmission case + # Resubmission case if self.resubmit: - return + return - #Getting back arguments + # Getting back arguments args = line.split() nargs = len(args) if not text: nargs += 1 - #Checking number of arguments - if nargs==2: - output=[] - for file in glob.glob(text+"*"): + # Checking number of arguments + if nargs == 2: + output = [] + for file in glob.glob(text + "*"): if os.path.isdir(file): output.append(file) - return self.finalize_complete(text,output) + return self.finalize_complete(text, output) else: return [] diff --git a/madanalysis/jet_clustering/__init__.py b/madanalysis/jet_clustering/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/madanalysis/jet_clustering/jet_collection.py b/madanalysis/jet_clustering/jet_collection.py new file mode 100644 index 00000000..78b92bc6 --- /dev/null +++ b/madanalysis/jet_clustering/jet_collection.py @@ -0,0 +1,262 @@ +################################################################################ +# +# Copyright (C) 2012-2020 Jack Araz, Eric Conte & Benjamin Fuks +# The MadAnalysis development team, email: +# +# This file is part of MadAnalysis 5. +# Official website: +# +# MadAnalysis 5 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MadAnalysis 5 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MadAnalysis 5. If not, see +# +################################################################################ + + +from __future__ import absolute_import +from madanalysis.jet_clustering.jet_configuration import JetConfiguration +from collections import OrderedDict +from six.moves import range +import logging + +from typing import Sequence, Text + + +class JetCollection: + """ + Holds a collection of jets. This module is separate from the original jet clustering + interface shipped with MadAnalysis5. This module can be activated using following command + + .. code-block:: + + ma5> define jet_algorithm my_jet antikt radius=0.5 + + where `my_jet` is a user-defined jet identifier, `antikt` is the algorithm to be used which + can be choosen from `antikt`, `cambridge`, `genkt`, `kt`, `gridjet`, `cdfjetclu`, `cdfmidpoint`, + and `siscone`. The rest of the arguments are optional. In this case, default parameters are + choosen. Each algorithm has its own unique set of parameters: + + | Algorithm | Parameters & Default values | + |:---------------------:|------------------------------------------------------------------------------------| + | `antikt`, `cambridge` | `radius=0.4`, `ptmin=5.` | + | `genkt` | `radius=0.4`, `ptmin=5.`, `exclusive=False`, `p=-1` | + | `kt` | `radius=0.4`, `ptmin=5.`, `exclusive=False` | + | `gridjet` | `ymax=3.`, `ptmin=5.` | + | `cdfjetclu` | `radius=0.4`, `ptmin=5.`, `overlap=0.5`, `seed=1.`, `iratch=0.` | + | `cdfmidpoint` | `radius=0.4`, `ptmin=5.`, `overlap=0.5`, `seed=1.`, `iratch=0.`, `areafraction=1.` | + | `siscone` | `radius=0.4`, `ptmin=5.`, `overlap=0.5`, `input_ptmin=5.`, `npassmax=1.` | + | `VariableR` | `rho=2000`, `minR=0`, `maxR=2`, `ptmin=20` `exclusive=False` `clustertype=CALIKE` `strategy=Best` | + + It is also possible to modify the entry after defining it + + .. code-block:: + + ma5> define jet_algorithm my_jet cambridge + ma5> set my_jet.ptmin = 200. + ma5> set my_jet.radius = 0.8 + + Note that as soon as a `jet_algorithm` is defined, MadAnalysis5 automatically switches the SFS module + to its constituent-smearing mode (see the [SFS manual](https://arxiv.org/abs/2006.09387) for more infomation). + The command `set my_jet.+tab` will display all options available for that particular algorithm. + + It is possible to display all jets defined in the current session by typing the command `display jet_algorithm`: + + .. code-block:: + + $ ./bin/ma5 -R + ma5>set main.fastsim.package = fastjet + ma5>define jet_algorithm my_jet cdfmidpoint + ma5>display jet_algorithm + MA5: * Primary Jet Definition : + MA5: fast-simulation package : fastjet + MA5: clustering algorithm : antikt + MA5: + Jet ID : Ma5Jet + MA5: + cone radius = 0.4 + MA5: + PT min (GeV) for produced jets = 5.0 + MA5: + exclusive identification = true + MA5: + b-jet identification: + MA5: + DeltaR matching = 0.5 + MA5: + exclusive algo = true + MA5: + id efficiency = 1.0 + MA5: + mis-id efficiency (c-quark) = 0.0 + MA5: + mis-id efficiency (light quarks) = 0.0 + MA5: + hadronic-tau identification: + MA5: + id efficiency = 1.0 + MA5: + mis-id efficiency (light quarks) = 0.0 + MA5: -------------------- + MA5: * Other Jet Definitions: + MA5: 1. Jet ID = my_jet + MA5: - algorithm : cdfmidpoint + MA5: - radius : 0.4 + MA5: - ptmin : 5.0 + MA5: - overlap : 0.5 + MA5: - seed : 1.0 + MA5: - iratch : 0.0 + MA5: - areafraction : 1.0 + + What is called the primary jet definition is that defined through the original syntax of MadAnalysis5. + As nothing was specified, the default `antikt` configuration is used. For more info on how to define + this primary jet, we refer to [arXiv:2006.09387](https://arxiv.org/abs/2006.09387). The block with the + other jet definitions include all those jets defined via a usage of the `jet_algorithm` keyword. + + To remove a `jet_algorithm` definition one can use `remove my_jet` command. + """ + + def __init__(self): + self.logger = logging.getLogger("MA5") + self.collection = OrderedDict() + self.algorithms = JetConfiguration().GetJetAlgorithms() + + def help(self): + self.logger.error(" * define jet_algorithm ") + self.logger.error(" - : Name to be assigned to the jet.") + self.logger.error( + " - : Clustering algorithm of the jet. Available algorithms are: " + ) + self.logger.error(" " + ", ".join(self.algorithms)) + self.logger.error( + " - : (Optional) depending on the nature of the algorithm." + ) + self.logger.error( + " it can be radius=0.4, ptmin=20, etc." + ) + + def define(self, args: Sequence[Text], dataset_names: Sequence = None) -> bool: + """ + Definition of a new jet + + Parameters + ---------- + args : Sequence[Text] + input arguments: + args[0] -> jet_algorithm + args[1] -> JetID + args[2] -> jet algorithm + args[3:] -> options: no need to cherry pick them only the relevant ones will be used. + dataset_names : Sequence + names for the datasets and primary jet to avoid overlaps + + Returns + ------- + bool: + if true new jet has been successfully created, if false not. + """ + + if dataset_names is None: + dataset_names = [] + + if len(args) < 3: + self.logger.error("Invalid syntax! Correct syntax is as follows:") + self.help() + return False + + if args[2] not in self.algorithms: + self.logger.error("Clustering algorithm '" + args[2] + "' does not exist.") + self.logger.error( + "Available algorithms are : " + ", ".join(self.algorithms) + ) + return False + + if args[1] in dataset_names + list(self.collection.keys()): + self.logger.error( + args[1] + " has been used as a dataset or jet identifier." + ) + if args[1] in self.collection.keys(): + self.logger.error( + "To modify clustering properties please use 'set' command." + ) + return False + + JetID = args[1] + algorithm = args[2] + + # remove commas from options + chunks = args[3:] + for i in range(len([x for x in chunks if x == ","])): + chunks.remove(",") + + # Decode keyword arguments + chunks = [chunks[x : x + 3] for x in range(0, len(chunks), 3)] + if any([len(x) != 3 for x in chunks]) or any([("=" != x[1]) for x in chunks]): + self.logger.error("Invalid syntax!") + self.help() + return False + + # Extract options + options = {} + for item in chunks: + try: + if item[0] == "exclusive": + if item[2].lower() in ["true", "t"]: + options[item[0]] = True + elif item[2].lower() in ["false", "f"]: + options[item[0]] = False + else: + raise ValueError("Exclusive can only be True or False.") + elif item[0] == "strategy" and algorithm == "VariableR": + strategy = ["Best", "N2Tiled", "N2Plain", "NNH", "Native"] + if item[2] in strategy: + options[item[0]] = item[2] + else: + self.logger.error(f"Invalid strategy: {item[2]}") + self.logger.error("Available types are: " + ", ".join(strategy)) + elif item[0] == "clustertype" and algorithm == "VariableR": + ctype = ["CALIKE", "KTLIKE", "AKTLIKE"] + if item[2] in ctype: + options[item[0]] = item[2] + else: + self.logger.error(f"Invalid cluster type: {item[2]}") + self.logger.error("Available types are: " + ", ".join(ctype)) + else: + options[item[0]] = float(item[2]) + except ValueError as err: + if item[0] == "exclusive": + self.logger.error("Invalid syntax! " + str(err)) + else: + self.logger.error( + "Invalid syntax! " + + item[0] + + " requires to have a float value." + ) + return False + + self.collection[JetID] = JetConfiguration( + JetID=JetID, algorithm=algorithm, options=options + ) + return True + + def Set(self, obj, value): + if len(obj) == 2: + self.collection[obj[0]].user_SetParameter(obj[1], value) + else: + self.logger.error("Invalid syntax!") + return + + def Delete(self, JetID): + if JetID in self.collection.keys(): + self.collection.pop(JetID) + else: + self.logger.error(JetID + " does not exist.") + + def Display(self): + for ix, (key, item) in enumerate(self.collection.items()): + self.logger.info(" " + str(ix + 1) + ". Jet ID = " + key) + item.Display() + + def __len__(self): + return len(self.collection.keys()) + + def GetNames(self): + return list(self.collection.keys()) + + def Get(self, JetID): + return self.collection[JetID] diff --git a/madanalysis/jet_clustering/jet_configuration.py b/madanalysis/jet_clustering/jet_configuration.py new file mode 100644 index 00000000..05b29d42 --- /dev/null +++ b/madanalysis/jet_clustering/jet_configuration.py @@ -0,0 +1,217 @@ +################################################################################ +# +# Copyright (C) 2012-2020 Jack Araz, Eric Conte & Benjamin Fuks +# The MadAnalysis development team, email: +# +# This file is part of MadAnalysis 5. +# Official website: +# +# MadAnalysis 5 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MadAnalysis 5 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MadAnalysis 5. If not, see +# +################################################################################ + +from __future__ import absolute_import +import logging +from typing import Text, Dict + +class JetConfiguration: + + userVariables = ['antikt','cambridge', 'genkt','kt', + 'gridjet', 'cdfjetclu','cdfmidpoint','siscone', + "VariableR"] + + def __init__(self,JetID: Text = 'Ma5Jet', algorithm: Text = '', options: Dict = None): + """ + Parameters + ---------- + JetID : STR + Jet identification => event.rec()->jet("MA5Jet") + algorithm: STR + Clustering algorithm + options: DICT + options such as radius, ptmin etc. + + The instance names are used directly in C++ implementation + hence change in instance name will require change in C++ portion + as well. + """ + self.JetID = JetID + + if options is None: + options = {} + + # Main Jet Configurations + if algorithm in self.userVariables: + self.SetDefaultAlgorithm(algorithm, options) + + + def SetDefaultAlgorithm(self,algorithm: Text, options: Dict): + if algorithm == 'antikt' : self.DefaultAntikT(options) + elif algorithm == 'cambridge' : self.DefaultCambridgeAchen(options) + elif algorithm == 'genkt' : self.DefaultGenkT(options) + elif algorithm == 'kt' : self.DefaultkT(options) + elif algorithm == 'gridjet' : self.DefaultGridJet(options) + elif algorithm == 'cdfjetclu' : self.DefaultCDF(options) + elif algorithm == 'cdfmidpoint' : self.DefaultCDFMidPoint(options) + elif algorithm == 'siscone' : self.DefaultSisCone(options) + elif algorithm == 'VariableR' : self.DefaultVariableR(options) + + def DefaultAntikT(self,kwargs: Dict) -> None: + self.algorithm = 'antikt' + self.radius = kwargs.get('radius', 0.4) + self.ptmin = kwargs.get('ptmin', 5.) + + def DefaultkT(self,kwargs: Dict) -> None: + self.algorithm = 'kt' + self.radius = kwargs.get('radius', 0.4) + self.ptmin = kwargs.get('ptmin', 5.) + self.exclusive = kwargs.get('exclusive', False) + + def DefaultCambridgeAchen(self,kwargs: Dict) -> None: + self.algorithm = 'cambridge' + self.radius = kwargs.get('radius', 0.4) + self.ptmin = kwargs.get('ptmin', 5.) + + def DefaultGenkT(self,kwargs: Dict) -> None: + self.algorithm = 'genkt' + self.radius = kwargs.get('radius', 0.4) + self.ptmin = kwargs.get('ptmin', 5.) + self.exclusive = kwargs.get('exclusive', False) + self.p = kwargs.get('p', -1) + + def DefaultGridJet(self,kwargs: Dict) -> None: + self.algorithm = 'gridjet' + self.ymax = kwargs.get('ymax', 3.) + self.ptmin = kwargs.get('ptmin', 5.) + + def DefaultSisCone(self,kwargs: Dict) -> None: + self.algorithm = 'siscone' + self.radius = kwargs.get('radius', 0.4) + self.ptmin = kwargs.get('ptmin', 5.) + self.input_ptmin = kwargs.get('input_ptmin', 5.) + self.overlap = kwargs.get('overlap', 0.5) + self.npassmax = kwargs.get('npassmax', 1.) + + def DefaultCDF(self,kwargs: Dict) -> None: + self.algorithm = 'cdfjetclu' + self.radius = kwargs.get('radius', 0.4) + self.ptmin = kwargs.get('ptmin', 5.) + self.overlap = kwargs.get('overlap', 0.5) + self.seed = kwargs.get('seed', 1.) + self.iratch = kwargs.get('iratch', 0.) + + def DefaultCDFMidPoint(self,kwargs: Dict) -> None: + self.algorithm = 'cdfmidpoint' + self.radius = kwargs.get('radius', 0.4) + self.ptmin = kwargs.get('ptmin', 5.) + self.overlap = kwargs.get('overlap', 0.5) + self.seed = kwargs.get('seed', 1.) + self.iratch = kwargs.get('iratch', 0.) + self.areafraction = kwargs.get('areafraction', 1.) + + def DefaultVariableR(self, kwargs: Dict) -> None: + self.algorithm = 'VariableR' + self.rho = float(kwargs.get('rho', 2000.)) + self.minR = float(kwargs.get('minR', 0.)) + self.maxR = float(kwargs.get('maxR', 2.)) + self.ptmin = float(kwargs.get('ptmin', 20.)) + self.exclusive = bool(kwargs.get('exclusive', False)) + ctype = kwargs.get('clustertype', "AKTLIKE") + self.clustertype = ctype if ctype in ["CALIKE", "KTLIKE", "AKTLIKE"] else "AKTLIKE" + strategy = kwargs.get('strategy', "Best") + self.strategy = strategy if strategy in ["Best", "N2Tiled", "N2Plain", "NNH", "Native"] else "Best" + + def GetJetAlgorithms(self): + return self.userVariables + + def user_GetValues(self, parameter: Text): + if parameter == 'algorithm': + return self.GetJetAlgorithms() + else: + return [str(self.__dict__[parameter])] + + def user_SetParameter(self, parameter: Text, value: Text) -> None: + if parameter not in ['algorithm','JetID']: + if parameter not in self.__dict__.keys(): + logging.getLogger('MA5').error("Option '"+parameter+"' is not available for "+self.algorithm+' algorithm.') + logging.getLogger('MA5').error("Available options are : "+\ + ', '.join([x for x in self.__dict__.keys() if x!='JetID'])) + return + try: + # Except exclusive rets of the parameters are floats!! + if parameter == 'exclusive': + if value.lower() in ['true','t']: + self.exclusive = True + elif value.lower() in ['false','f']: + self.exclusive = False + else: + raise ValueError + elif parameter == "strategy" and self.algorithm == "VariableR": + strategy = ["Best", "N2Tiled", "N2Plain", "NNH", "Native"] + if value in strategy: + self.strategy = value + else: + self.logger.error(f"Invalid strategy: {value}") + self.logger.error("Available types are: " + ", ".join(strategy)) + return + elif parameter == "clustertype" and self.algorithm == "VariableR": + ctype = ["CALIKE", "KTLIKE", "AKTLIKE"] + if value.upper() in ctype: + self.clustertype = value.upper() + else: + self.logger.error(f"Invalid cluster type: {value}") + self.logger.error("Available types are: " + ", ".join(ctype)) + return + else: + tmp = float(value) + self.__dict__[parameter] = tmp + return + except ValueError: + if parameter == 'exclusive': + logging.getLogger('MA5').error("The "+parameter+" value must be True or False.") + else: + logging.getLogger('MA5').error("The "+parameter+" value must be float.") + return + elif parameter == 'algorithm': + if value not in self.userVariables: + logging.getLogger('MA5').error("The clustering algorithm '"+value+"' is not available.") + logging.getLogger('MA5').error("Available algorithms are : "+ ', '.join(self.userVariables)) + return + else: + # Keep all the relevant options for the new algorithm throw the rest + options = {} + previous_keys = list(self.__dict__.keys()) + for key in previous_keys: + if key != 'JetID': + options[key] = self.__dict__[key] + self.__dict__.pop(key) + self.SetDefaultAlgorithm(value,options) + # logging.getLogger('MA5').warning(self.JetID+' has been reset.') + return + + def user_GetParameters(self): + return [x for x in self.__dict__.keys() if x != 'JetID'] + + + def Display(self): + key_order = ['JetID','algorithm']+[x for x in ['radius','ptmin'] if x in self.__dict__.keys()] + key_order += [x for x in self.__dict__.keys() if x not in key_order] + for key in key_order: + if key=='JetID': + continue + else: + logging.getLogger('MA5').info(' - '+key.ljust(15,' ')+' : '+str(self.__dict__[key])) + + + diff --git a/madanalysis/job/job_initialize.py b/madanalysis/job/job_initialize.py index 9906257f..3712fe20 100644 --- a/madanalysis/job/job_initialize.py +++ b/madanalysis/job/job_initialize.py @@ -45,15 +45,6 @@ def WriteJobInitialize(file,main): file.write(' const std::map& parameters)\n') file.write('{\n') - # mcConfig initialization - if main.mode!=MA5RunningType.RECO: - file.write(' // Initializing PhysicsService for MC\n') - file.write(' PHYSICS->mcConfig().Reset();\n\n') - WriteHadronicList(file,main) - file.write('\n') - WriteInvisibleList(file,main) - file.write('\n') - # recConfig initialization if main.mode==MA5RunningType.RECO: file.write(' // Initializing PhysicsService for RECO\n') diff --git a/madanalysis/job/job_tagger_header.py b/madanalysis/job/job_tagger_header.py index 85500b52..b0657f80 100644 --- a/madanalysis/job/job_tagger_header.py +++ b/madanalysis/job/job_tagger_header.py @@ -2,66 +2,99 @@ # # Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks # The MadAnalysis development team, email: -# +# # This file is part of MadAnalysis 5. # Official website: -# +# # MadAnalysis 5 is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # MadAnalysis 5 is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with MadAnalysis 5. If not, see -# +# ################################################################################ +from madanalysis.fastsim.tagger import TaggerStatus class JobTaggerHeader: + + # structure: (true_id, reco_id) : "..." + base = { + (5, 5): lambda tag: f"/// B-jet tagging efficiency (b as b)\nMAfloat32 NewTagger::{tag}_b_tagging_eff(const RecJetFormat &object) const", + (5, 4): lambda tag: f"/// B-jet mistagging rate as a C-jet (b as c)\nMAfloat32 NewTagger::{tag}_b_mistag_c(const RecJetFormat &object) const", + (4, 4): lambda tag: f"/// C-jet tagging efficiency (c as c)\nMAfloat32 NewTagger::{tag}_c_tagging_eff(const RecJetFormat &object) const", + (4, 5): lambda tag: f"/// C-jet mistagging rate as a B-jet (c as b)\nMAfloat32 NewTagger::{tag}_c_mistag_b(const RecJetFormat &object) const", + (21, 5): lambda tag: f"/// Light-Jet mistagging rate as a b-jet (j as b)\nMAfloat32 NewTagger::lightjet_mistag_b_{tag}(const RecJetFormat &object) const", + (21, 4): lambda tag: f"/// Light-Jet mistagging rate as a c jet (j as c)\nMAfloat32 NewTagger::lightjet_mistag_c_{tag}(const RecJetFormat &object) const", + (21, 15): lambda tag: f"/// Light-Jet mistagging rate as a tau (j as ta)\nMAfloat32 NewTagger::lightjet_mistag_tau_{tag}(const RecJetFormat &object) const", + (21, 11): lambda tag: f"/// Light-Jet mistagging rate as an electron (j as e)\nMAfloat32 NewTagger::lightjet_mistag_electron(const RecJetFormat &object) const", + (21, 22): lambda tag: f"/// Light-Jet mistagging rate as a photon (j as photon)\nMAfloat32 NewTagger::lightjet_mistag_photon(const RecJetFormat &object) const", + (15, 15): lambda tag: f"/// Tau tagging efficiency (ta as ta)\nMAfloat32 NewTagger::{tag}_tau_tagging_eff(const RecTauFormat &object) const", + (11, 13): lambda tag: f"/// Electron mistagging rate as a muon (e as mu)\nMAfloat32 NewTagger::electron_mistag_muon(const RecLeptonFormat &object) const", + (11, 22): lambda tag: f"/// Electron mistagging rate as a photon (e as a)\nMAfloat32 NewTagger::electron_mistag_photon(const RecLeptonFormat &object) const", + (11, 21): lambda tag: f"/// Electron mistagging rate as a light jet (e as j)\nMAfloat32 NewTagger::electron_mistag_lightjet(const RecLeptonFormat &object) const", + (13, 11): lambda tag: f"/// Electron mistagging rate as an electron (mu as e)\nMAfloat32 NewTagger::muon_mistag_electron(const RecLeptonFormat &object) const", + (13, 22): lambda tag: f"/// Electron mistagging rate as a photon (mu as a)\nMAfloat32 NewTagger::muon_mistag_photon(const RecLeptonFormat &object) const", + (13, 21): lambda tag: f"/// Electron mistagging rate as a light jet (mu as j)\nMAfloat32 NewTagger::muon_mistag_lightjet(const RecLeptonFormat &object) const", + (22, 11): lambda tag: f"/// Electron mistagging rate as an electron (a as e)\nMAfloat32 NewTagger::photon_mistag_electron(const RecPhotonFormat &object) const", + (22, 13): lambda tag: f"/// Electron mistagging rate as a muon (a as mu)\nMAfloat32 NewTagger::photon_mistag_muon(const RecPhotonFormat &object) const", + (22, 21): lambda tag: f"/// Electron mistagging rate as a light jet (a as j)\nMAfloat32 NewTagger::photon_mistag_lightjet(const RecPhotonFormat &object) const", + } + + ## Initialization def __init__(self, fastsim): self.fastsim = fastsim + self.unique_rules = [] + for key, rule in self.fastsim.tagger.rules.items(): + if (int(rule["id_true"]), int(rule["id_reco"]), TaggerStatus.to_str(rule["tag"])) not in self.unique_rules: + self.unique_rules.append((int(rule["id_true"]), int(rule["id_reco"]), TaggerStatus.to_str(rule["tag"]))) + ## Writing NewTagger.h def WriteNewTaggerHeader(self, file): - file.write('#ifndef NEW_TAGGER_H\n') - file.write('#define NEW_TAGGER_H\n') + file.write('#ifndef MADANALYSIS5_NEW_TAGGER_H\n') + file.write('#define MADANALYSIS5_NEW_TAGGER_H\n') file.write('// SampleAnalyzer headers\n') - file.write('#include "SampleAnalyzer/Commons/DataFormat/EventFormat.h"\n') - file.write('#include "SampleAnalyzer/Commons/DataFormat/SampleFormat.h"\n') - file.write('namespace MA5\n') - file.write('{\n') - file.write(' class NewTagger\n') - file.write(' {\n') + file.write('#include "SampleAnalyzer/Commons/Base/SFSTaggerBase.h"\n') + file.write('namespace MA5 {\n') + file.write(' class NewTagger: public SFSTaggerBase {\n') file.write(' public :\n') - file.write(' /// Constructor without argument\n') - file.write(' NewTagger() \n') - file.write(' {\n') - if not self.fastsim.isNewSmearerOn(): - # If tagger is on but SmearerBase wont be initialized, write SFS reference - # This way whenever SFS is used it will consistently show the ref. - file.write(' INFO <<" <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" << endmsg;\n') - file.write(' INFO <<" <> <>" << endmsg;\n') - file.write(' INFO <<" <> Simplified Fast Detector Simulation in MadAnalysis 5 <>" << endmsg;\n') - file.write(' INFO <<" <> Please cite arXiv:2006.09387 [hep-ph] <>" << endmsg;\n') - file.write(' INFO <<" <> <>" << endmsg;\n') - file.write(' INFO <<" <> https://madanalysis.irmp.ucl.ac.be/wiki/SFS <>" << endmsg;\n') - file.write(' INFO <<" <> <>" << endmsg;\n') - file.write(' INFO <<" <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" << endmsg;\n') - file.write(' }\n\n') - file.write(' /// Destructor\n') - file.write(' virtual ~NewTagger() {}\n\n') - file.write(' /// Tagger execution\n') - file.write(' void Execute(SampleFormat &mySample, EventFormat &myEvent);\n\n') - file.write(' };\n') - file.write('}\n') - file.write('#endif') + file.write(' /// Constructor without argument\n') + file.write(' NewTagger() {}\n\n') + file.write(' /// Destructor\n') + file.write(' virtual ~NewTagger() {}\n\n') + file.write(' void Initialize() {\n') + file.write(' /// @brief Booleans for code efficiency\n') + file.write(' /// Turn on the usage of tau tagging efficiency\n') + file.write(f" _isTauTaggingEffOn = {'true' if (15, 15) in [(x[0], x[1]) for x in self.unique_rules] else 'false'};\n") + file.write(' /// Turn on the usage of jet (mis)tagging efficiency\n') + file.write(f" _isJetTaggingOn = {'true' if any([x in [(x[0], x[1]) for x in self.unique_rules] for x in [(5,5), (4,5), (21,5), (5,4), (4,4), (21,4), (21,15), (21,11), (21,22)]]) else 'false'};\n") + file.write(' /// Turn on the usage of muon (mis)tagging efficiency\n') + file.write(f" _isMuonTaggingOn = {'true' if 13 in [x[0] for x in self.unique_rules] else 'false'};\n") + file.write(' /// Turn on the usage of electron (mis)tagging efficiency\n') + file.write(f" _isElectronTaggingOn = {'true' if 11 in [x[0] for x in self.unique_rules] else 'false'};\n") + file.write(' /// Turn on the usage of photon (mis)tagging efficiency\n') + file.write(f" _isPhotonTaggingOn = {'true' if 22 in [x[0] for x in self.unique_rules] else 'false'};\n") + file.write(' }\n\n') + file.write(' ///==========================================//\n') + file.write(' /// //\n') + file.write(' /// Tagging Efficiencies //\n') + file.write(' /// //\n') + file.write(' ///==========================================//\n\n') + for rule in self.unique_rules: + header = JobTaggerHeader.base[(rule[0], rule[1])](rule[2]).split("\n") + file.write(f"\n\t{header[0]}\n") + file.write(f"\t{header[1].replace('NewTagger::', '')};\n") + file.write(' };\n}\n#endif //MADANALYSIS5_NEW_TAGGER_H') ## efficiencies and bounds @@ -75,11 +108,17 @@ def WriteNewTaggerEfficiencies(self,file): for eff_key in value['efficiencies'].keys(): eff_fnc = value['efficiencies'][eff_key]['function'] eff_bnd = value['efficiencies'][eff_key]['bounds' ] - file.write(eff_fnc.tocpp('MAdouble64', \ - 'eff_'+str(value['id_true']) + '_' + str(value['id_reco'])+'_'+\ - str(eff_key))+'\n') - file.write(eff_bnd.tocpp('MAbool', \ - 'bnd_'+str(value['id_true']) + '_' + str(value['id_reco'])+'_'+\ - str(eff_key)) + '\n') + file.write( + eff_fnc.tocpp( + 'MAdouble64', + f"eff_{value['id_true']}_{value['id_reco']}_{eff_key}_{TaggerStatus.to_str(value['tag'])}" + )+'\n' + ) + file.write( + eff_bnd.tocpp( + 'MAbool', + f"bnd_{value['id_true']}_{value['id_reco']}_{eff_key}_{TaggerStatus.to_str(value['tag'])}" + ) + '\n' + ) file.write('#endif') diff --git a/madanalysis/job/job_tagger_main.py b/madanalysis/job/job_tagger_main.py index aab7b1b5..1b6e9c9d 100644 --- a/madanalysis/job/job_tagger_main.py +++ b/madanalysis/job/job_tagger_main.py @@ -21,8 +21,11 @@ # ################################################################################ +from madanalysis.job.job_tagger_header import JobTaggerHeader +from madanalysis.fastsim.tagger import TaggerStatus class JobTaggerMain: + ## Initialization def __init__(self, fastsim): self.fastsim = fastsim @@ -33,182 +36,36 @@ def WriteNewTaggerSource(self, file): # header file.write('#include "SampleAnalyzer/User/Analyzer/new_tagger.h"\n') file.write('#include "SampleAnalyzer/User/Analyzer/efficiencies.h"\n') - file.write('#include "SampleAnalyzer/Commons/Service/RandomService.h"\n') - file.write('#include "SampleAnalyzer/Commons/Service/PDGService.h"\n') - file.write('#include "SampleAnalyzer/Commons/Service/Physics.h"\n') file.write('using namespace MA5;\n') - file.write('\n') - file.write('void NewTagger::Execute(SampleFormat& sample, ' +\ - 'EventFormat& event)\n{\n') - - # Removal container - file.write(' // Storing the IDs of objects that need to leave a collection\n') - file.write(' std::vector toRemove;\n\n') - - # global event variables - file.write(' // Shortcut for global event variables\n') - file.write(' MAfloat64 & THT = event.rec()->THT();\n') - file.write(' MAfloat64 & Meff = event.rec()->Meff();\n\n') - - # b/c-tagging + jet mistagging as any other object - file.write(' // b/c-tagging + jet-mistagging\n') - file.write(' MAuint32 Ntaus = event.rec()->taus().size();\n') - file.write(' for (MAuint32 i=0; ijets().size(); i++)\n') - file.write(' {\n') - for reco_ID in [ ['5', 'b', 'Btag'], ['4', 'c', 'Ctag'] ]: - pretag='' - for true_ID in [ ['5', 'b', 'true_btag'], ['4', 'c', 'true_ctag'], ['21', 'j', '' ] ]: - if self.HaveRules(true_ID[:-1], reco_ID[:-1]): - file.write(' // We have a true ' + true_ID[-2].replace('j','light') + '-jet: is it ' + reco_ID[-2] + '-tagged?\n') - if true_ID[-1]=='': - file.write(' ' + pretag + '\n') - else: - file.write(' ' + pretag + 'if (event.rec()->jets()[i].' + true_ID[-1]+ '())\n') - file.write(' {\n') - self.PrintTagger(true_ID[:-1], reco_ID[:-1], file,'(&event.rec()->jets()[i])',reco_ID[-1]) - file.write(' }\n\n') - pretag='else ' - file.write(' // We have a '+reco_ID[-2]+'-tagged jet -> moving on with the next jet\n') - file.write(' if (event.rec()->jets()[i].'+reco_ID[-1].lower()+'()) { continue; }\n\n') - # Do we have some mistagging of a jet as any other object - if self.HaveRules(['21', 'j'], ['15', 'ta','11','e','22','a']): - file.write(' // We have a true b/c-jet -> cannot be mistagged\n') - file.write(' if (event.rec()->jets()[i].true_btag() || event.rec()->jets()[i].true_ctag()) { continue; }\n\n') - file.write(' // if not, is it mis-tagged as anything?\n') - file.write(' else\n') - file.write(' {\n') - for reco_ID in [ ['15', 'ta', 'TauMistag'], ['11', 'e', 'Electron'], ['22', 'a', 'Photon'] ]: - # Checking the existence of the related rules - if not self.HaveRules(['21', 'j'], reco_ID[:-1]): - continue - file.write(' {\n') - file.write(' // if not, is it '+reco_ID[2].split('Mistag')[0]+'-tagged?\n') - self.PrintTagger(['21', 'j'], reco_ID[:-1],file,'(&event.rec()->jets()[i])',reco_ID[2]) - file.write(' }\n') - file.write(' }\n') - file.write(' }\n\n') - file.write(' for (MAuint32 i=toRemove.size();i>0;i--)\n') - file.write(' event.rec()->jets().erase(event.rec()->jets().begin() + toRemove[i-1]);\n') - file.write(' toRemove.clear();\n\n') - - # tau-tagging - if self.HaveRules(['15', 'ta'], ['15', 'ta']): - file.write(' // tau-tagging\n') - file.write(' for (MAuint32 i=0; itaus()[i])','Jet') - file.write(' }\n') - file.write(' for (MAuint32 i=toRemove.size();i>0;i--)\n') - file.write(' event.rec()->taus().erase(event.rec()->taus().begin() + toRemove[i-1]);\n') - file.write(' toRemove.clear();\n\n') - - # Muon and electron mis-tagging - for true_ID in [ ['13', 'mu', 'muons'], ['11', 'e', 'electrons'], ['22', 'a', 'photons'] ]: - if self.HaveRules(true_ID[:-1], ['11', 'e', '22', 'a', '21', 'j', '13', 'mu']): - file.write(' // Mistagging of ' + true_ID[-1] + '\n') - file.write(' for (MAuint32 i=0; i' + true_ID[-1] + '().size(); i++)\n') - file.write(' {\n') - self.PrintTagger(true_ID[:-1], ['11', 'e', '22', 'a', '21', 'j', '13', 'mu'], file, - '(&event.rec()->' + true_ID[-1] + '()[i])','LeptonicMistag') - file.write(' }\n') - file.write(' for (MAuint32 i=toRemove.size();i>0;i--)\n') - file.write(' event.rec()->' + true_ID[-1] + '().erase(event.rec()->' + true_ID[-1] + '().begin() + toRemove[i-1]);\n') - file.write(' toRemove.clear();\n\n') - - # End - file.write('}\n\n') - - def HaveRules(self, true_list, reco_list): - for key, val in self.fastsim.tagger.rules.items(): - if val['id_true'] in true_list and val['id_reco'] in reco_list: - return True - return False + unique_rules = [] + for key, rule in self.fastsim.tagger.rules.items(): + if (int(rule["id_true"]), int(rule["id_reco"]), TaggerStatus.to_str(rule["tag"])) not in unique_rules: + unique_rules.append((int(rule["id_true"]), int(rule["id_reco"]), TaggerStatus.to_str(rule["tag"]))) + for true_id, reco_id, tag in unique_rules: + file.write("\n" + JobTaggerHeader.base[(true_id, reco_id)](tag) + " {\n") - def PrintTagger(self, true_list, reco_list, file, obj, prop): - # To get information on the existence of a tagger for a given particle species - check_initializer = 0 - for key, val in self.fastsim.tagger.rules.items(): - if val['id_true'] in true_list and val['id_reco'] in reco_list: - eff_str = [] - initializer = 'MAdouble64 ' - if check_initializer > 0: - initializer = '' - for eff_key, eff_val in val['efficiencies'].items(): - my_eff_str = eff_val['bounds'].tocpp_call(obj,\ - 'bnd_'+str(val['id_true'])+'_'+str(val['id_reco'])+'_'+str(eff_key)) - my_eff_str +=' * ' - my_eff_str += eff_val['function'].tocpp_call(obj,\ - 'eff_'+str(val['id_true'])+'_'+str(val['id_reco'])+'_'+str(eff_key)) - eff_str.append(my_eff_str) - file.write(' ' + initializer + ' efficiency = ' + ' + '.join(eff_str) +';\n') - if prop=='TauMistag': - file.write(' if (RANDOM->flat() < efficiency)\n') - file.write(' {\n') - file.write(' RecTauFormat* newTau = event.rec()->GetNewTau();\n') - file.write(' newTau->setMomentum('+obj+'->momentum());\n') - file.write(' newTau->setNtracks(' + obj + '->ntracks());\n') - file.write(' newTau->setMc(' + obj + '->mc());\n') - file.write(' newTau->setDecayMode(PHYSICS->GetTauDecayMode(newTau->mc()));\n') - file.write(' MAint32 charge = 0;\n') - file.write(' for (MAuint32 icst=0;icst<'+obj+'->constituents().size();icst++)\n') - file.write(' charge += PDG->GetCharge(event.mc()->particles()['+obj+'->constituents()[icst]].pdgid());\n') - file.write(' newTau->setCharge(charge>0);\n') - file.write(' toRemove.push_back(i);\n') - file.write(' continue;\n') - file.write(' }\n') - elif prop in ['Jet', 'LeptonicMistag', 'Electron', 'Photon']: - if 'tau' in obj and prop=='Jet': - file.write(' if (RANDOM->flat() > efficiency)\n') - else: - file.write(' if (RANDOM->flat() < efficiency)\n') - # Get the object for the reco object - newprop = prop - if val['id_reco'] in ['11', 'e'] : - newprop = 'Electron' - elif val['id_reco'] in ['13', 'mu'] : - newprop = 'Muon' - elif val['id_reco'] in ['22', 'a'] : - newprop = 'Photon' - elif val['id_reco'] in ['21', 'j'] : - newprop = 'Jet' - file.write(' {\n') - file.write(' Rec'+newprop.replace('Electron','Lepton').replace('Muon','Lepton')+ \ - 'Format* NewParticle = event.rec()->GetNew'+newprop+'();\n') - file.write(' NewParticle->setMomentum('+obj+'->momentum());\n') - file.write(' NewParticle->setMc(' + obj + '->mc());\n') - if newprop in ['Electron', 'Muon']: - if 'muon' in obj or 'electron' in obj: - file.write(' NewParticle->SetCharge(' + obj + '->charge());\n') - else: - file.write(' if(RANDOM->flat() > 0.5)\n') - file.write(' NewParticle->SetCharge(1.);\n') - file.write(' else)\n') - file.write(' NewParticle->SetCharge(-1.);\n') - elif newprop=='Jet': - if 'tau' in obj: - file.write(' NewParticle->setNtracks(' + obj + '->ntracks());\n') - else: - file.write(' NewParticle->setNtracks(1);\n') - file.write(' THT += '+obj+'->pt();\n') - file.write(' Meff += '+obj+'->pt();\n') - file.write(' MALorentzVector MissHT = event.rec()->MHT().momentum() - '+obj+'->momentum();\n') - file.write(' (&event.rec()->MHT().momentum())->SetPxPyPzE(MissHT.Px(), '+\ - 'MissHT.Py(), 0., MissHT.E());\n') - if 'jets' in obj and newprop in ['Electron', 'Photon']: - file.write(' THT -= '+obj+'->pt();\n') - file.write(' Meff -= '+obj+'->pt();\n') - file.write(' MALorentzVector MissHT = event.rec()->MHT().momentum() + '+obj+'->momentum();\n') - file.write(' (&event.rec()->MHT().momentum())->SetPxPyPzE(MissHT.Px(), MissHT.Py(), 0., MissHT.E());\n') - file.write(' toRemove.push_back(i);\n') - file.write(' continue;\n') - file.write(' }\n') - else: - if true_list[0] in reco_list: - file.write(' if (RANDOM->flat() > efficiency)') - file.write(' { ' + obj+'->set'+prop+'(false); }\n') - else: - file.write(' if (RANDOM->flat() < efficiency)') - file.write(' { ' + obj+'->set'+prop+'(true); }\n') - check_initializer+=1 + check_initializer = 0 + for key, val in self.fastsim.tagger.rules.items(): + if val['id_true'] in [str(true_id)] and val['id_reco'] in [str(reco_id)] and val["tag"] == TaggerStatus.get_status(tag): + eff_str = [] + initializer = 'MAfloat32 ' + if check_initializer > 0: + initializer = '' + for eff_key, eff_val in val['efficiencies'].items(): + my_eff_str = eff_val['bounds'].tocpp_call( + "object", + f"bnd_{val['id_true']}_{val['id_reco']}_{eff_key}_{TaggerStatus.to_str(val['tag'])}", + pointer=".", + ) + my_eff_str +=' * ' + my_eff_str += eff_val['function'].tocpp_call( + "object", + f"eff_{val['id_true']}_{val['id_reco']}_{eff_key}_{TaggerStatus.to_str(val['tag'])}", + pointer=".", + ) + eff_str.append(my_eff_str) + file.write(' ' + initializer + ' efficiency = ' + ' + '.join(eff_str) +';\n') + check_initializer += 1 + file.write(" return efficiency;\n}\n") diff --git a/madanalysis/layout/merging_plots.py b/madanalysis/layout/merging_plots.py index 65f246bb..92e72511 100644 --- a/madanalysis/layout/merging_plots.py +++ b/madanalysis/layout/merging_plots.py @@ -460,6 +460,7 @@ def DrawMATPLOTLIB(self,DJRplots,dataset,filenamePy,output_files,index): outputPy.write(' label=\'Sum\', ') else: outputPy.write(' label=\''+str(ind-1)+'-jet sample\', ') + try: import matplotlib.pyplot as plt plt.hist([0],normed=True) diff --git a/madanalysis/layout/plotflow.py b/madanalysis/layout/plotflow.py index 6ef6f696..f05a9115 100644 --- a/madanalysis/layout/plotflow.py +++ b/madanalysis/layout/plotflow.py @@ -799,6 +799,7 @@ def DrawMATPLOTLIB(self,histos,scales,ref,irelhisto,filenamePy,outputnames): ' label='+mytitle+', ') if ntot!=0: outputPy.write('histtype='+filledmode+', ') + try: import matplotlib.pyplot as plt plt.hist([0],normed=True) diff --git a/madanalysis/misc/run_recast.py b/madanalysis/misc/run_recast.py index 0af46597..c4d4d3c8 100644 --- a/madanalysis/misc/run_recast.py +++ b/madanalysis/misc/run_recast.py @@ -34,7 +34,7 @@ from shell_command import ShellCommand from string_tools import StringTools from six.moves import map, range, input -import copy, logging, math, os, shutil, time, sys, json +import copy, logging, math, os, shutil, time, sys, json, os class RunRecast(): @@ -258,7 +258,7 @@ def run_delphes(self,dataset,card): self.logger.info(" Writing the list of datasets...") jobber.WriteDatasetList(dataset) self.logger.info(" Creating Makefiles...") - if not jobber.WriteMakefiles(): + if not jobber.WriteMakefiles(ma5_fastjet_mode=False): return False self.logger.debug(" Fixing the pileup path...") self.fix_pileup(self.dirname+'_RecastRun/Input/'+card) @@ -352,6 +352,10 @@ def run_SimplifiedFastSim(self,dataset,card,analysislist): analysisList.write('#include "SampleAnalyzer/User/Analyzer/'+ana+'.h"\n') analysisList.write('#include "SampleAnalyzer/Process/Analyzer/AnalyzerManager.h"\n') analysisList.write('#include "SampleAnalyzer/Commons/Service/LogStream.h"\n\n') + if self.main.superfastsim.isTaggerOn(): + analysisList.write('#include "new_tagger.h"\n') + if self.main.superfastsim.isNewSmearerOn(): + analysisList.write('#include "new_smearer_reco.h"\n') analysisList.write('// -----------------------------------------------------------------------------\n') analysisList.write('// BuildUserTable\n') analysisList.write('// -----------------------------------------------------------------------------\n') @@ -424,6 +428,12 @@ def run_SimplifiedFastSim(self,dataset,card,analysislist): #restore self.main.recasting.status = "on" self.main.fastsim.package = old_fastsim + + # @Jack: new setup configuration. In order to run the code in SFS-FastJet mode analysis + # has to be compiled with `-DMA5_FASTJET_MODE` flag but this needs to be deactivated for + # Delphes-ROOT based analyses. + os.environ["FASTJET_FLAG"] = "-DMA5_FASTJET_MODE" + # Creating executable self.logger.info(" Compiling 'SampleAnalyzer'...") if not jobber.CompileJob(): @@ -680,6 +690,8 @@ def make_pad(self): strcores='-j'+str(ncores) command.append(strcores) logfile = self.dirname+'_RecastRun/Build/Log/PADcompilation.log' + # @jackaraz: this is needed for the recjetformat + os.environ["FASTJET_FLAG"] = "-DMA5_FASTJET_MODE" result, out = ShellCommand.ExecuteWithLog(command,logfile,self.dirname+'_RecastRun/Build') time.sleep(1.); # Checks and exit diff --git a/madanalysis/system/architecture_info.py b/madanalysis/system/architecture_info.py index 6106ad05..2ba6ef43 100644 --- a/madanalysis/system/architecture_info.py +++ b/madanalysis/system/architecture_info.py @@ -41,6 +41,8 @@ def __init__(self): # Is there optional package? self.has_root = False self.has_fastjet = False + self.has_fjcontrib = False + self.has_heptoptagger = False self.has_zlib = False self.has_delphes = False self.has_delphesMA5tune = False diff --git a/madanalysis/system/checkup.py b/madanalysis/system/checkup.py index b12c7e94..ddcd299c 100644 --- a/madanalysis/system/checkup.py +++ b/madanalysis/system/checkup.py @@ -322,6 +322,10 @@ def CheckOptionalProcessingPackages(self): return False if not self.checker.Execute('fastjet'): return False + if not self.checker.Execute('fastjet-contrib'): + return False + if not self.checker.Execute('HEPTopTagger'): + return False if not self.checker.Execute('root'): return False @@ -557,7 +561,7 @@ def check_updates(self): meta = json.loads(out) - latest_version = [int(x) for x in meta['tag_name'][1:].split(".")] + latest_version = [int(x) for x in meta['tag_name'][1:].split("_")[0].split(".")] current_version = [int(x) for x in self.archi_info.ma5_version.split(".")] def compare_versions(version1, version2): diff --git a/madanalysis/system/detect_fastjetcontrib.py b/madanalysis/system/detect_fastjetcontrib.py new file mode 100644 index 00000000..4447c3db --- /dev/null +++ b/madanalysis/system/detect_fastjetcontrib.py @@ -0,0 +1,150 @@ +################################################################################ +# +# Copyright (C) 2012-2020 Jack Araz, Eric Conte & Benjamin Fuks +# The MadAnalysis development team, email: +# +# This file is part of MadAnalysis 5. +# Official website: +# +# MadAnalysis 5 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MadAnalysis 5 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MadAnalysis 5. If not, see +# +################################################################################ + + +from __future__ import absolute_import +import logging, os +from shell_command import ShellCommand +from madanalysis.enumeration.detect_status_type import DetectStatusType + + +class DetectFastjetContrib: + def __init__(self, archi_info, user_info, session_info, debug): + self.archi_info = archi_info + self.user_info = user_info + self.session_info = session_info + self.debug = debug + self.name = "FastJet Contrib" + self.mandatory = False + self.force = False + self.lib_paths = [] + self.bin_file = "" + self.bin_path = "" + self.version = "" + self.logger = logging.getLogger("MA5") + self.required = ["RecursiveTools", "Nsubjettiness", "VariableR", "EnergyCorrelator"] + + def IsItVetoed(self): + if self.user_info.fastjet_veto: + self.logger.debug("user setting: veto on FastJet") + return True + else: + self.logger.debug("no user veto") + return False + + def detect_libs(self, fjconfig): + """ + Detect fastjet contrib libraries + """ + msg = "" + + theCommands = [fjconfig, "--libs"] + ok, out, err = ShellCommand.ExecuteWithCapture(theCommands, "./") + if not ok: + return False, "The fastjet-config executable does not work properly." + + libpath = [x[2:] for x in out.split() if x.startswith("-L")][0] + + not_found = [] + for libs in self.required: + if not any( + [f"lib{libs}{ext}" in os.listdir(libpath) for ext in [".a", ".dylib", ".so"]] + ): + not_found.append(libs) + if len(not_found) != 0: + return ( + DetectStatusType.UNFOUND, + "The following FJContrib libraries cannot be found: " + ", ".join(not_found), + ) + + # Ok + return DetectStatusType.FOUND, msg + + def ManualDetection(self): + msg = "" + + # User setting + if self.user_info.fastjet_bin_path == None: + return DetectStatusType.UNFOUND, msg + # Ok + return self.detect_libs(self.user_info.fastjet_bin_path + "/fastjet-config") + + def ToolsDetection(self): + msg = "" + + filename = os.path.normpath(self.archi_info.ma5dir + "/tools/fastjet/bin/fastjet-config") + self.logger.debug("Look for FastJet in the folder here:" + filename + " ...") + if os.path.isfile(filename): + self.logger.debug("-> found") + self.bin_file = filename + self.bin_path = os.path.dirname(self.bin_file) + else: + self.logger.debug("-> not found") + return DetectStatusType.UNFOUND, msg + + return self.detect_libs(self.archi_info.ma5dir + "/tools/fastjet/bin/fastjet-config") + + def AutoDetection(self): + msg = "" + + # Trying to call fastjet-config with which + result = ShellCommand.Which("fastjet-config", mute=True) + if len(result) == 0: + msg = "The FastJet package is not found." + return DetectStatusType.UNFOUND, msg + islink = os.path.islink(result[0]) + if not islink: + self.bin_file = os.path.normpath(result[0]) + else: + self.bin_file = os.path.normpath(os.path.realpath(result[0])) + self.bin_path = os.path.dirname(self.bin_file) + + # Debug mode + if self.debug: + self.logger.debug( + " which: " + str(result[0]) + " [is it a link? " + str(islink) + "]" + ) + if islink: + self.logger.debug(" -> " + os.path.realpath(result[0])) + + # Which all + if self.debug: + result = ShellCommand.Which("fastjet-config", all=True, mute=True) + if len(result) == 0: + msg = "The FastJet package is not found." + return DetectStatusType.UNFOUND, msg + self.logger.debug(" which-all: ") + for file in result: + self.logger.debug(" - " + str(file)) + + return self.detect_libs("fastjet-config") + + def ExtractInfo(self): + return True + + def SaveInfo(self): + # archi_info + self.archi_info.has_fjcontrib = True + + # Ok + return True diff --git a/madanalysis/system/detect_gpp.py b/madanalysis/system/detect_gpp.py index abae6cb5..67af6f22 100644 --- a/madanalysis/system/detect_gpp.py +++ b/madanalysis/system/detect_gpp.py @@ -68,6 +68,23 @@ def AutoDetection(self): if self.debug: self.logger.debug(" which: " + str(result[0])) + # Check GCC version + try: + command = ["g++ -dumpversion > .gcc_version"] + result = ShellCommand.Execute(command, self.archi_info.ma5dir, shell=True) + with open(os.path.join(self.archi_info.ma5dir, ".gcc_version"), "r") as f: + result = f.read() + os.remove(os.path.join(self.archi_info.ma5dir, ".gcc_version")) + gcc_version = [int(x) for x in result.split(".")] + if (gcc_version[0] < 8 and not self.archi_info.isMac) or (gcc_version[0] < 9 and self.archi_info.isMac): + msg = "MadAnalysis 5 requires " + self.archi_info.isMac*"clang version 9 " + \ + (not self.archi_info.isMac)*"GCC version 8 " + "or above." + \ + f" Current version is " + ".".join([str(x) for x in gcc_version]) + self.logger.error(msg) + return DetectStatusType.UNFOUND, msg + except Exception as err: + self.logger.debug("Problem with compiler version detection:: " + str(err)) + # Check C++ version try: with open(os.path.join(self.archi_info.ma5dir, "cxxtest.cc"), 'w') as f: @@ -86,6 +103,7 @@ def AutoDetection(self): except Exception as err: self.logger.debug(f"Unexpected {err}, {type(err)}") + if not self.archi_info.cpp11: return DetectStatusType.UNFOUND, "Please update C++ compiler. " + \ "Old compilers are no longer supported." diff --git a/madanalysis/system/detect_heptoptagger.py b/madanalysis/system/detect_heptoptagger.py new file mode 100644 index 00000000..a95e205a --- /dev/null +++ b/madanalysis/system/detect_heptoptagger.py @@ -0,0 +1,102 @@ +################################################################################ +# +# Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +# The MadAnalysis development team, email: +# +# This file is part of MadAnalysis 5. +# Official website: +# +# MadAnalysis 5 is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MadAnalysis 5 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with MadAnalysis 5. If not, see +# +################################################################################ + + +from __future__ import absolute_import +import logging, os +from madanalysis.enumeration.detect_status_type import DetectStatusType + + +class DetectHEPTopTagger: + def __init__(self, archi_info, user_info, session_info, debug): + self.archi_info = archi_info + self.user_info = user_info + self.session_info = session_info + self.debug = debug + self.name = "HEPTopTagger" + self.mandatory = False + self.force = False + self.lib_paths = [] + self.bin_file = "" + self.bin_path = "" + self.version = "" + self.logger = logging.getLogger("MA5") + + def IsItVetoed(self): + if self.user_info.fastjet_veto: + self.logger.debug("user setting: veto on FastJet") + return True + else: + self.logger.debug("no user veto") + return False + + def detect_files(self): + """ + Detect HEPTopTagger files + """ + msg = "" + + if not self.archi_info.has_fastjet: + logging.getLogger("MA5").debug(f" -> FastJet not found") + return DetectStatusType.UNFOUND, "FastJet not found." + if not self.archi_info.has_fjcontrib: + logging.getLogger("MA5").debug(f" -> FastJet contrib not found.") + return DetectStatusType.UNFOUND, "FastJet contrib not found." + + if not os.path.isdir(os.path.join(self.archi_info.ma5dir, "tools", "HEPTopTagger")): + logging.getLogger("MA5").debug( + f" -> The {os.path.join(self.archi_info.ma5dir, 'tools', 'HEPTopTagger')} folder does not exist." + ) + return ( + DetectStatusType.UNFOUND, + f"The {os.path.join(self.archi_info.ma5dir, 'tools', 'HEPTopTagger')} folder does not exist.", + ) + + # Check HTT files + for htt_file in ["HEPTopTagger.hh", "HEPTopTagger.cc"]: + if not os.path.isfile( + os.path.join(self.archi_info.ma5dir, "tools", "HEPTopTagger", htt_file) + ): + logging.getLogger("MA5").debug(f" -> {htt_file} is missing.") + return DetectStatusType.UNFOUND, f"{htt_file} is missing." + # Ok + return DetectStatusType.FOUND, msg + + def ManualDetection(self): + return self.detect_files() + + def ToolsDetection(self): + return self.detect_files() + + def AutoDetection(self): + return self.detect_files() + + def ExtractInfo(self): + return True + + def SaveInfo(self): + # archi_info + self.archi_info.has_heptoptagger = True + + # Ok + return True diff --git a/madanalysis/system/detect_manager.py b/madanalysis/system/detect_manager.py index 6b1edd9a..f3c6dd63 100644 --- a/madanalysis/system/detect_manager.py +++ b/madanalysis/system/detect_manager.py @@ -69,6 +69,9 @@ def Execute(self, rawpackage): elif package=='fastjet-contrib': from madanalysis.system.detect_fastjetcontrib import DetectFastjetContrib checker=DetectFastjetContrib(self.archi_info, self.user_info, self.session_info, self.debug) + elif package=='heptoptagger': + from madanalysis.system.detect_heptoptagger import DetectHEPTopTagger + checker=DetectHEPTopTagger(self.archi_info, self.user_info, self.session_info, self.debug) elif package=='delphes': from madanalysis.system.detect_delphes import DetectDelphes checker=DetectDelphes(self.archi_info, self.user_info, self.session_info, self.debug) diff --git a/madanalysis/system/detect_zlib.py b/madanalysis/system/detect_zlib.py index 5974db60..a4e561f0 100644 --- a/madanalysis/system/detect_zlib.py +++ b/madanalysis/system/detect_zlib.py @@ -47,7 +47,7 @@ def __init__(self,archi_info, user_info, session_info, debug): self.search_libs = [] self.search_incs = [] - + self.logger = logging.getLogger('MA5') # NAme of the header diff --git a/tools/SampleAnalyzer/Commons/Base/ClusterAlgoBase.h b/tools/SampleAnalyzer/Commons/Base/ClusterAlgoBase.h index b930a281..5450a03d 100644 --- a/tools/SampleAnalyzer/Commons/Base/ClusterAlgoBase.h +++ b/tools/SampleAnalyzer/Commons/Base/ClusterAlgoBase.h @@ -62,18 +62,6 @@ class ClusterAlgoBase /// Exclusive id for tau-elec-photon-jet MAbool ExclusiveId_; - // Track Isolation radius - std::vector isocone_track_radius_; - - // Electron Isolation radius - std::vector isocone_electron_radius_; - - // Muon Isolation radius - std::vector isocone_muon_radius_; - - // Photon Isolation radius - std::vector isocone_photon_radius_; - //--------------------------------------------------------------------------------- // method members @@ -86,10 +74,6 @@ class ClusterAlgoBase JetAlgorithm_=Algo; // Initializing common parameters Ptmin_ = 0.; - isocone_track_radius_.clear(); - isocone_electron_radius_.clear(); - isocone_muon_radius_.clear(); - isocone_photon_radius_.clear(); Exclusive_ = false; ExclusiveId_ = false; } @@ -98,10 +82,11 @@ class ClusterAlgoBase virtual ~ClusterAlgoBase() {} /// Jet clustering - virtual MAbool Execute(SampleFormat& mySample, EventFormat& myEvent, - MAbool ExclusiveId, const std::vector& vetos, - const std::set vetos2, - SmearerBase* smearer)=0; + virtual MAbool Execute(SampleFormat& mySample, EventFormat& myEvent, + SmearerBase* smearer)=0; + + // Extra Jet clustering + virtual MAbool Cluster(EventFormat& myEvent, std::string JetID)=0; /// Set parameter virtual MAbool SetParameter(const std::string& key, const std::string& value)=0; diff --git a/tools/SampleAnalyzer/Commons/Base/Configuration.cpp b/tools/SampleAnalyzer/Commons/Base/Configuration.cpp index 5b35d14c..1d1e8944 100644 --- a/tools/SampleAnalyzer/Commons/Base/Configuration.cpp +++ b/tools/SampleAnalyzer/Commons/Base/Configuration.cpp @@ -37,8 +37,8 @@ using namespace MA5; // Initializing static data members // ----------------------------------------------------------------------------- // DO NOT TOUCH THESE LINES -const std::string Configuration::sampleanalyzer_version_ = "1.10.12"; -const std::string Configuration::sampleanalyzer_date_ = "2023/09/13"; +const std::string Configuration::sampleanalyzer_version_ = "2.0.8"; +const std::string Configuration::sampleanalyzer_date_ = "2023/05/31"; // DO NOT TOUCH THESE LINES // ----------------------------------------------------------------------------- @@ -63,9 +63,9 @@ void Configuration::PrintSyntax() // ----------------------------------------------------------------------------- void Configuration::Lower(std::string &word) { - std::transform(word.begin(), word.end(), - word.begin(), - (MAint32(*)(MAint32))std::tolower); + std::transform(word.begin(), word.end(), + word.begin(), + (MAint32(*)(MAint32))std::tolower); } // ----------------------------------------------------------------------------- @@ -73,34 +73,34 @@ void Configuration::Lower(std::string &word) // ----------------------------------------------------------------------------- void Configuration::DecodeMA5version(const std::string &option) { - std::string stamp = option.substr(14, std::string::npos); - std::size_t result = stamp.find(";"); - try - { - // check the syntax - if (result == std::string::npos) - throw EXCEPTION_WARNING("MA5 version '" + stamp + "' is not valid.", "", 0); - - // version - pythoninterface_version_ = stamp.substr(0, result); - if (pythoninterface_version_.find("\"") == 0) - pythoninterface_version_ = pythoninterface_version_.substr(1, std::string::npos); - if (pythoninterface_version_.size() >= 2) - if (pythoninterface_version_.find("\"") == (pythoninterface_version_.size() - 1)) - pythoninterface_version_ = pythoninterface_version_.substr(0, (pythoninterface_version_.size() - 1)); - - // date - pythoninterface_date_ = stamp.substr(result + 1, std::string::npos); - if (pythoninterface_date_.find("\"") == 0) - pythoninterface_date_ = pythoninterface_date_.substr(1, std::string::npos); - if (pythoninterface_date_.size() >= 2) - if (pythoninterface_date_.find("\"") == (pythoninterface_date_.size() - 1)) - pythoninterface_date_ = pythoninterface_date_.substr(0, (pythoninterface_date_.size() - 1)); - } - catch (const std::exception &e) - { - MANAGE_EXCEPTION(e); - } + std::string stamp = option.substr(14, std::string::npos); + std::size_t result = stamp.find(";"); + try + { + // check the syntax + if (result == std::string::npos) + throw EXCEPTION_WARNING("MA5 version '" + stamp + "' is not valid.", "", 0); + + // version + pythoninterface_version_ = stamp.substr(0, result); + if (pythoninterface_version_.find("\"") == 0) + pythoninterface_version_ = pythoninterface_version_.substr(1, std::string::npos); + if (pythoninterface_version_.size() >= 2) + if (pythoninterface_version_.find("\"") == (pythoninterface_version_.size() - 1)) + pythoninterface_version_ = pythoninterface_version_.substr(0, (pythoninterface_version_.size() - 1)); + + // date + pythoninterface_date_ = stamp.substr(result + 1, std::string::npos); + if (pythoninterface_date_.find("\"") == 0) + pythoninterface_date_ = pythoninterface_date_.substr(1, std::string::npos); + if (pythoninterface_date_.size() >= 2) + if (pythoninterface_date_.find("\"") == (pythoninterface_date_.size() - 1)) + pythoninterface_date_ = pythoninterface_date_.substr(0, (pythoninterface_date_.size() - 1)); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } } // ----------------------------------------------------------------------------- @@ -108,87 +108,87 @@ void Configuration::DecodeMA5version(const std::string &option) // ----------------------------------------------------------------------------- MAbool Configuration::Initialize(MAint32 &argc, MAchar *argv[]) { - // Checking number of arguments - // is compulsory - if (argc < 2) + // Checking number of arguments + // is compulsory + if (argc < 2) + { + ERROR << "number of arguments is incorrect." << endmsg; + PrintSyntax(); + return false; + } + + // Decoding arguments + for (MAuint32 i = 1; i < static_cast(argc); i++) + { + // converting const characters into string + std::string argument = std::string(argv[i]); + Lower(argument); + + // safety : skip empty string + if (argument.size() == 0) + continue; + + // Is it an option? + if (argument.size() >= 2 && argument[0] == '-' && argument[1] == '-') { - ERROR << "number of arguments is incorrect." << endmsg; - PrintSyntax(); - return false; - } - - // Decoding arguments - for (MAuint32 i = 1; i < static_cast(argc); i++) - { - // converting const characters into string - std::string argument = std::string(argv[i]); - Lower(argument); - - // safety : skip empty string - if (argument.size() == 0) - continue; - - // Is it an option? - if (argument.size() >= 2 && argument[0] == '-' && argument[1] == '-') - { - // check event - if (argument == "--check_event") - check_event_ = true; - - // weighted event - else if (argument == "--no_event_weight") - no_event_weight_ = true; - - // version - else if (argument.find("--ma5_version=") == 0) - DecodeMA5version(argument); - - // other = command line options - else - { - std::string arg = argv[i]; - MAuint32 loc = arg.find("="); - if (loc == 0 || loc > arg.length()) - { - ERROR << "option '" << argument << "' unknown." << endmsg; - PrintSyntax(); - return false; - } - std::string name = arg.substr(2, loc - 2); - std::string value = arg.substr(loc + 1, arg.length() - 1); - options_[name] = value; - } - } - - // It is not an option? So it is a list of samples - else + // check event + if (argument == "--check_event") + check_event_ = true; + + // weighted event + else if (argument == "--no_event_weight") + no_event_weight_ = true; + + // version + else if (argument.find("--ma5_version=") == 0) + DecodeMA5version(argument); + + // other = command line options + else + { + std::string arg = argv[i]; + MAuint32 loc = arg.find("="); + if (loc == 0 || loc > arg.length()) { - if (input_list_name_ == "" || input_list_name_ == std::string(argv[i])) - { - // Extracting the input list - input_list_name_ = std::string(argv[i]); - } - else - { - // only one list of samples is required - ERROR << "several list of samples have been declared: '" - << input_list_name_ << "' and '" << argv[i] - << "'. Only one is required." << endmsg; - return false; - } + ERROR << "option '" << argument << "' unknown." << endmsg; + PrintSyntax(); + return false; } + std::string name = arg.substr(2, loc - 2); + std::string value = arg.substr(loc + 1, arg.length() - 1); + options_[name] = value; + } } - // Check that the input list is supplied - if (input_list_name_ == "") + // It is not an option? So it is a list of samples + else { - ERROR << "no list of samples has been provided." << endmsg; - PrintSyntax(); + if (input_list_name_ == "" || input_list_name_ == std::string(argv[i])) + { + // Extracting the input list + input_list_name_ = std::string(argv[i]); + } + else + { + // only one list of samples is required + ERROR << "several list of samples have been declared: '" + << input_list_name_ << "' and '" << argv[i] + << "'. Only one is required." << endmsg; return false; + } } - - // Ok - return true; + } + + // Check that the input list is supplied + if (input_list_name_ == "") + { + ERROR << "no list of samples has been provided." << endmsg; + PrintSyntax(); + return false; + } + + // Ok + return true; } // ----------------------------------------------------------------------------- @@ -196,29 +196,27 @@ MAbool Configuration::Initialize(MAint32 &argc, MAchar *argv[]) // ----------------------------------------------------------------------------- void Configuration::Display() { - INFO << " - version: " << sampleanalyzer_version_ << " (" << sampleanalyzer_date_ << ") "; - if ((sampleanalyzer_version_ != pythoninterface_version_ && pythoninterface_version_ != "") || - (sampleanalyzer_date_ != pythoninterface_date_ && pythoninterface_version_ != "")) - INFO << "[ python interface version: " << pythoninterface_version_ - << " (" << pythoninterface_date_ << ") ]"; + INFO << " - version: " << sampleanalyzer_version_ << " (" << sampleanalyzer_date_ << ") "; + if ((sampleanalyzer_version_ != pythoninterface_version_ && pythoninterface_version_ != "") || + (sampleanalyzer_date_ != pythoninterface_date_ && pythoninterface_version_ != "")) + INFO << "[ python interface version: " << pythoninterface_version_ + << " (" << pythoninterface_date_ << ") ]"; + INFO << endmsg; + + INFO << " - general: "; + + // Is there option ? + if (!check_event_ && !no_event_weight_) + { + INFO << "everything is default." << endmsg; + return; + } + else INFO << endmsg; - INFO << " - general: "; - - // Is there option ? - if (!check_event_ && !no_event_weight_) - { - INFO << "everything is default." << endmsg; - return; - } - else - { - INFO << endmsg; - } - - // Displaying options - if (check_event_) - INFO << " -> checking the event file format." << endmsg; - if (no_event_weight_) - INFO << " -> event weights are not used." << endmsg; + // Displaying options + if (check_event_) + INFO << " -> checking the event file format." << endmsg; + if (no_event_weight_) + INFO << " -> event weights are not used." << endmsg; } diff --git a/tools/SampleAnalyzer/Commons/Base/SFSTaggerBase.cpp b/tools/SampleAnalyzer/Commons/Base/SFSTaggerBase.cpp new file mode 100644 index 00000000..0a1d89bb --- /dev/null +++ b/tools/SampleAnalyzer/Commons/Base/SFSTaggerBase.cpp @@ -0,0 +1,507 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have const Received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// SampleAnalyser headers +#include "SampleAnalyzer/Commons/Base/SFSTaggerBase.h" +#include "SampleAnalyzer/Commons/Service/RandomService.h" +#include "SampleAnalyzer/Commons/Service/Physics.h" +#include "SampleAnalyzer/Commons/Service/PDGService.h" + +namespace MA5 { + + /// Print parameters + void SFSTaggerBase::PrintParam() const + { + /// Print B-taggging options + std::string excl = _options.btag_exclusive ? "Exclusive" : "Inclusive"; + INFO << " with bjet: matching ΔR = " + << _options.btag_matching_deltaR + << " ; " << excl << endmsg; + excl = _options.ctag_exclusive ? "Exclusive" : "Inclusive"; + + /// Print C-tagging options + if (_options.enable_ctagging) { + INFO << " with cjet: matching ΔR = " + << _options.ctag_matching_deltaR + << " ; " << excl << endmsg; + } + + /// Print Tau-tagging options + if (_options.tautag_jetbased) { + excl = _options.ctag_exclusive ? "Exclusive" : "Inclusive"; + INFO << " with tau : matching ΔR = " + << _options.tautag_matching_deltaR + << " ; " << excl << endmsg; + } else { + INFO << " with tau : hadron-based tagging" << endmsg; + } + } + + /// Convert jet to tau + MAfloat32 SFSTaggerBase::tau_tagging_eff(const RecJetFormat &jet, TaggerStatus status) const + { + RecTauFormat myTau; + myTau.setMomentum(jet.momentum()); + myTau.ntracks_ = jet.ntracks(); + myTau.mc_ = jet.mc_; + + if (status == TaggerStatus::MID) return mid_tau_tagging_eff(myTau); + else if (status == TaggerStatus::TIGHT) return tight_tau_tagging_eff(myTau); + else return loose_tau_tagging_eff(myTau); + } + + /// Execute tagger + void SFSTaggerBase::Execute(EventFormat &myEvent) const + { + /// Shortcut for global event variables + MAfloat64 & THT = myEvent.rec()->THT(); + MAfloat64 & Meff = myEvent.rec()->Meff(); + + /// Truth level B/C tagging + BJetTagging(myEvent); + CJetTagging(myEvent); + + /// Run tau tagging + if (_options.tautag_jetbased) JetBasedTauTagging(myEvent); + + /// Get initial number of taus. + /// @attention if tau tagging is jet based Ntau will be zero + MAuint32 Ntau = myEvent.rec()->taus().size(); + std::vector toRemove; + /// Jet tagging with detector effects + if (_isJetTaggingOn) + { + MAint32 ijet = -1; + for (auto &jet: myEvent.rec()->jets()) + { + ijet++; + MAfloat64 flat = RANDOM->flat(); + /// We have a true b-jet: is it b-tagged? + if (jet.true_btag()) + { + if (flat > loose_b_tagging_eff(jet)) jet.setLooseBtag(false); + if (flat > mid_b_tagging_eff(jet)) jet.setMidBtag(false); + if (flat > tight_b_tagging_eff(jet)) jet.setTightBtag(false); + } + /// We have a true c-jet: is it b-tagged? + else if (jet.true_ctag()) + { + if (flat < loose_c_mistag_b(jet)) jet.setLooseBtag(true); + if (flat < mid_c_mistag_b(jet)) jet.setMidBtag(true); + if (flat < tight_c_mistag_b(jet)) jet.setTightBtag(true); + } + /// We have a true light-jet: is it b-tagged? + else + { + if (flat < lightjet_mistag_b_loose(jet)) jet.setLooseBtag(true); + if (flat < lightjet_mistag_b_mid(jet)) jet.setMidBtag(true); + if (flat < lightjet_mistag_b_tight(jet)) jet.setTightBtag(true); + } + + /// We have a true b-jet: is it c-tagged? + if (jet.true_btag() && !jet.loose_btag()) + { + /// We have a b-tagged jet -> moving on with the next jet + if (flat < loose_b_mistag_c(jet)) jet.setLooseCtag(true); + if (flat < mid_b_mistag_c(jet)) jet.setMidCtag(true); + if (flat < tight_b_mistag_c(jet)) jet.setTightCtag(true); + } + /// We have a true c-jet: is it c-tagged? + else if (jet.true_ctag() && !jet.loose_btag()) + { + if (flat > loose_c_tagging_eff(jet)) jet.setLooseCtag(false); + if (flat > mid_c_tagging_eff(jet)) jet.setMidCtag(false); + if (flat > tight_c_tagging_eff(jet)) jet.setTightCtag(false); + } + /// We have a true light-jet: is it c-tagged? + else if (!jet.loose_btag() && !jet.loose_ctag()) + { + if (flat < lightjet_mistag_c_loose(jet)) jet.setLooseCtag(true); + if (flat < lightjet_mistag_c_mid(jet)) jet.setMidCtag(true); + if (flat < lightjet_mistag_c_tight(jet)) jet.setTightCtag(true); + } + + if (_options.tautag_jetbased) + { + if (jet.true_tautag() && !jet.loose_btag() && !jet.loose_ctag()) + { + if (flat > tau_tagging_eff(jet, LOOSE)) jet.setLooseTautag(false); + if (flat > tau_tagging_eff(jet, MID)) jet.setMidTautag(false); + if (flat > tau_tagging_eff(jet, TIGHT)) jet.setTightTautag(false); + } + else if (!jet.loose_btag() && !jet.loose_ctag()) + { + if (flat < lightjet_mistag_tau_loose(jet)) jet.setLooseTautag(true); + if (flat < lightjet_mistag_tau_mid(jet)) jet.setMidTautag(true); + if (flat < lightjet_mistag_tau_tight(jet)) jet.setTightTautag(true); + } + } + + /// We have a true b/c-jet -> cannot be mistagged + /// @attention Loose tag is always the default + if (jet.loose_ctag() || jet.loose_btag() || jet.loose_tautag()) continue; + + /// if not, is it mis-tagged as anything? + else + { + /// Scope for light jet mistagging as tau + if (!_options.tautag_jetbased) { + /// if not, is it Tau-tagged? + if (flat < lightjet_mistag_tau_loose(jet)) { + RecTauFormat *newTau = myEvent.rec()->GetNewTau(); + Jet2Tau(&jet, newTau, myEvent); + toRemove.push_back(ijet); + continue; + } + } + /// Scope for light jet mistagging for electron + { + /// if not, is it Electron-tagged? + if (flat < lightjet_mistag_electron(jet)) + { + RecLeptonFormat* NewParticle = myEvent.rec()->GetNewElectron(); + NewParticle->setMomentum(jet.momentum()); + NewParticle->setMc(jet.mc()); + /// @attention charge can also be determined via total constituent charge + NewParticle->SetCharge(RANDOM->flat() > 0.5 ? 1. : -1.); + THT -= jet.pt(); + Meff -= jet.pt(); + MALorentzVector MissHT = myEvent.rec()->MHT().momentum() + jet.momentum(); + (&myEvent.rec()->MHT().momentum())->SetPxPyPzE( + MissHT.Px(), MissHT.Py(), 0., MissHT.E() + ); + toRemove.push_back(ijet); + } + } + /// Scope for light jet mistagging for photon + { + /// if not, is it Photon-tagged? + if (flat < lightjet_mistag_photon(jet)) + { + RecPhotonFormat* NewParticle = myEvent.rec()->GetNewPhoton(); + NewParticle->setMomentum(jet.momentum()); + NewParticle->setMc(jet.mc()); + THT -= jet.pt(); + Meff -= jet.pt(); + MALorentzVector MissHT = myEvent.rec()->MHT().momentum() + jet.momentum(); + (&myEvent.rec()->MHT().momentum())->SetPxPyPzE( + MissHT.Px(), MissHT.Py(), 0., MissHT.E() + ); + toRemove.push_back(ijet); + continue; + } + } + } + } + } + /// Remove jets from the collection + for (MAuint32 i = toRemove.size(); i > 0; i--) + myEvent.rec()->jets().erase(myEvent.rec()->jets().begin() + toRemove[i-1]); + toRemove.clear(); + + if (_isTauTaggingEffOn && !_options.tautag_jetbased) + { + /// @attention In Jet based tau tagging this loop will not run. If its runnning thats a bug + for (MAuint32 itau = 0; itau < Ntau; itau++) + { + if (RANDOM->flat() > loose_tau_tagging_eff(myEvent.rec()->taus()[itau])) + { + RecJetFormat* NewParticle = myEvent.rec()->GetNewJet(); + NewParticle->setMomentum((&myEvent.rec()->taus()[itau])->momentum()); + NewParticle->setMc((&myEvent.rec()->taus()[itau])->mc()); + NewParticle->setNtracks((&myEvent.rec()->taus()[itau])->ntracks()); + toRemove.push_back(itau); + } + } + /// Remove taus from the collection + for (MAuint32 i=toRemove.size();i>0;i--) + myEvent.rec()->taus().erase(myEvent.rec()->taus().begin() + toRemove[i-1]); + toRemove.clear(); + } + + + /// Muon mistagging + if (_isMuonTaggingOn) + { + MAuint32 imu = -1; + for (auto &muon: myEvent.rec()->muons()) + { + imu++; + /// Muon mistagging as electron + if (RANDOM->flat() < muon_mistag_electron(muon)) + { + RecLeptonFormat* NewParticle = myEvent.rec()->GetNewElectron(); + NewParticle->setMomentum(muon.momentum()); + NewParticle->setMc(muon.mc()); + NewParticle->SetCharge(muon.charge()); + toRemove.push_back(imu); + continue; + } + /// Muon mistagging as photon + if (RANDOM->flat() < muon_mistag_photon(muon)) + { + RecPhotonFormat* NewParticle = myEvent.rec()->GetNewPhoton(); + NewParticle->setMomentum(muon.momentum()); + NewParticle->setMc(muon.mc()); + toRemove.push_back(imu); + continue; + } + /// Muon mistagging as light jet + /// @warning this will cause problems if executed in substructure tools + if (RANDOM->flat() < muon_mistag_lightjet(muon)) + { + RecJetFormat* NewParticle = myEvent.rec()->GetNewJet(); + NewParticle->setMomentum(muon.momentum()); + NewParticle->setMc(muon.mc()); + NewParticle->setNtracks(1); + THT += muon.pt(); + Meff += muon.pt(); + MALorentzVector MissHT = myEvent.rec()->MHT().momentum() - muon.momentum(); + (&myEvent.rec()->MHT().momentum())->SetPxPyPzE( + MissHT.Px(), MissHT.Py(), 0., MissHT.E() + ); + toRemove.push_back(imu); + continue; + } + } + for (MAuint32 i=toRemove.size();i>0;i--) + myEvent.rec()->muons().erase(myEvent.rec()->muons().begin() + toRemove[i-1]); + toRemove.clear(); + } + + + /// Electron mistagging + if (_isElectronTaggingOn) + { + MAuint32 ielec = -1; + for (auto &electron: myEvent.rec()->electrons()) + { + ielec++; + /// Electron mistagging as muon + if (RANDOM->flat() < electron_mistag_muon(electron)) + { + RecLeptonFormat* NewParticle = myEvent.rec()->GetNewMuon(); + NewParticle->setMomentum(electron.momentum()); + NewParticle->setMc(electron.mc()); + NewParticle->SetCharge(electron.charge()); + toRemove.push_back(ielec); + continue; + } + /// Electron mistagging as photon + if (RANDOM->flat() < electron_mistag_photon(electron)) + { + RecPhotonFormat* NewParticle = myEvent.rec()->GetNewPhoton(); + NewParticle->setMomentum(electron.momentum()); + NewParticle->setMc(electron.mc()); + toRemove.push_back(ielec); + continue; + } + /// Electron mistagging as jet + /// @warning This will cause problems during execution with substructure module + if (RANDOM->flat() < electron_mistag_lightjet(electron)) + { + RecJetFormat* NewParticle = myEvent.rec()->GetNewJet(); + NewParticle->setMomentum(electron.momentum()); + NewParticle->setMc(electron.mc()); + NewParticle->setNtracks(1); + THT += electron.pt(); + Meff += electron.pt(); + MALorentzVector MissHT = myEvent.rec()->MHT().momentum() - electron.momentum(); + (&myEvent.rec()->MHT().momentum())->SetPxPyPzE( + MissHT.Px(), MissHT.Py(), 0., MissHT.E() + ); + toRemove.push_back(ielec); + continue; + } + } + /// Remove mistagged electrons + for (MAuint32 i=toRemove.size();i>0;i--) + myEvent.rec()->electrons().erase(myEvent.rec()->electrons().begin() + toRemove[i-1]); + toRemove.clear(); + } + + + /// Photon mistaging + if (_isPhotonTaggingOn) + { + MAuint32 iph = -1; + for (auto &photon: myEvent.rec()->photons()) + { + iph++; + /// Photon mistagging as electron + if (RANDOM->flat() < photon_mistag_electron(photon)) + { + RecLeptonFormat* NewParticle = myEvent.rec()->GetNewElectron(); + NewParticle->setMomentum(photon.momentum()); + NewParticle->setMc(photon.mc()); + NewParticle->SetCharge(RANDOM->flat() > 0.5 ? 1. : -1.); + toRemove.push_back(iph); + continue; + } + /// Photon mistagging as muon + if (RANDOM->flat() < photon_mistag_muon(photon)) + { + RecLeptonFormat* NewParticle = myEvent.rec()->GetNewMuon(); + NewParticle->setMomentum(photon.momentum()); + NewParticle->setMc(photon.mc()); + NewParticle->SetCharge(RANDOM->flat() > 0.5 ? 1. : -1.); + toRemove.push_back(iph); + continue; + } + /// Photon mistagging as jet + /// @warning This will cause problems during execution with substructure module + if (RANDOM->flat() < photon_mistag_lightjet(photon)) + { + RecJetFormat* NewParticle = myEvent.rec()->GetNewJet(); + NewParticle->setMomentum(photon.momentum()); + NewParticle->setMc(photon.mc()); + NewParticle->setNtracks(1); + THT += photon.pt(); + Meff += photon.pt(); + MALorentzVector MissHT = myEvent.rec()->MHT().momentum() - photon.momentum(); + (&myEvent.rec()->MHT().momentum())->SetPxPyPzE( + MissHT.Px(), MissHT.Py(), 0., MissHT.E() + ); + toRemove.push_back(iph); + continue; + } + } + /// Remove mistagged photons + for (MAuint32 i=toRemove.size();i>0;i--) + myEvent.rec()->photons().erase(myEvent.rec()->photons().begin() + toRemove[i-1]); + toRemove.clear(); + } + } + + /// @attention BJetTagging and CJetTagging methods do not include any detector effects + /// this is due to the construction of the for loop over jets. If one applies detector + /// efficiencies at this state an efficiency can be applied to a jet multiple times. + /// Since one jet can contains multiple B/C hadrons within its cone. + + /// Truth B-Jet tagging + void SFSTaggerBase::BJetTagging(EventFormat &myEvent) const + { + /// Loop over B-hadrons + for (auto &bHadron: myEvent.rec()->MCBquarks_) + { + MAfloat32 DeltaRmax = _options.btag_matching_deltaR; + /// @attention If not exclusive `current_ijet` will always be -1 + /// thus jets will only be tagged with respect to dR + MAint32 current_ijet = -1; + /// Loop over jets + for (MAuint32 ijet = 0; ijet < myEvent.rec()->jets().size(); ijet++) + { + MAfloat32 dR = myEvent.rec()->jets()[ijet].dr(bHadron); + if (dR <= DeltaRmax) + { + if (_options.btag_exclusive) { current_ijet = ijet; DeltaRmax = dR; } + else myEvent.rec()->jets()[ijet].setAllBtags(true); + } + } + if (current_ijet >= 0) myEvent.rec()->jets()[current_ijet].setAllBtags(true); + } + } + + /// Truth C-Jet tagging + void SFSTaggerBase::CJetTagging(EventFormat &myEvent) const + { + /// Loop over C-hadrons + for (auto &cHadron: myEvent.rec()->MCCquarks_) + { + MAfloat32 DeltaRmax = _options.ctag_matching_deltaR; + /// @attention If not exclusive `current_ijet` will always be -1 + /// thus jets will only be tagged with respect to dR + MAint32 current_ijet = -1; + + /// Loop over jets + for (MAuint32 ijet = 0; ijet < myEvent.rec()->jets().size(); ijet++) + { + if (myEvent.rec()->jets()[ijet].true_btag()) continue; + MAfloat32 dR = myEvent.rec()->jets()[ijet].dr(cHadron); + if (dR <= DeltaRmax) + { + if (_options.ctag_exclusive) { current_ijet = ijet; DeltaRmax = dR; } + else { + if (_options.enable_ctagging) + myEvent.rec()->jets()[ijet].setAllCtags(true); + else myEvent.rec()->jets()[ijet].setTrueCtag(true); + } + } + } + if (current_ijet >= 0) { + if (_options.enable_ctagging) + myEvent.rec()->jets()[current_ijet].setAllCtags(true); + else myEvent.rec()->jets()[current_ijet].setTrueCtag(true); + } + } + } + + /// This method implements tau matching for jets + void SFSTaggerBase::JetBasedTauTagging(EventFormat &myEvent) const + { + for (auto &hadronicTau: myEvent.rec()->MCHadronicTaus()) + { + MAfloat32 DeltaRmax = _options.tautag_matching_deltaR; + MAint32 current_jet = -1; + for (MAuint32 ijet = 0; ijet < myEvent.rec()->jets().size(); ijet++) + { + if (myEvent.rec()->jets()[ijet].true_ctag() || myEvent.rec()->jets()[ijet].true_btag()) + continue; + + MAfloat32 dR = myEvent.rec()->jets()[ijet].dr(hadronicTau); + if (dR <= DeltaRmax) + { + if (_options.tautag_exclusive) + { + DeltaRmax = dR; current_jet = ijet; + } + else myEvent.rec()->jets()[current_jet].setAllTautags(true); + } + } + if (current_jet >= 0) myEvent.rec()->jets()[current_jet].setAllTautags(true); + } + } + + /// Convert Jet object to tau object + void SFSTaggerBase::Jet2Tau(const RecJetFormat * myJet, RecTauFormat *myTau, EventFormat &myEvent) const + { + myTau->setMomentum(myJet->momentum()); + myTau->setNtracks(myJet->ntracks()); + myTau->setMc(myJet->mc_); + myTau->setDecayMode(PHYSICS->GetTauDecayMode(myTau->mc_)); +#ifdef MA5_FASTJET_MODE + myTau->setPseudoJet(myJet->pseudojet_); +#endif + + MAint32 charge = 0; + myTau->Constituents_.reserve(myJet->Constituents_.size()); + myTau->Constituents_.insert( + myTau->Constituents_.end(), myJet->Constituents_.begin(), myJet->Constituents_.end() + ); + for (auto &constit: myTau->Constituents_) + charge += PDG->GetCharge(myEvent.mc()->particles()[constit].pdgid()); + + myTau->setCharge(charge > 0); + } + +} diff --git a/tools/SampleAnalyzer/Commons/Base/SFSTaggerBase.h b/tools/SampleAnalyzer/Commons/Base/SFSTaggerBase.h new file mode 100644 index 00000000..7ecc279d --- /dev/null +++ b/tools/SampleAnalyzer/Commons/Base/SFSTaggerBase.h @@ -0,0 +1,269 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have const Received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_SFSTAGGERBASE_H +#define MADANALYSIS5_SFSTAGGERBASE_H + +// SampleAnalyser headers +#include "SampleAnalyzer/Commons/DataFormat/EventFormat.h" + +namespace MA5 { + + /// Status of the tagger + enum TaggerStatus {LOOSE, MID, TIGHT}; + + struct SFSTaggerBaseOptions { + /// @brief Tagging options + /// + /// @code btag_matching_deltaR : double @endcode + /// matching deltaR is the upper threshold on the dR distance between a jet and B-hadron + /// @code btag_exclusive : bool @endcode + /// The exclusive algorithm is designed to dynamically find the jet that best matches with a given B-hadron + /// + /// options starting with ctag and tautag are the ones corresponding to c-jet and tau-jet tagging + /// + /// @warning Old tagger did not have c-tagger. In order to match the results from the old + /// tagger, adding @code enable_ctagging = false @endcode .This makes sure that the results + /// do not change between versions. Additionally @code deltaR = 0.5 @endcode was the default + /// value in old version that has been reinstated as well. + /// + /// @code taujtag_jetbased : bool@endcode + /// States the nature of the tau tagging proecedure. If false, hadronic taus in the event history + /// will be found and used as hadronic tau object. If True, this hadronic tau will be matched with + /// a jet and the jet will be considered as a tau jet. + /// + /// @warning DR matching for tau tagging is only available with the jet-based method + MAfloat32 btag_matching_deltaR = 0.5; + MAbool btag_exclusive = true; + MAbool enable_ctagging = false; + MAfloat32 ctag_matching_deltaR = 0.5; + MAbool ctag_exclusive = true; + MAfloat32 tautag_matching_deltaR = 0.5; + MAbool tautag_exclusive = true; + MAbool tautag_jetbased = false; + }; + + /// @brief Tagger base is designed to accommodate both truth and detector level B/C/Hadronic Tau tagging. + /// + /// Tagging efficiencies are designed to redefine in new_tagger.h/cpp files locally for the analysis + /// and used during tagging. If not defined, by default truth level tagging will be applied. + + class SFSTaggerBase { + protected: + /// Code efficiency booleans + MAbool _isJetTaggingOn, _isTauTaggingEffOn, _isMuonTaggingOn, _isElectronTaggingOn, _isPhotonTaggingOn; + SFSTaggerBaseOptions _options; + + public: + /// Constructor without argument + SFSTaggerBase() {} + + /// Destructor + virtual ~SFSTaggerBase() {} + + virtual void Initialize() + { + /// @brief Booleans for code efficiency + /// Turn on the usage of tau tagging efficiency + _isTauTaggingEffOn = false; + /// Turn on the usage of jet (mis)tagging efficiency + _isJetTaggingOn = false; + /// Turn on the usage of muon (mis)tagging efficiency + _isMuonTaggingOn = false; + /// Turn on the usage of electron (mis)tagging efficiency + _isElectronTaggingOn = false; + /// Turn on the usage of photon (mis)tagging efficiency + _isPhotonTaggingOn = false; + } + + /// @brief Execution: execute truth and detector level tagging algorithm + void Execute(EventFormat& myEvent) const; + + /// Initialize options + void SetOptions(SFSTaggerBaseOptions &opt) { _options = opt; } + + /// Print parameters + void PrintParam() const; + + /// Accesor to options + SFSTaggerBaseOptions options() const { return _options; } + + /// Truth B-Jet tagging + void BJetTagging(EventFormat& myEvent) const; + + /// Truth C-Jet tagging + void CJetTagging(EventFormat& myEvent) const; + + /// Hadronic tau tagging: this method implements both truth and detector level tagging simultaneously + void JetBasedTauTagging(EventFormat& myEvent) const; + + /// Convert Jet object to tau object + void Jet2Tau(const RecJetFormat * myJet, RecTauFormat *myTau, EventFormat &myEvent) const; + + ///==========================================// + /// // + /// Tagging Efficiencies // + /// // + ///==========================================// + + /// @brief By default, all efficiencies are initialised as perfect detector + + ///===============// + /// B-Tagging // + ///===============// + + /// loose B-jet tagging efficiency (b as b) + virtual MAfloat32 loose_b_tagging_eff(const RecJetFormat &object) const { return 2.; } + + /// loose B-jet mistagging as C-jet (b as c) + virtual MAfloat32 loose_b_mistag_c(const RecJetFormat &object) const { return -1.; } + + /// mid B-jet tagging efficiency (b as b) + virtual MAfloat32 mid_b_tagging_eff(const RecJetFormat &object) const { return 2.; } + + /// loose B-jet mistagging as C-jet (b as c) + virtual MAfloat32 mid_b_mistag_c(const RecJetFormat &object) const { return -1.; } + + /// tight B-jet tagging efficiency (b as b) + virtual MAfloat32 tight_b_tagging_eff(const RecJetFormat &object) const { return 2.; } + + /// loose B-jet mistagging as C-jet (b as c) + virtual MAfloat32 tight_b_mistag_c(const RecJetFormat &object) const { return -1.; } + + //===============// + // C-Tagging // + //===============// + + /// loose C-jet tagging efficiency (c as c) + virtual MAfloat32 loose_c_tagging_eff(const RecJetFormat &object) const { return 2.; } + + /// loose C-jet mistagging as C-jet (c as b) + virtual MAfloat32 loose_c_mistag_b(const RecJetFormat &object) const { return -1.; } + + /// mid C-jet tagging efficiency (c as c) + virtual MAfloat32 mid_c_tagging_eff(const RecJetFormat &object) const { return 2.; } + + /// mid C-jet mistagging as C-jet (c as b) + virtual MAfloat32 mid_c_mistag_b(const RecJetFormat &object) const { return -1.; } + + /// tight C-jet tagging efficiency (c as c) + virtual MAfloat32 tight_c_tagging_eff(const RecJetFormat &object) const { return 2.; } + + /// tight C-jet mistagging as C-jet (c as b) + virtual MAfloat32 tight_c_mistag_b(const RecJetFormat &object) const { return -1.; } + + //=======================// + // Light-Jet Tagging // + //=======================// + + /// loose Light-Jet mistagging as b-jet (j as b) + virtual MAfloat32 lightjet_mistag_b_loose(const RecJetFormat &object) const { return -1.; } + + /// loose Light-Jet mistagging as c jet (j as c) + virtual MAfloat32 lightjet_mistag_c_loose(const RecJetFormat &object) const { return -1.; } + + /// loose Light-Jet mistagging as tau (j as ta) + virtual MAfloat32 lightjet_mistag_tau_loose(const RecJetFormat &object) const { return -1.; } + + /// mid Light-Jet mistagging as b-jet (j as b) + virtual MAfloat32 lightjet_mistag_b_mid(const RecJetFormat &object) const { return -1.; } + + /// mid Light-Jet mistagging as c jet (j as c) + virtual MAfloat32 lightjet_mistag_c_mid(const RecJetFormat &object) const { return -1.; } + + /// mid Light-Jet mistagging as tau (j as ta) + virtual MAfloat32 lightjet_mistag_tau_mid(const RecJetFormat &object) const { return -1.; } + + /// tight Light-Jet mistagging as b-jet (j as b) + virtual MAfloat32 lightjet_mistag_b_tight(const RecJetFormat &object) const { return -1.; } + + /// tight Light-Jet mistagging as c jet (j as c) + virtual MAfloat32 lightjet_mistag_c_tight(const RecJetFormat &object) const { return -1.; } + + /// tight Light-Jet mistagging as tau (j as ta) + virtual MAfloat32 lightjet_mistag_tau_tight(const RecJetFormat &object) const { return -1.; } + + /// Light-Jet mistagging as electron (j as e) + virtual MAfloat32 lightjet_mistag_electron(const RecJetFormat &object) const { return -1.; } + + /// Light-Jet mistagging as photon (j as photon) + virtual MAfloat32 lightjet_mistag_photon(const RecJetFormat &object) const { return -1.; } + + //=================// + // Tau Tagging // + //=================// + + /// Convert jet to tau + MAfloat32 tau_tagging_eff(const RecJetFormat &jet, TaggerStatus status) const; + + /// loose_Tau tagging efficiency (ta as ta) + virtual MAfloat32 loose_tau_tagging_eff(const RecTauFormat &object) const { return 2.; } + + /// mid_Tau tagging efficiency (ta as ta) + virtual MAfloat32 mid_tau_tagging_eff(const RecTauFormat &object) const { return 2.; } + + /// tight_Tau tagging efficiency (ta as ta) + virtual MAfloat32 tight_tau_tagging_eff(const RecTauFormat &object) const { return 2.; } + + //=======================// + // Electron Tagging // + //======================// + + /// Electron mistagging as muon (e as mu) + virtual MAfloat32 electron_mistag_muon(const RecLeptonFormat &object) const { return -1.; } + + /// Electron mistagging as photon (e as a) + virtual MAfloat32 electron_mistag_photon(const RecLeptonFormat &object) const { return -1.; } + + /// Electron mistagging as light jet (e as j) + virtual MAfloat32 electron_mistag_lightjet(const RecLeptonFormat &object) const { return -1.; } + + //==================// + // Muon Tagging // + //==================// + + /// Electron mistagging as electron (mu as e) + virtual MAfloat32 muon_mistag_electron(const RecLeptonFormat &object) const { return -1.; } + + /// Electron mistagging as photon (mu as a) + virtual MAfloat32 muon_mistag_photon(const RecLeptonFormat &object) const { return -1.; } + + /// Electron mistagging as light jet (mu as j) + virtual MAfloat32 muon_mistag_lightjet(const RecLeptonFormat &object) const { return -1.; } + + //====================// + // Photon Tagging // + //====================// + + /// Electron mistagging as electron (a as e) + virtual MAfloat32 photon_mistag_electron(const RecPhotonFormat &object) const { return -1.; } + + /// Electron mistagging as muon (a as mu) + virtual MAfloat32 photon_mistag_muon(const RecPhotonFormat &object) const { return -1.; } + + /// Electron mistagging as light jet (a as j) + virtual MAfloat32 photon_mistag_lightjet(const RecPhotonFormat &object) const { return -1.; } + }; +} + +#endif //MADANALYSIS5_SFSTAGGERBASE_H diff --git a/tools/SampleAnalyzer/Commons/Base/SmearerBase.h b/tools/SampleAnalyzer/Commons/Base/SmearerBase.h index 25be44c4..59c7ebdb 100644 --- a/tools/SampleAnalyzer/Commons/Base/SmearerBase.h +++ b/tools/SampleAnalyzer/Commons/Base/SmearerBase.h @@ -2,30 +2,28 @@ // // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef SMEARERBASE_H #define SMEARERBASE_H - // STL headers #include #include @@ -35,7 +33,6 @@ #include "SampleAnalyzer/Commons/Service/RandomService.h" #include "SampleAnalyzer/Commons/Service/Physics.h" - namespace MA5 { @@ -44,257 +41,256 @@ namespace MA5 //--------------------------------------------------------------------------------- // private data members //--------------------------------------------------------------------------------- - private: - // Set constants: speed of light & pi - MAdouble64 c_; - MAdouble64 pi_; + private: + // Set constants: speed of light & pi + MAdouble64 c_; + MAdouble64 pi_; - /// Lenght unit mm=1 cm=0.1 - MAfloat32 length_unit_; + /// Lenght unit mm=1 cm=0.1 + MAfloat32 length_unit_; //--------------------------------------------------------------------------------- // protected data members //--------------------------------------------------------------------------------- - protected: + protected: + // Creating a container for the smeared output + MCParticleFormat output_; - // Creating a container for the smeared output - MCParticleFormat output_; + // Magnetic field along beam axis + MAdouble64 Bz_; - // Magnetic field along beam axis - MAdouble64 Bz_; + // Tracker cylinder radius + MAdouble64 Radius_; - // Tracker cylinder radius - MAdouble64 Radius_; + // Tracker half length + MAdouble64 HalfLength_; - // Tracker half length - MAdouble64 HalfLength_; - - // To optimise the code running time - MAbool MuonSmearer_; - MAbool ElectronSmearer_; - MAbool PhotonSmearer_; - MAbool TauSmearer_; - MAbool JetSmearer_; - MAbool ParticlePropagator_; + // To optimise the code running time + MAbool MuonSmearer_; + MAbool ElectronSmearer_; + MAbool PhotonSmearer_; + MAbool TauSmearer_; + MAbool JetSmearer_; + MAbool ParticlePropagator_; //--------------------------------------------------------------------------------- // public data members //--------------------------------------------------------------------------------- - public: - //--------------------------------------------------------------------------------- - // method members - //--------------------------------------------------------------------------------- - /// Constructor without argument - SmearerBase() { } - - /// Destructor - virtual ~SmearerBase() {} - - /// Accessors - const MAdouble64 Bz() const { return Bz_; } - - /// Length unit setter - void SetLengthUnit(MAfloat32 val) { length_unit_ = val; } - - /// Initialisation - void Initialize(MAbool base=false) - { - SetParameters(); - length_unit_ = 1.0; - if (!base) { PrintHeader(); } - PrintDebug(); - output_.Reset(); - c_ = 2.99792458E+8; // [m/s] - pi_ = 3.14159265; - } - - /// Matching general method - MCParticleFormat Execute(const MCParticleFormat * part, MAint32 smearerID) - { - // Clearing the output vector - output_.Reset(); - - if (smearerID == 21) output_ = JetSmearer(part); - else if (smearerID == 15) output_ = TauSmearer(part); - else if (smearerID == 13) output_ = MuonSmearer(part); - else if (smearerID == 11) output_ = ElectronSmearer(part); - else if (smearerID == 22) output_ = PhotonSmearer(part); - else if (smearerID == 0) output_ = ConstituentSmearer(part); - else if (smearerID == -1) output_ = TrackSmearer(part); - else - { - WARNING << "Unknown smearing method" << endmsg; - WARNING << "Smearing skipped for PDG-ID : "<< smearerID << endmsg; - SetDefaultOutput(part,output_); - } - return output_; - } - - // Copy part to output - void SetDefaultOutput(const MCParticleFormat * part, MCParticleFormat & output) - { - output.Reset(); - output.momentum().SetPxPyPzE(part->px(),part->py(),part->pz(),part->e()); - output.setDecayVertex(part->decay_vertex()); - if (!isPropagatorOn() && part->mothers().size() > 0) - SetDisplacementObservables(part, output); - else - { - output.setClosestApproach(part->closest_approach()); - output.setD0(part->d0()); - output.setDZ(part->dz()); - output.setD0Approx(part->d0_approx()); - output.setDZApprox(part->dz_approx()); - } - } - - // Calculate displacement observables without magnetic field - void SetDisplacementObservables(const MCParticleFormat*, MCParticleFormat &); - - // Set parameters - virtual void SetParameters() - { - Bz_ = 1.0e-9; - Radius_ = 1.0e+99; - HalfLength_ = 1.0e+99; - ParticlePropagator_ = false; - MuonSmearer_ = false; - ElectronSmearer_ = false; - PhotonSmearer_ = false; - TauSmearer_ = false; - JetSmearer_ = false; - } - - // For all methods below, the only relevant part of the output object is the momentum - // The reset allows to clear the left-over from the previous object - - // Electron smearing method - virtual MCParticleFormat ElectronSmearer(const MCParticleFormat * part) - { - SetDefaultOutput(part,output_); - return output_; - } - // Check whether electron smearing is on (code-efficiency-related) - MAbool isElectronSmearerOn() {return ElectronSmearer_;} - - // Muon smearing method - virtual MCParticleFormat MuonSmearer(const MCParticleFormat * part) - { - SetDefaultOutput(part,output_); - return output_; - } - // Check whether muon smearing is on (code-efficiency-related) - MAbool isMuonSmearerOn() {return MuonSmearer_;} - - // Hadronic Tau smearing method - virtual MCParticleFormat TauSmearer(const MCParticleFormat * part) - { - SetDefaultOutput(part,output_); - return output_; - } - // Check whether tau smearing is on (code-efficiency-related) - MAbool isTauSmearerOn() {return TauSmearer_;} + public: + //--------------------------------------------------------------------------------- + // method members + //--------------------------------------------------------------------------------- + /// Constructor without argument + SmearerBase() {} - // Photon smearing method - virtual MCParticleFormat PhotonSmearer(const MCParticleFormat * part) - { - SetDefaultOutput(part,output_); - return output_; - } - // Check whether photon smearing is on (code-efficiency-related) - MAbool isPhotonSmearerOn() {return PhotonSmearer_;} + /// Destructor + virtual ~SmearerBase() {} - // Jet smearing method - virtual MCParticleFormat JetSmearer(const MCParticleFormat * part) - { - SetDefaultOutput(part,output_); - return output_; - } + /// Accessors + const MAdouble64 Bz() const { return Bz_; } - // Check whether jet smearing is on (code-efficiency-related) - MAbool isJetSmearerOn() {return JetSmearer_;} + /// Length unit setter + void SetLengthUnit(MAfloat32 val) { length_unit_ = val; } - // Jet Constituent smearing method - virtual MCParticleFormat ConstituentSmearer(const MCParticleFormat * part) + /// Initialisation + void Initialize(MAbool base = false) + { + SetParameters(); + length_unit_ = 1.0; + if (!base) { - SetDefaultOutput(part,output_); - return output_; + PrintHeader(); } - - // Track smearing method - virtual MCParticleFormat TrackSmearer(const MCParticleFormat * part) + PrintDebug(); + output_.Reset(); + c_ = 2.99792458E+8; // [m/s] + pi_ = 3.14159265; + } + + /// Matching general method + MCParticleFormat Execute(const MCParticleFormat *part, MAint32 smearerID) + { + // Clearing the output vector + output_.Reset(); + + if (smearerID == 21) + output_ = JetSmearer(part); + else if (smearerID == 15) + output_ = TauSmearer(part); + else if (smearerID == 13) + output_ = MuonSmearer(part); + else if (smearerID == 11) + output_ = ElectronSmearer(part); + else if (smearerID == 22) + output_ = PhotonSmearer(part); + else if (smearerID == 0) + output_ = ConstituentSmearer(part); + else if (smearerID == -1) + output_ = TrackSmearer(part); + else { - SetDefaultOutput(part,output_); - return output_; + WARNING << "Unknown smearing method" << endmsg; + WARNING << "Smearing skipped for PDG-ID : " << smearerID << endmsg; + SetDefaultOutput(part, output_); } - - - //================================// - // Particle Propagator Method // - //================================// - - // Check whether particle propagator is on (code-efficiency-related) - MAbool isPropagatorOn() {return ParticlePropagator_;} - - // Particle propagator method - void ParticlePropagator(MCParticleFormat * part); - - /// Smearer Gaussian function - MAdouble64 Gaussian(MAdouble64, MAdouble64); - - /// Smearer Cumulative distribution function TO BE TESTED -// MAdouble64 Sigmoid(MAdouble64 sigma, MAdouble64 property) -// { -// MAdouble64 err = erf(property/(sigma*sqrt(2.))); -// MAdouble64 r = RANDOM->flat(); -// MAdouble64 sign = (r >= 0.5) * 1.0 + (r < 0.5) * (-1.0); -// return property + sign * RANDOM->flat() * (1. + err) * 0.5; -// } - - void PrintDebug() + return output_; + } + + // Copy part to output + void SetDefaultOutput(const MCParticleFormat *part, MCParticleFormat &output) + { + output.Reset(); + output.momentum().SetPxPyPzE(part->px(), part->py(), part->pz(), part->e()); + output.setDecayVertex(part->decay_vertex()); + if (!isPropagatorOn() && part->mothers().size() > 0) + SetDisplacementObservables(part, output); + else { - DEBUG << " -> Smearer Input Values:" << endmsg; - DEBUG << " * Magnetic field [T] = " << Bz_ << endmsg; -// DEBUG << " * Radius [m] = " << Radius_ << endmsg; -// DEBUG << " * Half Length [m] = " << HalfLength_ << endmsg; - - std::string module = ParticlePropagator_ ? "on" : "off"; - DEBUG << " * Propagator = " << module << endmsg; - - module = MuonSmearer_ ? "on" : "off"; - DEBUG << " * Muon Smearer = " << module << endmsg; - - module = ElectronSmearer_ ? "on" : "off"; - DEBUG << " * Electron Smearer = " << module << endmsg; - - module = PhotonSmearer_ ? "on" : "off"; - DEBUG << " * Photon Smearer = " << module << endmsg; - - module = TauSmearer_ ? "on" : "off"; - DEBUG << " * Tau Smearer = " << module << endmsg; - - module = JetSmearer_ ? "on" : "off"; - DEBUG << " * Jet Smearer = " << module << endmsg; + output.setClosestApproach(part->closest_approach()); + output.setD0(part->d0()); + output.setDZ(part->dz()); + output.setD0Approx(part->d0_approx()); + output.setDZApprox(part->dz_approx()); } - - - void PrintHeader() + } + + // Calculate displacement observables without magnetic field + void SetDisplacementObservables(const MCParticleFormat *, MCParticleFormat &); + + // Set parameters + virtual void SetParameters() + { + Bz_ = 1.0e-9; + Radius_ = 1.0e+99; + HalfLength_ = 1.0e+99; + ParticlePropagator_ = false; + MuonSmearer_ = false; + ElectronSmearer_ = false; + PhotonSmearer_ = false; + TauSmearer_ = false; + JetSmearer_ = false; + } + + // For all methods below, the only relevant part of the output object is the momentum + // The reset allows to clear the left-over from the previous object + + // Electron smearing method + virtual MCParticleFormat ElectronSmearer(const MCParticleFormat *part) + { + SetDefaultOutput(part, output_); + return output_; + } + // Check whether electron smearing is on (code-efficiency-related) + MAbool isElectronSmearerOn() { return ElectronSmearer_; } + + // Muon smearing method + virtual MCParticleFormat MuonSmearer(const MCParticleFormat *part) + { + SetDefaultOutput(part, output_); + return output_; + } + // Check whether muon smearing is on (code-efficiency-related) + MAbool isMuonSmearerOn() { return MuonSmearer_; } + + // Hadronic Tau smearing method + virtual MCParticleFormat TauSmearer(const MCParticleFormat *part) + { + SetDefaultOutput(part, output_); + return output_; + } + // Check whether tau smearing is on (code-efficiency-related) + MAbool isTauSmearerOn() { return TauSmearer_; } + + // Photon smearing method + virtual MCParticleFormat PhotonSmearer(const MCParticleFormat *part) + { + SetDefaultOutput(part, output_); + return output_; + } + // Check whether photon smearing is on (code-efficiency-related) + MAbool isPhotonSmearerOn() { return PhotonSmearer_; } + + // Jet smearing method + virtual MCParticleFormat JetSmearer(const MCParticleFormat *part) + { + SetDefaultOutput(part, output_); + return output_; + } + + // Check whether jet smearing is on (code-efficiency-related) + MAbool isJetSmearerOn() { return JetSmearer_; } + + // Jet Constituent smearing method + virtual MCParticleFormat ConstituentSmearer(const MCParticleFormat *part) + { + SetDefaultOutput(part, output_); + return output_; + } + + // Track smearing method + virtual MCParticleFormat TrackSmearer(const MCParticleFormat *part) + { + SetDefaultOutput(part, output_); + return output_; + } + + //================================// + // Particle Propagator Method // + //================================// + + // Check whether particle propagator is on (code-efficiency-related) + MAbool isPropagatorOn() { return ParticlePropagator_; } + + // Particle propagator method + void ParticlePropagator(MCParticleFormat *part); + + /// Smearer Gaussian function + MAdouble64 Gaussian(MAdouble64, MAdouble64); + + void PrintDebug() + { + DEBUG << " -> Smearer Input Values:" << endmsg; + DEBUG << " * Magnetic field [T] = " << Bz_ << endmsg; + // DEBUG << " * Radius [m] = " << Radius_ << endmsg; + // DEBUG << " * Half Length [m] = " << HalfLength_ << endmsg; + + std::string module = ParticlePropagator_ ? "on" : "off"; + DEBUG << " * Propagator = " << module << endmsg; + + module = MuonSmearer_ ? "on" : "off"; + DEBUG << " * Muon Smearer = " << module << endmsg; + + module = ElectronSmearer_ ? "on" : "off"; + DEBUG << " * Electron Smearer = " << module << endmsg; + + module = PhotonSmearer_ ? "on" : "off"; + DEBUG << " * Photon Smearer = " << module << endmsg; + + module = TauSmearer_ ? "on" : "off"; + DEBUG << " * Tau Smearer = " << module << endmsg; + + module = JetSmearer_ ? "on" : "off"; + DEBUG << " * Jet Smearer = " << module << endmsg; + } + + void PrintHeader() + { + INFO << " <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" << endmsg; + INFO << " <> <>" << endmsg; + INFO << " <> Simplified Fast Detector Simulation in MadAnalysis 5 <>" << endmsg; + INFO << " <> Please cite arXiv:2006.09387 [hep-ph] <>" << endmsg; + INFO << " <> and arXiv:2303.03427 [hep-ph] <>" << endmsg; + if (isPropagatorOn()) // cite particle propagator module { - INFO << " <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" << endmsg; INFO << " <> <>" << endmsg; - INFO << " <> Simplified Fast Detector Simulation in MadAnalysis 5 <>" << endmsg; - INFO << " <> Please cite arXiv:2006.09387 [hep-ph] <>" << endmsg; - if (isPropagatorOn()) // cite particle propagator module - { - INFO << " <> <>" << endmsg; - INFO << " <> Particle Propagation in MadAnalysis 5 <>" << endmsg; - INFO << " <> Please cite arXiv:2112.05163 [hep-ph] <>" << endmsg; - INFO << " <> <>" << endmsg; - } - INFO << " <> https://madanalysis.irmp.ucl.ac.be/wiki/SFS <>" << endmsg; + INFO << " <> Particle Propagation in MadAnalysis 5 <>" << endmsg; + INFO << " <> Please cite arXiv:2112.05163 [hep-ph] <>" << endmsg; INFO << " <> <>" << endmsg; - INFO << " <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" << endmsg; } + INFO << " <> https://madanalysis.irmp.ucl.ac.be/wiki/SFS <>" << endmsg; + INFO << " <> <>" << endmsg; + INFO << " <><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>" << endmsg; + } }; } diff --git a/tools/SampleAnalyzer/Commons/Base/TaggerBase.cpp b/tools/SampleAnalyzer/Commons/Base/TaggerBase.cpp deleted file mode 100644 index 7b4928c7..00000000 --- a/tools/SampleAnalyzer/Commons/Base/TaggerBase.cpp +++ /dev/null @@ -1,131 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks -// The MadAnalysis development team, email: -// -// This file is part of MadAnalysis 5. -// Official website: -// -// MadAnalysis 5 is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// MadAnalysis 5 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with MadAnalysis 5. If not, see -// -//////////////////////////////////////////////////////////////////////////////// - - -// SampleAnalyzer headers -#include "SampleAnalyzer/Commons/Base/TaggerBase.h" -#include "SampleAnalyzer/Commons/Service/ExceptionService.h" -#include "SampleAnalyzer/Commons/Service/ConvertService.h" - - -using namespace MA5; - -MAbool TaggerBase::IsLast(MCParticleFormat* part, EventFormat& myEvent) -{ - for (MAuint32 i=0; idaughters().size(); i++) - { - if (part->daughters()[i]->pdgid()==part->pdgid()) return false; - } - return true; -} - - - - -MAbool TaggerBase::SetParameter(const std::string& key, - const std::string& value, - std::string header) -{ - // Method - if (key=="method") - { - MAint32 tmp=0; - std::stringstream str,str2; - std::string Method_str; - str << value; - str >> tmp; - str2 << Method_; - str2 >> Method_str; - try - { - if (tmp<0 || tmp>3) throw EXCEPTION_WARNING("Available methods are 1, 2 and 3. Using the default value = "+Method_str,"",0); - Method_=tmp; - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - } - - // deltaR - else if (key=="matching_dr") - { - MAfloat32 tmp=0; - std::stringstream str; - str << value; - str >> tmp; - try - { - if (tmp<0) throw EXCEPTION_WARNING("DeltaRmax must be a positive value. Using the default value = "+CONVERT->ToString(DeltaRmax_),"",0); - DeltaRmax_=tmp; - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - } - - // exclusive - else if (key=="exclusive") - { - MAint32 tmp=0; - std::stringstream str; - str << value; - str >> tmp; - try - { - if (tmp<0) throw EXCEPTION_WARNING("Exclusive_ must be equal to 0 or 1.value. Using the default value = "+CONVERT->ToString(Exclusive_),"",0); - Exclusive_=(tmp==1); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - } - - // efficiency - else if (key=="efficiency") - { - MAfloat32 tmp=0; - std::stringstream str; - str << value; - str >> tmp; - try - { - if (tmp<0) throw EXCEPTION_WARNING("Efficiency must be a positive value. Using the default value = "+CONVERT->ToString(Efficiency_),"",0); - if (tmp>1) throw EXCEPTION_WARNING("Efficiency cannot be greater than 1. Using the default value = "+CONVERT->ToString(Efficiency_),"",0); - Efficiency_=tmp; - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - if (Efficiency_!=1) doEfficiency_=true; else doEfficiency_=false; - } - - // Other - else return false; - - return true; - -} diff --git a/tools/SampleAnalyzer/Commons/Base/TaggerBase.h b/tools/SampleAnalyzer/Commons/Base/TaggerBase.h deleted file mode 100644 index ca58dc1f..00000000 --- a/tools/SampleAnalyzer/Commons/Base/TaggerBase.h +++ /dev/null @@ -1,126 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks -// The MadAnalysis development team, email: -// -// This file is part of MadAnalysis 5. -// Official website: -// -// MadAnalysis 5 is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// MadAnalysis 5 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with MadAnalysis 5. If not, see -// -//////////////////////////////////////////////////////////////////////////////// - - -#ifndef TAGGERBASE_H -#define TAGGERBASE_H - - -// STL headers -#include - -// SampleAnalyser headers -#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" -#include "SampleAnalyzer/Commons/DataFormat/EventFormat.h" -#include "SampleAnalyzer/Commons/DataFormat/SampleFormat.h" -#include "SampleAnalyzer/Commons/DataFormat/RecJetFormat.h" -#include "SampleAnalyzer/Commons/Service/Physics.h" -#include "SampleAnalyzer/Commons/Service/PDGService.h" -#include "SampleAnalyzer/Commons/Service/RandomService.h" - - -namespace MA5 -{ - -class TaggerBase -{ -//--------------------------------------------------------------------------------- -// data members -//--------------------------------------------------------------------------------- - protected : - - /// Method used - MAint32 Method_; - - /// Delta R max - MAfloat32 DeltaRmax_; - - /// Is the tagging exclusive ? - MAbool Exclusive_; - - /// Efficiency - MAfloat32 Efficiency_; - - /// Applying efficiency - MAbool doEfficiency_; - -//--------------------------------------------------------------------------------- -// method members -//--------------------------------------------------------------------------------- - public : - - /// Constructor without argument - TaggerBase() - { - Method_=1; - DeltaRmax_=0.5; - Exclusive_=false; - Efficiency_=1.; - doEfficiency_=false; - } - - /// Destructor - virtual ~TaggerBase() - {} - - /// Matching using dr - virtual void Method1(SampleFormat& mySample, EventFormat& myEvent)=0; - - /// Matching using the history - virtual void Method2(SampleFormat& mySample, EventFormat& myEvent)=0; - - /// Matching using a jet preselection with the history before calculating dr - virtual void Method3(SampleFormat& mySample, EventFormat& myEvent)=0; - - /// Matching general method - virtual void Execute(SampleFormat& mySample, EventFormat& myEvent)=0; - - /// Accessor to the selected method - MAint32 GetMethod() - {return Method_;} - - /// - MAbool IsLast(MCParticleFormat* part, EventFormat& myEvent); - - /// Set a parameter - virtual MAbool SetParameter(const std::string& key, const std::string& value, std::string header=""); - - /// Function for identification - MAbool IsIdentified() const - { - // no efficiency = default - if (!doEfficiency_) return true; - - // applying efficiency - MAdouble64 value = RANDOM->flat(); - if (value < Efficiency_) return true; - else return false; - } - - virtual std::string GetParameters()=0; - -}; - -} - -#endif diff --git a/tools/SampleAnalyzer/Commons/DataFormat/MCParticleFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/MCParticleFormat.h index ea650b30..5c5d2bed 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/MCParticleFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/MCParticleFormat.h @@ -43,174 +43,169 @@ namespace MA5 { -class LHEReader; -class LHCOReader; -class STDHEPreader; -class HEPMCReader; -class ROOTReader; -class LHEWriter; -class MergingPlots; -class DelphesTreeReader; -class DelphesMA5tuneTreeReader; -class SmearerBase; - -class MCParticleFormat : public ParticleBaseFormat -{ - friend class LHEReader; - friend class LHCOReader; - friend class STDHEPreader; - friend class HEPMCReader; - friend class ROOTReader; - friend class LHEWriter; - friend class MergingPlots; - friend class DelphesTreeReader; - friend class DelphesMA5tuneTreeReader; - friend class SmearerBase; - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private: - - /// PDG numbering of the particle - MAint32 pdgid_; - - /// Status code of the particle - /// For LHE: -1 for initial state, 2 intermediate state, 1 final state - /// For PYTHIA: more sophisticated - MAint16 statuscode_; - - /// Cosine of the angle btwn the spin vector and its 3-momentum, in the lab frame - MAfloat32 spin_; - - /// Is a PileUp particle or not? - MAbool isPU_; - - /// List of daughter particles - std::vector daughters_; - - /// List of mother particles - std::vector mothers_; - - /// Decay position in time & space (in s & mm) - MALorentzVector decay_vertex_; - - /// Angle defining the rotation the momentum is subjected to during its - /// propagation in the magnetic field - MAdouble64 momentum_rotation_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without arguments - MCParticleFormat() - { - momentum_.SetPxPyPzE(0.,0.,0.,0.); - closest_approach_.SetXYZ(0.,0.,0.); - spin_ = 0.; - pdgid_ = 0; - statuscode_ = 0; - isPU_ = false; - d0_ = 0.; d0_approx_ = 0.; - dz_ = 0.; dz_approx_ = 0.; - momentum_rotation_ = 0.; - } - - /// Destructor - virtual ~MCParticleFormat() - {} - - /// Clear all information - virtual void Reset() - { - momentum_.SetPxPyPzE(0.,0.,0.,0.); - spin_ = 0.; - pdgid_ = 0; - statuscode_ = 0; - isPU_ = false; - daughters_.clear(); - mothers_.clear(); - decay_vertex_.clear(); - closest_approach_.clear(); - d0_ = 0.; - dz_ = 0.; - } - - /// Print particle informations - virtual void Print() const - { - INFO << "momentum=(" << /*set::setw(8)*/"" << std::left << momentum_.Px() - << ", "<(statuscode_) << " - " << endmsg; - INFO << "Number of mothers=" << mothers_.size() << " - " - << "Number of daughters=" << daughters_.size() << endmsg; - } - - const MAbool& isPU() const {return isPU_;} - const MAfloat64& ctau() const {return decay_vertex_.T();} - const MAfloat32& spin() const {return spin_;} - const MAint32& pdgid() const {return pdgid_;} - const MAint16& statuscode() const {return statuscode_;} - - /// Accessor to the daughters (read-only) - const std::vector& daughters() const {return daughters_;} - - /// Accessor to the daughters - std::vector& daughters() {return daughters_;} - - /// Accessor to the mothers (read-only) - const std::vector& mothers() const {return mothers_;} - - /// Accessor to the mothers - std::vector& mothers() {return mothers_;} - - /// Accessor to the decay vertex (read-only) - const MALorentzVector& decay_vertex() const {return decay_vertex_;} - - /// Accessor to the rotation angle of the momentum (read-only) - const MAdouble64& momentum_rotation() const {return momentum_rotation_;} - - - /// Mutators - void setDecayVertex(const MALorentzVector& v) {decay_vertex_=v;} - void setIsPU(MAbool v) {isPU_=v;} - void setSpin(MAfloat32 v) {spin_=v;} - void setPdgid(MAint32 v) {pdgid_=v;} - void setStatuscode(MAint16 v) {statuscode_=v;} - void setMomentum(const MALorentzVector& v) {momentum_=v;} - void setMomentumRotation(MAdouble64 v) {momentum_rotation_=v;} - - /// Boosting the four momentum to the restframe of another particle - void ToRestFrame(const MCParticleFormat* boost) - { - if (boost==0) return; - ToRestFrame(*boost); - } - - void ToRestFrame(const MCParticleFormat& boost) - { - MALorentzVector momentum = boost.momentum(); - momentum.SetPx(-momentum.X()); - momentum.SetPy(-momentum.Y()); - momentum.SetPz(-momentum.Z()); - - MABoost convertor; - convertor.setBoostVector(momentum); - convertor.boost(momentum_); - } - -}; + class LHEReader; + class LHCOReader; + class STDHEPreader; + class HEPMCReader; + class ROOTReader; + class LHEWriter; + class MergingPlots; + class DelphesTreeReader; + class DelphesMA5tuneTreeReader; + class SmearerBase; + + class MCParticleFormat : public ParticleBaseFormat + { + friend class LHEReader; + friend class LHCOReader; + friend class STDHEPreader; + friend class HEPMCReader; + friend class ROOTReader; + friend class LHEWriter; + friend class MergingPlots; + friend class DelphesTreeReader; + friend class DelphesMA5tuneTreeReader; + friend class SmearerBase; + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + + /// PDG numbering of the particle + MAint32 pdgid_; + + /// Status code of the particle + /// For LHE: -1 for initial state, 2 intermediate state, 1 final state + /// For PYTHIA: more sophisticated + MAint16 statuscode_; + + /// Cosine of the angle btwn the spin vector and its 3-momentum, in the lab frame + MAfloat32 spin_; + + /// Is a PileUp particle or not? + MAbool isPU_; + + /// List of daughter particles + std::vector daughters_; + + /// List of mother particles + std::vector mothers_; + + /// Decay position in time & space (in s & mm) + MALorentzVector decay_vertex_; + + /// Angle defining the rotation the momentum is subjected to during its + /// propagation in the magnetic field + MAdouble64 momentum_rotation_; + + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public : + + /// Constructor without arguments + MCParticleFormat() + { Reset(); } + + /// Destructor + virtual ~MCParticleFormat() + {} + + /// Constructor with arguments + MCParticleFormat(MAfloat64 px, MAfloat64 py, MAfloat64 pz, MAfloat64 e) + { Reset(); momentum_.SetPxPyPzE(px,py,pz,e); } + + /// Clear all information + virtual void Reset() + { + momentum_.SetPxPyPzE(0.,0.,0.,0.); + spin_ = 0.; + pdgid_ = 0; + statuscode_ = 0; + isPU_ = false; + daughters_.clear(); + mothers_.clear(); + decay_vertex_.clear(); + closest_approach_.clear(); + d0_ = 0.; + dz_ = 0.; + momentum_rotation_ = 0.; + } + + /// Print particle informations + virtual void Print() const + { + INFO << "momentum=(" << /*set::setw(8)*/"" << std::left << momentum_.Px() + << ", "<(statuscode_) << " - " << endmsg; + INFO << "Number of mothers=" << mothers_.size() << " - " + << "Number of daughters=" << daughters_.size() << endmsg; + } + + const MAbool& isPU() const {return isPU_;} + const MAfloat64& ctau() const {return decay_vertex_.T();} + const MAfloat32& spin() const {return spin_;} + const MAint32& pdgid() const {return pdgid_;} + const MAint16& statuscode() const {return statuscode_;} + + /// Accessor to the daughters (read-only) + const std::vector& daughters() const {return daughters_;} + + /// Accessor to the daughters + std::vector& daughters() {return daughters_;} + + /// Accessor to the mothers (read-only) + const std::vector& mothers() const {return mothers_;} + + /// Accessor to the mothers + std::vector& mothers() {return mothers_;} + + /// Accessor to the decay vertex (read-only) + const MALorentzVector& decay_vertex() const {return decay_vertex_;} + + /// Accessor to the rotation angle of the momentum (read-only) + const MAdouble64& momentum_rotation() const {return momentum_rotation_;} + + + /// Mutators + void setDecayVertex(const MALorentzVector& v) {decay_vertex_=v;} + void setIsPU(MAbool v) {isPU_=v;} + void setSpin(MAfloat32 v) {spin_=v;} + void setPdgid(MAint32 v) {pdgid_=v;} + void setStatuscode(MAint16 v) {statuscode_=v;} + void setMomentum(const MALorentzVector& v) {momentum_=v;} + void setMomentumRotation(MAdouble64 v) {momentum_rotation_=v;} + + /// Boosting the four momentum to the restframe of another particle + void ToRestFrame(const MCParticleFormat* boost) + { + if (boost==0) return; + ToRestFrame(*boost); + } + + void ToRestFrame(const MCParticleFormat& boost) + { + MALorentzVector momentum = boost.momentum(); + momentum.SetPx(-momentum.X()); + momentum.SetPy(-momentum.Y()); + momentum.SetPz(-momentum.Z()); + + MABoost convertor; + convertor.setBoostVector(momentum); + convertor.boost(momentum_); + } + + }; } diff --git a/tools/SampleAnalyzer/Commons/DataFormat/RecEventFormat.cpp b/tools/SampleAnalyzer/Commons/DataFormat/RecEventFormat.cpp new file mode 100644 index 00000000..cbd021aa --- /dev/null +++ b/tools/SampleAnalyzer/Commons/DataFormat/RecEventFormat.cpp @@ -0,0 +1,262 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2020 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// Fastjet headers +#ifdef MA5_FASTJET_MODE +#include "fastjet/PseudoJet.hh" +#endif + +// SampleAnalyzer headers +#include "SampleAnalyzer/Commons/DataFormat/RecEventFormat.h" + +namespace MA5 { + /// Clearing all information + void RecEventFormat::Reset() + { + PrimaryJetID_ = "Ma5Jet"; + photons_.clear(); + electrons_.clear(); + muons_.clear(); + taus_.clear(); + jetcollection_.clear(); + emptyjet_.clear(); +#ifdef MA5_FASTJET_MODE + // pseudojet : only available when fastjet is in use (code efficiency) + input_hadrons_.clear(); +#endif + towers_ok_=false; + towers_.clear(); + tracks_ok_=false; + tracks_.clear(); + vertices_ok_=false; + vertices_.clear(); + EFlowTracks_ok_=false; + EFlowTracks_.clear(); + EFlowPhotons_ok_=false; + EFlowPhotons_.clear(); + EFlowNeutralHadrons_ok_=false; + EFlowNeutralHadrons_.clear(); + MET_.Reset(); + MHT_.Reset(); + TET_ = 0.; + THT_ = 0.; + Meff_ = 0.; + MCHadronicTaus_.clear(); + MCMuonicTaus_.clear(); + MCElectronicTaus_.clear(); + MCBquarks_.clear(); + MCCquarks_.clear(); + } + + //======================// + //===== Jet Tools ======// + //======================// + + // Remove an element from jet collection + void RecEventFormat::Remove_Collection(std::string id) + { + if (hasJetID(id)) jetcollection_.erase(id); + else ERROR << "Remove_Collection:: '" << id << "' does not exist." << endmsg; + } + + /// Change Jet ID + void RecEventFormat::ChangeJetID(std::string previous_id, std::string new_id) + { + if (!hasJetID(new_id) && hasJetID(previous_id)) + { + auto it = jetcollection_.find(previous_id); + std::swap(jetcollection_[new_id],it->second); + jetcollection_.erase(it); + } + else + { + if (hasJetID(new_id)) + ERROR << "ChangeJetID:: '" << new_id << "' already exists." << endmsg; + if (!hasJetID(previous_id)) + ERROR << "ChangeJetID:: '" << previous_id << "' does not exist." << endmsg; + } + } + + // Get the list of jet collection IDs + const std::vector RecEventFormat::GetJetIDs() const + { + std::vector keys; + keys.reserve(jetcollection_.size()); + for (auto &key: jetcollection_) + keys.emplace_back(key.first); + return keys; + } + + + // Add a new hadron to be clustered. (for code efficiency) + void RecEventFormat::AddHadron(MCParticleFormat& v, MAuint32& idx) + { +#ifdef MA5_FASTJET_MODE + fastjet::PseudoJet input; + input.reset(v.px(), v.py(), v.pz(), v.e()); + input.set_user_index(idx); + input_hadrons_.push_back(input); +#endif + } + +#ifdef MA5_FASTJET_MODE + // Get hadrons to cluster (code efficiency) + std::vector& RecEventFormat::cluster_inputs() {return input_hadrons_;} +#endif + + //======================// + //=== Get New Object ===// + //======================// + + /// Giving a new photon entry + RecPhotonFormat* RecEventFormat::GetNewPhoton() + { + photons_.push_back(RecPhotonFormat()); + return &photons_.back(); + } + + /// Giving a new electron entry + RecLeptonFormat* RecEventFormat::GetNewElectron() + { + electrons_.push_back(RecLeptonFormat()); + (&electrons_.back())->setElectronId(); + return &electrons_.back(); + } + + /// Giving a new muon entry + RecLeptonFormat* RecEventFormat::GetNewMuon() + { + muons_.push_back(RecLeptonFormat()); + (&muons_.back())->setMuonId(); + return &muons_.back(); + } + + /// Giving a new tower entry + RecTowerFormat* RecEventFormat::GetNewTower() + { + towers_.push_back(RecTowerFormat()); + return &towers_.back(); + } + + /// Giving a new EFlowTrack entry + RecTrackFormat* RecEventFormat::GetNewEFlowTrack() + { + EFlowTracks_.push_back(RecTrackFormat()); + return &EFlowTracks_.back(); + } + + /// Giving a new EFlowPhoton entry + RecParticleFormat* RecEventFormat::GetNewEFlowPhoton() + { + EFlowPhotons_.push_back(RecParticleFormat()); + return &EFlowPhotons_.back(); + } + + /// Giving a new EFlowNeutralHadron entry + RecParticleFormat* RecEventFormat::GetNewEFlowNeutralHadron() + { + EFlowNeutralHadrons_.push_back(RecParticleFormat()); + return &EFlowNeutralHadrons_.back(); + } + + /// Giving a new tau entry + RecTauFormat* RecEventFormat::GetNewTau() + { + taus_.push_back(RecTauFormat()); + return &taus_.back(); + } + + /// Giving a new primary jet entry + RecJetFormat* RecEventFormat::GetNewJet() + { + std::pair< std::map >::iterator, bool> new_jet; + new_jet = jetcollection_.insert(std::make_pair(PrimaryJetID_,std::vector() )); + new_jet.first->second.push_back(RecJetFormat()); + return &(new_jet.first->second.back()); + } + + /// Giving a new primary jet entry + void RecEventFormat::CreateEmptyJetAccesor() + { + std::pair< std::map >::iterator, bool> new_jet; + new_jet = jetcollection_.insert(std::make_pair(PrimaryJetID_,std::vector() )); + } + + // Get a new jet entry with specific ID + RecJetFormat* RecEventFormat::GetNewJet(std::string id) + { + std::pair< std::map >::iterator,bool> new_jet; + new_jet = jetcollection_.insert(std::make_pair(id,std::vector() )); + new_jet.first->second.push_back(RecJetFormat()); + return &(new_jet.first->second.back()); + } + + // Create an empty jet accessor with specific id + void RecEventFormat::CreateEmptyJetAccesor(std::string id) + { + std::pair< std::map >::iterator,bool> new_jet; + new_jet = jetcollection_.insert(std::make_pair(id,std::vector() )); + } + + /// Giving a new fat jet entry + RecJetFormat* RecEventFormat::GetNewFatJet() + { + std::string id = "fatjet"; + std::pair< std::map >::iterator,bool> new_jet; + new_jet = jetcollection_.insert(std::make_pair(id,std::vector() )); + new_jet.first->second.push_back(RecJetFormat()); + return &(new_jet.first->second.back()); + } + + /// Giving a new gen jet entry + RecJetFormat* RecEventFormat::GetNewGenJet() + { + std::string id = "genjet"; + std::pair< std::map >::iterator,bool> new_jet; + new_jet = jetcollection_.insert(std::make_pair(id,std::vector() )); + new_jet.first->second.push_back(RecJetFormat()); + return &(new_jet.first->second.back()); + } + + /// Giving a new track entry + RecTrackFormat* RecEventFormat::GetNewTrack() + { + tracks_.push_back(RecTrackFormat()); + return &tracks_.back(); + } + + /// Giving a new vertex entry + RecVertexFormat* RecEventFormat::GetNewVertex() + { + vertices_.push_back(RecVertexFormat()); + return &vertices_.back(); + } + + /// Giving a pointer to the Missing Transverse Energy + RecParticleFormat* RecEventFormat::GetNewMet() { return &MET_; } + + /// Giving a pointer to the Missing Transverse Energy + RecParticleFormat* RecEventFormat::GetNewMht() { return &MHT_; } + + +} diff --git a/tools/SampleAnalyzer/Commons/DataFormat/RecEventFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/RecEventFormat.h index 4b427340..4087d0ef 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/RecEventFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/RecEventFormat.h @@ -25,7 +25,6 @@ #ifndef RecEventFormat_h #define RecEventFormat_h - // STL headers #include #include @@ -42,411 +41,475 @@ #include "SampleAnalyzer/Commons/DataFormat/RecVertexFormat.h" #include "SampleAnalyzer/Commons/Service/LogService.h" +#ifdef MA5_FASTJET_MODE +namespace fastjet { + class PseudoJet; +} +#endif + namespace MA5 { -class LHEReader; -class LHCOReader; -class ROOTReader; -class TauTagger; -class bTagger; -class JetClusterer; -class DelphesTreeReader; -class DelphesMA5tuneTreeReader; -class DelphesMemoryInterface; - -class RecEventFormat -{ - friend class LHEReader; - friend class LHCOReader; - friend class ROOTReader; - friend class TauTagger; - friend class bTagger; - friend class JetClusterer; - friend class DelphesTreeReader; - friend class DelphesMA5tuneTreeReader; - friend class DelphesMemoryInterface; - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private : - - /// Collection of reconstructed photons - std::vector photons_; - - /// Collection of reconstructed electrons - std::vector electrons_; - - /// Collection of reconstructed muons - std::vector muons_; - - /// Collection of reconstructed taus - std::vector taus_; - - /// Collection of reconstructed jets - std::vector jets_; - - /// Collection of reconstructed fat jets - std::vector fatjets_; - - /// Collection of generated jets - std::vector genjets_; - - /// Collection of reconstructed tracks - MAbool tracks_ok_; - std::vector tracks_; - - /// Collection of reconstructed vertices - MAbool vertices_ok_; - std::vector vertices_; - - /// Reconstructed towers - MAbool towers_ok_; - std::vector towers_; - - /// Collection of reconstructed EFlow tracks - MAbool EFlowTracks_ok_; - std::vector EFlowTracks_; - - /// Collection of reconstructed EFlow tracks - MAbool EFlowPhotons_ok_; - std::vector EFlowPhotons_; - - /// Collection of reconstructed EFlow tracks - MAbool EFlowNeutralHadrons_ok_; - std::vector EFlowNeutralHadrons_; - - /// Reconstructed Missing Transverse Energy - RecParticleFormat MET_; - - /// Reconstructed Missing Hadronic Transverse Energy - RecParticleFormat MHT_; - - /// Reconstructed Scalar sum of transverse energy - MAfloat64 TET_; - - /// Reconstructed Scalar sum of hadronic transverse energy - MAfloat64 THT_; - - /// Computed total effective mass (sum of jet's PT + MET - MAfloat64 Meff_; - - /// Monte Carlo taus decaying hadronically - std::vector MCHadronicTaus_; - - /// Monte Carlo taus decaying into muon - std::vector MCMuonicTaus_; - - /// Monte Carlo taus decaying into electron - std::vector MCElectronicTaus_; - - /// Monte Carlo b-quarks - std::vector MCBquarks_; + namespace Substructure { + class ClusterBase; + } + class LHEReader; + class LHCOReader; + class ROOTReader; + class TauTagger; + class bTagger; + class SFSTaggerBase; + class JetClusterer; + class ClusterAlgoBase; + class ClusterAlgoFastJet; + class DelphesTreeReader; + class DelphesMA5tuneTreeReader; + class DelphesMemoryInterface; + + class RecEventFormat + { + friend class LHEReader; + friend class LHCOReader; + friend class ROOTReader; + friend class TauTagger; + friend class bTagger; + friend class SFSTaggerBase; + friend class JetClusterer; + friend class ClusterAlgoBase; + friend class ClusterAlgoFastJet; + friend class DelphesTreeReader; + friend class DelphesMA5tuneTreeReader; + friend class DelphesMemoryInterface; + friend class Substructure::ClusterBase; + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private : + + /// Collection of reconstructed photons + std::vector photons_; + + /// Collection of reconstructed electrons + std::vector electrons_; + + /// Collection of reconstructed muons + std::vector muons_; + + /// Collection of reconstructed taus + std::vector taus_; + + // Identification of the primary jet. Corresponds to content of the jets_ + std::string PrimaryJetID_; + + /// Collection of reconstructed jet dictionary + // @JACK note for the future: if lots of jet input is used change map + // to unordered map for efficiency UI is the same! + // 29.09.2022 - Jack: the fatjet and genjet collections are added to jetcollection + std::map > jetcollection_; + +#ifdef MA5_FASTJET_MODE + // hadrons to be clustered (code efficiency) + std::vector input_hadrons_; +#endif - /// Monte Carlo c-quarks - std::vector MCCquarks_; + /// Empty jet (useful temporary object) + std::vector emptyjet_; + /// Collection of reconstructed tracks + MAbool tracks_ok_; + std::vector tracks_; - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : + /// Collection of reconstructed vertices + MAbool vertices_ok_; + std::vector vertices_; + + /// Reconstructed towers + MAbool towers_ok_; + std::vector towers_; + + /// Collection of reconstructed EFlow tracks + MAbool EFlowTracks_ok_; + std::vector EFlowTracks_; + + /// Collection of reconstructed EFlow tracks + MAbool EFlowPhotons_ok_; + std::vector EFlowPhotons_; + + /// Collection of reconstructed EFlow tracks + MAbool EFlowNeutralHadrons_ok_; + std::vector EFlowNeutralHadrons_; + + /// Reconstructed Missing Transverse Energy + RecParticleFormat MET_; + + /// Reconstructed Missing Hadronic Transverse Energy + RecParticleFormat MHT_; + + /// Reconstructed Scalar sum of transverse energy + MAfloat64 TET_; + + /// Reconstructed Scalar sum of hadronic transverse energy + MAfloat64 THT_; + + /// Computed total effective mass (sum of jet's PT + MET + MAfloat64 Meff_; + + /// Monte Carlo taus decaying hadronically + std::vector MCHadronicTaus_; + + /// Monte Carlo taus decaying into muon + std::vector MCMuonicTaus_; + + /// Monte Carlo taus decaying into electron + std::vector MCElectronicTaus_; + + /// Monte Carlo b-quarks + std::vector MCBquarks_; + + /// Monte Carlo c-quarks + std::vector MCCquarks_; + + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public : + + /// Constructor without arguments + RecEventFormat() + { Reset(); } + + /// Destructor + ~RecEventFormat() + { + for (auto &p: MCHadronicTaus_) + if (p != 0) delete p; + for (auto &p: MCMuonicTaus_) + if (p != 0) delete p; + for (auto &p: MCElectronicTaus_) + if (p != 0) delete p; + for (auto &p: MCBquarks_) + if (p != 0) delete p; + for (auto &p: MCCquarks_) + if (p != 0) delete p; + } + + /// Accessor to the photon collection (read-only) + const std::vector& photons() const {return photons_;} + + /// Accessor to the electron collection (read-only) + const std::vector& electrons() const {return electrons_;} + + /// Accessor to the muon collection (read-only) + const std::vector& muons() const {return muons_;} + + /// Accessor to the tau collection (read-only) + const std::vector& taus() const {return taus_;} + + /// Accessor to the fat jet collection (read-only) + const std::vector& fatjets() const + { + std::string id = "fatjet"; + if (jetcollection_.find(id) != jetcollection_.end()) + return jetcollection_.at(id); + else + { + return emptyjet_; + } + } + + /// Accessor to the jet collection (read-only) + const std::vector& jets() const + { + if (jetcollection_.find(PrimaryJetID_) != jetcollection_.end()) + return jetcollection_.at(PrimaryJetID_); + else + { + return emptyjet_; + } + } + + /// Accessor to the jet collection dictionary (read-only) + const std::map >& jetcollection() const {return jetcollection_;} + + // Accessor to a specific jet dictionary (read-only) + const std::vector& jets(std::string id) const + { + if (jetcollection_.find(id) != jetcollection_.end()) + return jetcollection_.at(id); + else + { + return emptyjet_; + } + } + + /// Accessor to the genjet collection (read-only) + const std::vector& genjets() const + { + std::string id = "genjet"; + if (jetcollection_.find(id) != jetcollection_.end()) + return jetcollection_.at(id); + else + { + return emptyjet_; + } + } + + /// Accessor to the track collection (read-only) + const std::vector& tracks() const {return tracks_;} + + /// Accessor to the vertex collection (read-only) + const std::vector& vertex() const {return vertices_;} + + /// Accessor to the tower collection (read-only) + const std::vector& towers() const {return towers_;} + const std::vector& EFlowTracks() const {return EFlowTracks_;} + const std::vector& EFlowPhotons() const {return EFlowPhotons_;} + const std::vector& EFlowNeutralHadrons() const {return EFlowNeutralHadrons_;} + + /// Accessor to the Missing Transverse Energy (read-only) + const RecParticleFormat& MET() const {return MET_;} + + /// Accessor to the Missing Hadronic Transverse Energy (read-only) + const RecParticleFormat& MHT() const {return MHT_;} + + /// Accessor to the Total Transverse Energy (read-only) + const MAfloat64& TET() const {return TET_;} + + /// Accessor to the Total Hadronic Transverse Energy (read-only) + const MAfloat64& THT() const {return THT_;} + + /// Accessor to the Total effective mass (read-only) + const MAfloat64& Meff() const {return Meff_;} + + /// Accessor to the Monte Carlo taus decaying hadronically + const std::vector& MCHadronicTaus() const + {return MCHadronicTaus_;} + + /// Accessor to Monte Carlo taus decaying into muon + const std::vector& MCMuonicTaus() const + {return MCMuonicTaus_;} + + /// Accessor to Monte Carlo taus decaying into electron + const std::vector& MCElectronicTaus() const + {return MCElectronicTaus_;} + + /// Accessor to Monte Carlo b-quarks + const std::vector& MCBquarks() const + {return MCBquarks_;} + + /// Accessor to Monte Carlo c-quarks + const std::vector& MCCquarks() const + {return MCCquarks_;} + + /// Accessor to the photon collection + std::vector& photons() {return photons_;} + + /// Accessor to the electron collection + std::vector& electrons() {return electrons_;} + + /// Accessor to the muon collection + std::vector& muons() {return muons_;} + + /// Accessor to the tau collection + std::vector& taus() {return taus_;} + + /// Accessor to the jet collection + std::vector& jets() + { + if (jetcollection_.find(PrimaryJetID_) != jetcollection_.end()) + return jetcollection_.at(PrimaryJetID_); + else + { + return emptyjet_; + } + } + + /// Accessor to the jet dictionary + std::map >& jetcollection() {return jetcollection_;} + + /// Accessor to a specific jet in the dictionary + std::vector& jets(std::string id) + { + if (jetcollection_.find(id) != jetcollection_.end()) + return jetcollection_.at(id); + else + { + return emptyjet_; + } + } + + /// Accessor to the fat jet collection + std::vector& fatjets() + { + std::string id = "fatjet"; + if (jetcollection_.find(id) != jetcollection_.end()) + return jetcollection_.at(id); + else + { + return emptyjet_; + } + } + + /// Accessor to the towers collection + std::vector& towers() {return towers_;} + std::vector& EFlowTracks() {return EFlowTracks_;} + std::vector& EFlowPhotons() {return EFlowPhotons_;} + std::vector& EFlowNeutralHadrons() {return EFlowNeutralHadrons_;} + + /// Accessor to the jet collection + std::vector& genjets() + { + std::string id = "genjet"; + if (jetcollection_.find(id) != jetcollection_.end()) + return jetcollection_.at(id); + else + { + return emptyjet_; + } + } + + /// Accessor to the track collection + std::vector& tracks() {return tracks_;} + + /// Accessor to the Missing Transverse Energy + RecParticleFormat& MET() {return MET_;} + + /// Accessor to the Missing Hadronic Transverse Energy + RecParticleFormat& MHT() {return MHT_;} + + /// Accessor to the Total Transverse Energy + MAfloat64& TET() {return TET_;} + + /// Accessor to the Total Hadronic Transverse Energy + MAfloat64& THT() {return THT_;} + + /// Accessor to the Total effective mass + MAfloat64& Meff() {return Meff_;} + + /// Accessor to the Monte Carlo taus decaying hadronically + std::vector& MCHadronicTaus() + {return MCHadronicTaus_;} + + /// Accessor to Monte Carlo taus decaying into muon + std::vector& MCMuonicTaus() + {return MCMuonicTaus_;} + + /// Accessor to Monte Carlo taus decaying into electron + std::vector& MCElectronicTaus() + {return MCElectronicTaus_;} + + /// Accessor to Monte Carlo b-quarks + std::vector& MCBquarks() + {return MCBquarks_;} + + /// Accessor to Monte Carlo c-quarks + std::vector& MCCquarks() + {return MCCquarks_;} + + /// Clearing all information + void Reset(); + + // Initialize PrimaryJetID + void SetPrimaryJetID(std::string v) {PrimaryJetID_ = v;} + + // Remove an element from jet collection + void Remove_Collection(std::string id); + + /// Change Jet ID + void ChangeJetID(std::string previous_id, std::string new_id); + + // Get the list of jet collection IDs + const std::vector GetJetIDs() const; + + // Check if collection ID exists + MAbool hasJetID(std::string id) { return (jetcollection_.find(id) != jetcollection_.end()); } + + // Add a new hadron to be clustered. (for code efficiency) + void AddHadron(MCParticleFormat& v, MAuint32& idx); + +#ifdef MA5_FASTJET_MODE + // Get hadrons to cluster (code efficiency) + std::vector& cluster_inputs(); +#endif - /// Constructor withtout arguments - RecEventFormat() - { Reset(); } + /// Displaying data member values. + /// @JACK: added for debugging purposes. Does not need to be included in the original code. + void Print() const + { + INFO << " -------------------------------------------" << endmsg; + INFO << " Event Content : " << endmsg; + INFO << " * Jet Content : " << endmsg; + for (auto &col: jetcollection_) + { + std::string tag = col.first==PrimaryJetID_ ? " (Primary)" : " "; + INFO << " - Jet ID = " << col.first << ", Number of Jets = " + << col.second.size() << tag << endmsg; + } + INFO << " * Number of Taus = " << taus_.size() << endmsg; + INFO << " * Number of Electrons = " << electrons_.size() << endmsg; + INFO << " * Number of Muons = " << muons_.size() << endmsg; + INFO << " * Number of Photons = " << photons_.size() << endmsg; + INFO << " -------------------------------------------" << endmsg; + } - /// Destructor - ~RecEventFormat() - { - for (auto &p: MCHadronicTaus_) - if (p != 0) delete p; - for (auto &p: MCMuonicTaus_) - if (p != 0) delete p; - for (auto &p: MCElectronicTaus_) - if (p != 0) delete p; - for (auto &p: MCBquarks_) - if (p != 0) delete p; - for (auto &p: MCCquarks_) - if (p != 0) delete p; - } + /// Giving a new photon entry + RecPhotonFormat* GetNewPhoton(); - /// Accessor to the photon collection (read-only) - const std::vector& photons() const {return photons_;} + /// Giving a new electron entry + RecLeptonFormat* GetNewElectron(); - /// Accessor to the electron collection (read-only) - const std::vector& electrons() const {return electrons_;} + /// Giving a new muon entry + RecLeptonFormat* GetNewMuon(); - /// Accessor to the muon collection (read-only) - const std::vector& muons() const {return muons_;} + /// Giving a new tower entry + RecTowerFormat* GetNewTower(); - /// Accessor to the tau collection (read-only) - const std::vector& taus() const {return taus_;} + /// Giving a new EFlowTrack entry + RecTrackFormat* GetNewEFlowTrack(); - /// Accessor to the fat jet collection (read-only) - const std::vector& fatjets() const {return fatjets_;} + /// Giving a new EFlowPhoton entry + RecParticleFormat* GetNewEFlowPhoton(); - /// Accessor to the jet collection (read-only) - const std::vector& jets() const {return jets_;} + /// Giving a new EFlowNeutralHadron entry + RecParticleFormat* GetNewEFlowNeutralHadron(); - /// Accessor to the genjet collection (read-only) - const std::vector& genjets() const {return genjets_;} + /// Giving a new tau entry + RecTauFormat* GetNewTau(); - /// Accessor to the track collection (read-only) - const std::vector& tracks() const {return tracks_;} + /// Giving a new primary jet entry + RecJetFormat* GetNewJet(); - /// Accessor to the vertex collection (read-only) - const std::vector& vertex() const {return vertices_;} + /// Giving a new primary jet entry + void CreateEmptyJetAccesor(); - /// Accessor to the tower collection (read-only) - const std::vector& towers() const {return towers_;} - const std::vector& EFlowTracks() const {return EFlowTracks_;} - const std::vector& EFlowPhotons() const {return EFlowPhotons_;} - const std::vector& EFlowNeutralHadrons() const {return EFlowNeutralHadrons_;} + // Get a new jet entry with specific ID + RecJetFormat* GetNewJet(std::string id); - /// Accessor to the Missing Transverse Energy (read-only) - const RecParticleFormat& MET() const {return MET_;} + // Create an empty jet accessor with specific id + void CreateEmptyJetAccesor(std::string id); - /// Accessor to the Missing Hadronic Transverse Energy (read-only) - const RecParticleFormat& MHT() const {return MHT_;} + /// Giving a new fat jet entry + RecJetFormat* GetNewFatJet(); - /// Accessor to the Total Transverse Energy (read-only) - const MAfloat64& TET() const {return TET_;} + /// Giving a new gen jet entry + RecJetFormat* GetNewGenJet(); - /// Accessor to the Total Hadronic Transverse Energy (read-only) - const MAfloat64& THT() const {return THT_;} + /// Giving a new track entry + RecTrackFormat* GetNewTrack(); - /// Accessor to the Total effective mass (read-only) - const MAfloat64& Meff() const {return Meff_;} + /// Giving a new vertex entry + RecVertexFormat* GetNewVertex(); - /// Accessor to the Monte Carlo taus decaying hadronically - const std::vector& MCHadronicTaus() const - {return MCHadronicTaus_;} + /// Giving a pointer to the Missing Transverse Energy + RecParticleFormat* GetNewMet(); - /// Accessor to Monte Carlo taus decaying into muon - const std::vector& MCMuonicTaus() const - {return MCMuonicTaus_;} + /// Giving a pointer to the Missing Transverse Energy + RecParticleFormat* GetNewMht(); - /// Accessor to Monte Carlo taus decaying into electron - const std::vector& MCElectronicTaus() const - {return MCElectronicTaus_;} - - /// Accessor to Monte Carlo b-quarks - const std::vector& MCBquarks() const - {return MCBquarks_;} - - /// Accessor to Monte Carlo c-quarks - const std::vector& MCCquarks() const - {return MCCquarks_;} - - /// Accessor to the electron collection - std::vector& photons() {return photons_;} - - /// Accessor to the electron collection - std::vector& electrons() {return electrons_;} - - /// Accessor to the muon collection - std::vector& muons() {return muons_;} - - /// Accessor to the tau collection - std::vector& taus() {return taus_;} - - /// Accessor to the jet collection - std::vector& jets() {return jets_;} - - /// Accessor to the fat jet collection - std::vector& fatjets() {return fatjets_;} - - /// Accessor to the towers collection - std::vector& towers() {return towers_;} - std::vector& EFlowTracks() {return EFlowTracks_;} - std::vector& EFlowPhotons() {return EFlowPhotons_;} - std::vector& EFlowNeutralHadrons() {return EFlowNeutralHadrons_;} - - /// Accessor to the jet collection - std::vector& genjets() {return genjets_;} - - /// Accessor to the track collection - std::vector& tracks() {return tracks_;} - - /// Accessor to the Missing Transverse Energy - RecParticleFormat& MET() {return MET_;} - - /// Accessor to the Missing Hadronic Transverse Energy - RecParticleFormat& MHT() {return MHT_;} - - /// Accessor to the Total Transverse Energy - MAfloat64& TET() {return TET_;} - - /// Accessor to the Total Hadronic Transverse Energy - MAfloat64& THT() {return THT_;} - - /// Accessor to the Total effective mass - MAfloat64& Meff() {return Meff_;} - - /// Accessor to the Monte Carlo taus decaying hadronically - std::vector& MCHadronicTaus() - {return MCHadronicTaus_;} - - /// Accessor to Monte Carlo taus decaying into muon - std::vector& MCMuonicTaus() - {return MCMuonicTaus_;} - - /// Accessor to Monte Carlo taus decaying into electron - std::vector& MCElectronicTaus() - {return MCElectronicTaus_;} - - /// Accessor to Monte Carlo b-quarks - std::vector& MCBquarks() - {return MCBquarks_;} - - /// Accessor to Monte Carlo c-quarks - std::vector& MCCquarks() - {return MCCquarks_;} - - /// Clearing all information - void Reset() - { - photons_.clear(); - electrons_.clear(); - muons_.clear(); - taus_.clear(); - jets_.clear(); - fatjets_.clear(); - towers_ok_=false; - towers_.clear(); - tracks_ok_=false; - tracks_.clear(); - vertices_ok_=false; - vertices_.clear(); - EFlowTracks_ok_=false; - EFlowTracks_.clear(); - EFlowPhotons_ok_=false; - EFlowPhotons_.clear(); - EFlowNeutralHadrons_ok_=false; - EFlowNeutralHadrons_.clear(); - genjets_.clear(); - MET_.Reset(); - MHT_.Reset(); - TET_ = 0.; - THT_ = 0.; - Meff_ = 0.; - MCHadronicTaus_.clear(); - MCMuonicTaus_.clear(); - MCElectronicTaus_.clear(); - MCBquarks_.clear(); - MCCquarks_.clear(); - } - - /// Displaying data member values - void Print() const - { - } - - /// Giving a new photon entry - RecPhotonFormat* GetNewPhoton() - { - photons_.push_back(RecPhotonFormat()); - return &photons_.back(); - } - - /// Giving a new electron entry - RecLeptonFormat* GetNewElectron() - { - electrons_.push_back(RecLeptonFormat()); - (&electrons_.back())->setElectronId(); - return &electrons_.back(); - } - - /// Giving a new muon entry - RecLeptonFormat* GetNewMuon() - { - muons_.push_back(RecLeptonFormat()); - (&muons_.back())->setMuonId(); - return &muons_.back(); - } - - /// Giving a new tower entry - RecTowerFormat* GetNewTower() - { - towers_.push_back(RecTowerFormat()); - return &towers_.back(); - } - - /// Giving a new EFlowTrack entry - RecTrackFormat* GetNewEFlowTrack() - { - EFlowTracks_.push_back(RecTrackFormat()); - return &EFlowTracks_.back(); - } - - /// Giving a new EFlowPhoton entry - RecParticleFormat* GetNewEFlowPhoton() - { - EFlowPhotons_.push_back(RecParticleFormat()); - return &EFlowPhotons_.back(); - } - - /// Giving a new EFlowNeutralHadron entry - RecParticleFormat* GetNewEFlowNeutralHadron() - { - EFlowNeutralHadrons_.push_back(RecParticleFormat()); - return &EFlowNeutralHadrons_.back(); - } - - /// Giving a new tau entry - RecTauFormat* GetNewTau() - { - taus_.push_back(RecTauFormat()); - return &taus_.back(); - } - - /// Giving a new jet entry - RecJetFormat* GetNewJet() - { - jets_.push_back(RecJetFormat()); - return &jets_.back(); - } - - /// Giving a new fat jet entry - RecJetFormat* GetNewFatJet() - { - fatjets_.push_back(RecJetFormat()); - return &fatjets_.back(); - } - - /// Giving a new gen jet entry - RecJetFormat* GetNewGenJet() - { - genjets_.push_back(RecJetFormat()); - return &genjets_.back(); - } - - /// Giving a new track entry - RecTrackFormat* GetNewTrack() - { - tracks_.push_back(RecTrackFormat()); - return &tracks_.back(); - } - - /// Giving a new vertex entry - RecVertexFormat* GetNewVertex() - { - vertices_.push_back(RecVertexFormat()); - return &vertices_.back(); - } - - /// Giving a pointer to the Missing Transverse Energy - RecParticleFormat* GetNewMet() - { return &MET_; } - - /// Giving a pointer to the Missing Transverse Energy - RecParticleFormat* GetNewMht() - { return &MHT_; } - -}; + }; } diff --git a/tools/SampleAnalyzer/Commons/DataFormat/RecJetFormat.cpp b/tools/SampleAnalyzer/Commons/DataFormat/RecJetFormat.cpp new file mode 100644 index 00000000..8f1580bd --- /dev/null +++ b/tools/SampleAnalyzer/Commons/DataFormat/RecJetFormat.cpp @@ -0,0 +1,90 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#include "SampleAnalyzer/Commons/DataFormat/RecJetFormat.h" + +#ifdef MA5_FASTJET_MODE + +namespace MA5 { + + /// Add one constituent + void RecJetFormat::AddConstituent(const MAint32& index) { Constituents_.push_back(index); } + + /// get constituent collections + const std::vector& RecJetFormat::constituents() const { return Constituents_; } + + /// Add one isolation cone + void RecJetFormat::AddIsolCone (const IsolationConeType& cone) { isolCones_.push_back(cone); } + + /// get the collection of isolation cones + const std::vector& RecJetFormat::isolCones() const { return isolCones_; } + + // return a vector of all subjets of the current jet (in the sense of the exclusive algorithm) + // that would be obtained when running the algorithm with the given dcut. + std::vector RecJetFormat::exclusive_subjets(MAfloat32 dcut) const + { + std::vector output_jets; + try { + if (!RecJetFormat::has_exclusive_subjets()) + throw EXCEPTION_ERROR("This jet structure does not contain exclusive_subjets", + "Exclusive subjets only exist for jets clustered through an exclusive algorithm.", 0); + } catch (const std::exception& err) { + MANAGE_EXCEPTION(err); + return output_jets; + } + std::vector current_jets = fastjet::sorted_by_pt(pseudojet_.exclusive_subjets(dcut)); + output_jets.reserve(current_jets.size()); + for (auto &jet: current_jets) + { + RecJetFormat * NewJet = new RecJetFormat(jet); + output_jets.push_back(NewJet); + } + return output_jets; + } + + // return the list of subjets obtained by unclustering the supplied jet down to nsub subjets. + std::vector RecJetFormat::exclusive_subjets(MAint32 nsub) const + { + std::vector output_jets; + try { + if (!RecJetFormat::has_exclusive_subjets()) + throw EXCEPTION_ERROR("This jet structure does not contain exclusive_subjets", + "Exclusive subjets only exist for jets clustered through an exclusive algorithm.", 0); + } catch (const std::exception& err) { + MANAGE_EXCEPTION(err); + return output_jets; + } + std::vector current_jets = fastjet::sorted_by_pt(pseudojet_.exclusive_subjets(nsub)); + output_jets.reserve(current_jets.size()); + for (auto &jet: current_jets) + { + RecJetFormat * NewJet = new RecJetFormat(jet); + output_jets.push_back(NewJet); + } + return output_jets; + } + + //returns true if the PseudoJet has support for exclusive subjets + MAbool RecJetFormat::has_exclusive_subjets() const { return pseudojet_.has_exclusive_subjets(); } +} +#endif diff --git a/tools/SampleAnalyzer/Commons/DataFormat/RecJetFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/RecJetFormat.h index cf71ebff..a0142f44 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/RecJetFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/RecJetFormat.h @@ -37,131 +37,320 @@ #include "SampleAnalyzer/Commons/DataFormat/RecParticleFormat.h" #include "SampleAnalyzer/Commons/Service/LogService.h" +// FastJet headers +#ifdef MA5_FASTJET_MODE +#include "fastjet/PseudoJet.hh" +#endif namespace MA5 { + namespace Substructure { + class ClusterBase; + class Pruner; + class Nsubjettiness; + class SoftDrop; + class Filter; + class EnergyCorrelator; + } + class LHCOReader; + class ROOTReader; + class DelphesTreeReader; + class DelphesMA5tuneTreeReader; + class DetectorDelphes; + class DetectorDelphesMA5tune; + class DelphesMemoryInterface; + class SFSTaggerBase; + + class RecJetFormat : public RecParticleFormat + { + + friend class LHCOReader; + friend class ROOTReader; + friend class ClusterAlgoFastJet; + friend class bTagger; + friend class TauTagger; + friend class cTagger; + friend class SFSTaggerBase; + friend class DetectorDelphes; + friend class DetectorDelphesMA5tune; + friend class DelphesTreeReader; + friend class DelphesMA5tuneTreeReader; + friend class DelphesMemoryInterface; + + // Substructure methods + friend class Substructure::ClusterBase; + friend class Substructure::Pruner; + friend class Substructure::Nsubjettiness; + friend class Substructure::SoftDrop; + friend class Substructure::Filter; + friend class Substructure::EnergyCorrelator; + + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + + MAuint16 ntracks_; /// number of tracks + + /// Tags are separated into 4 cathegories truth, loose, mid, tight. + /// Truth is used for MC event tagging rest is from detector simulations. + /// Loose tagging will be used as default for backwards compatibility btag() + /// ctag(), tautag() will return loose tagging criteria. + MAbool loose_btag_; /// loose b-tag + MAbool loose_ctag_; /// loose c-tag + MAbool loose_tautag_; /// loose tau-tag + + MAbool mid_btag_; /// tight b-tag + MAbool mid_ctag_; /// tight c-tag + MAbool mid_tautag_; /// tight tau-tag + + MAbool tight_btag_; /// tight b-tag + MAbool tight_ctag_; /// tight c-tag + MAbool tight_tautag_; /// tight tau-tag + + MAbool true_ctag_; /// c-tag (before id or misid) + MAbool true_btag_; /// b-tag (before id or misid) + MAbool true_tautag_; /// tau-tag (before id or misid) + + std::vector Constituents_; /// indices of the MC particles + std::vector isolCones_; // isolation cones + +#ifdef MA5_FASTJET_MODE + // @Jack: Save the modified jet as pseudojet for jet substructure applications + // This will make it faster and avoid extra for loops. + fastjet::PseudoJet pseudojet_; +#endif + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + + /// Constructor without arguments + RecJetFormat() + { clear(); } + + /// Constructor with argument + RecJetFormat(MAfloat64 pt, MAfloat64 eta, MAfloat64 phi, MAfloat64 m) + { clear(); momentum_.SetPtEtaPhiM(pt,eta,phi,m); } + + /// Constructor with argument + RecJetFormat(const MALorentzVector& p) + { clear(); momentum_.SetPxPyPzE(p.Px(),p.Py(),p.Pz(),p.E()); } + +#ifdef MA5_FASTJET_MODE + /// Constructor with argument + RecJetFormat(fastjet::PseudoJet& jet) + { + clear(); + momentum_.SetPxPyPzE(jet.px(), jet.py(), jet.pz(), jet.e()); + pseudojet_=jet; + } +#endif -class LHCOReader; -class ROOTReader; -class DelphesTreeReader; -class DelphesMA5tuneTreeReader; -class DetectorDelphes; -class DetectorDelphesMA5tune; -class DelphesMemoryInterface; + /// Destructor + virtual ~RecJetFormat() + {} + + /// Dump information + virtual void Print() const + { + INFO << "ntracks =" << /*set::setw(8)*/"" << std::left << ntracks_ << ", " + << "loose btag = " << std::left << loose_btag_ << ", " + << "loose ctag = " << std::left << loose_ctag_ << ", " + << "medium btag = " << std::left << mid_btag_ << ", " + << "medium ctag = " << std::left << mid_ctag_ << ", " + << "tight btag = " << std::left << tight_btag_ << ", " + << "tight ctag = " << std::left << tight_ctag_ << ", " + << "loose tautag = " << std::left << loose_tautag_ << ", " + << "medium tautag = " << std::left << mid_tautag_ << ", " + << "tight tautag = " << std::left << tight_tautag_ << ", "; + RecParticleFormat::Print(); + } -class RecJetFormat : public RecParticleFormat -{ + /// Clear all information + virtual void Reset() { clear(); } + + /// Clear all information + void clear() + { + ntracks_ = 0; + loose_btag_ = false; + loose_ctag_ = false; + loose_tautag_ = false; + mid_btag_ = false; + mid_ctag_ = false; + mid_tautag_ = false; + tight_btag_ = false; + tight_ctag_ = false; + tight_tautag_ = false; + true_ctag_ = false; + true_btag_ = false; + true_tautag_ = false; + isolCones_.clear(); + Constituents_.clear(); + } + + /// Accessor to the number of tracks + const MAuint16 ntracks() const {return ntracks_;} + + /// Setting ntracks + void setNtracks(MAuint16 ntracks) { ntracks_ = ntracks; } + + ///==================/// + /// Tagger accessors /// + ///==================/// + + /// Accessor to the loose b-tag + const MAbool& btag() const { return loose_btag(); } + + /// Accessor to the loose c-tag + const MAbool& ctag() const { return loose_ctag(); } + + /// Accessor to the loose c-tag + const MAbool& tautag() const { return loose_tautag(); } + + /// Accessor to the loose b-tag + const MAbool& loose_btag() const { return loose_btag_; } + + /// Accessor to the loose c-tag + const MAbool& loose_ctag() const { return loose_ctag_; } + + /// Accessor to the loose c-tag + const MAbool& loose_tautag() const { return loose_tautag_; } + + /// Accessor to the mid b-tag + const MAbool& mid_btag() const { return mid_btag_; } + + /// Accessor to the mid c-tag + const MAbool& mid_ctag() const { return mid_ctag_; } + + /// Accessor to the mid c-tag + const MAbool& mid_tautag() const { return mid_tautag_; } + + /// Accessor to the tight b-tag + const MAbool& tight_btag() const { return tight_btag_; } + + /// Accessor to the tight c-tag + const MAbool& tight_ctag() const { return tight_ctag_; } + + /// Accessor to the tight c-tag + const MAbool& tight_tautag() const { return tight_tautag_; } + + /// Accessor to the true c-tag + const MAbool& true_ctag() const {return true_ctag_;} + + /// Accessor to the true b-tag + const MAbool& true_btag() const {return true_btag_;} + + /// Accessor to the true tau-tag + const MAbool& true_tautag() const {return true_tautag_;} + + /// Setters for tagger + + /// Setting a new true_btag_ value + void setTrueBtag(const MAbool& tag) { true_btag_ = tag;} - friend class LHCOReader; - friend class ROOTReader; - friend class ClusterAlgoFastJet; - friend class bTagger; - friend class TauTagger; - friend class cTagger; - friend class DetectorDelphes; - friend class DetectorDelphesMA5tune; - friend class DelphesTreeReader; - friend class DelphesMA5tuneTreeReader; - friend class DelphesMemoryInterface; - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected: - - MAbool btag_; /// b-tag - MAbool ctag_; /// c-tag - MAbool true_ctag_; /// c-tag (before id or misid) - MAbool true_btag_; /// b-tag (before id or misid) - std::vector Constituents_; /// indices of the MC particles - std::vector isolCones_; // isolation cones - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - - /// Constructor without arguments - RecJetFormat() - { Reset(); } - - /// Destructor - virtual ~RecJetFormat() - {} - - /// Dump information - virtual void Print() const - { - INFO << "ntracks =" << /*set::setw(8)*/"" << std::left << ntracks_ << ", " - << "btag = " << /*set::setw(8)*/"" << std::left << btag_ << ", " - << "ctag = " << /*set::setw(8)*/"" << std::left << ctag_ << ", "; - RecParticleFormat::Print(); - } - - /// Clear all information - virtual void Reset() - { - btag_ = false; - ctag_ = false; - true_btag_ = false; - true_ctag_ = false; - isolCones_.clear(); - } - - /// Accessor to the b-tag - const MAbool& btag() const - {return btag_;} - - /// Accessor to the c-tag - const MAbool& ctag() const - {return ctag_;} - - /// Accessor to the true c-tag - const MAbool& true_ctag() const - {return true_ctag_;} - - /// Accessor to the true b-tag - const MAbool& true_btag() const - {return true_btag_;} - - /// Setting a new true_btag_ value - void setTrueBtag(const MAbool& tag) - {true_btag_=tag;} - - /// Setting a new btag_ value - void setBtag(const MAbool& tag) - {btag_=tag;} - - /// Setting a new true_ctag_ value - void setCtag(const MAbool& tag) - {ctag_=tag;} - - /// Setting a new ctag_ value - void setTrueCtag(const MAbool& tag) - {true_ctag_=tag;} - - /// Setting ntracks - void setNtracks(MAuint16 ntracks) - { ntracks_=ntracks; } - - /// Add one constituent - void AddConstituent (const MAint32& index) - {Constituents_.push_back(index);} - - /// get constituent collections - const std::vector& constituents() const - { return Constituents_; } - - /// Add one isolation cone - void AddIsolCone (const IsolationConeType& cone) - {isolCones_.push_back(cone);} - - /// get the collection of isolation cones - const std::vector& isolCones() const - { return isolCones_; } - -}; + /// Setting a new true_ctag_ value + void setTrueCtag(const MAbool& tag) { true_ctag_ = tag;} + + /// Setting a new true_tautag_ value + void setTrueTautag(const MAbool& tag) { true_tautag_ = tag;} + /// Setting a new loose_btag_ value + void setBtag(const MAbool& tag) { setLooseBtag(tag); } + + /// Setting a new loose_ctag_ value + void setCtag(const MAbool& tag) { setLooseCtag(tag); } + + /// Setting a new loose_tautag_ value + void setTautag(const MAbool& tag) { setLooseTautag(tag); } + + /// Setting a new loose_btag_ value + void setLooseBtag(const MAbool& tag) { loose_btag_ = tag; } + + /// Setting a new loose_ctag_ value + void setLooseCtag(const MAbool& tag) { loose_ctag_ = tag; } + + /// Setting a new loose_tautag_ value + void setLooseTautag(const MAbool& tag) { loose_tautag_ = tag; } + + /// Setting a new Mid_btag_ value + void setMidBtag(const MAbool& tag) { mid_btag_ = tag; } + + /// Setting a new Mid_ctag_ value + void setMidCtag(const MAbool& tag) { mid_ctag_ = tag; } + + /// Setting a new Mid_tautag_ value + void setMidTautag(const MAbool& tag) { mid_tautag_ = tag; } + + /// Setting a new Tight_btag_ value + void setTightBtag(const MAbool& tag) { tight_btag_ = tag; } + + /// Setting a new Tight_ctag_ value + void setTightCtag(const MAbool& tag) { tight_ctag_ = tag; } + + /// Setting a new Tight_tautag_ value + void setTightTautag(const MAbool& tag) { tight_tautag_ = tag; } + + /// Set all b-tags + void setAllBtags(const MAbool &tag) { + true_btag_ = tag; + loose_btag_ = tag; + mid_btag_ = tag; + tight_btag_ = tag; + } + + /// Set all c-tags + void setAllCtags(const MAbool &tag) { + true_ctag_ = tag; + loose_ctag_ = tag; + mid_ctag_ = tag; + tight_ctag_ = tag; + } + + /// Set all tau-tags + void setAllTautags(const MAbool &tag) { + true_tautag_ = tag; + loose_tautag_ = tag; + mid_tautag_ = tag; + tight_tautag_ = tag; + } + + /// Add one constituent + void AddConstituent (const MAint32& index); + + /// get constituent collections + const std::vector& constituents() const; + + /// Add one isolation cone + void AddIsolCone (const IsolationConeType& cone); + + /// get the collection of isolation cones + const std::vector& isolCones() const; + +#ifdef MA5_FASTJET_MODE + // Accessor for pseudojets + const fastjet::PseudoJet& pseudojet() const {return pseudojet_;} + + // return a vector of all subjets of the current jet (in the sense of the exclusive algorithm) + // that would be obtained when running the algorithm with the given dcut. + std::vector exclusive_subjets(MAfloat32 dcut) const; + + // return the list of subjets obtained by unclustering the supplied jet down to nsub subjets. + std::vector exclusive_subjets(MAint32 nsub) const; + + //returns true if the PseudoJet has support for exclusive subjets + MAbool has_exclusive_subjets() const; + + // Add one pseudojet + void setPseudoJet (const fastjet::PseudoJet& v) {pseudojet_=v;} + void setPseudoJet (MALorentzVector& v) + { + pseudojet_=fastjet::PseudoJet(v.Px(), v.Py(), v.Pz(), v.E()); + } +#endif + }; } #endif diff --git a/tools/SampleAnalyzer/Commons/DataFormat/RecTauFormat.h b/tools/SampleAnalyzer/Commons/DataFormat/RecTauFormat.h index 1b5c31c6..063851ec 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/RecTauFormat.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/RecTauFormat.h @@ -33,7 +33,7 @@ #include // SampleAnalyzer headers -#include "SampleAnalyzer/Commons/DataFormat/RecParticleFormat.h" +#include "SampleAnalyzer/Commons/DataFormat/RecJetFormat.h" #include "SampleAnalyzer/Commons/Service/LogService.h" @@ -47,8 +47,9 @@ class DelphesMA5tuneTreeReader; class DetectorDelphes; class DetectorDelphesMA5tune; class DelphesMemoryInterface; +class SFSTaggerBase; -class RecTauFormat : public RecParticleFormat +class RecTauFormat : public RecJetFormat { friend class LHCOReader; @@ -59,6 +60,7 @@ class RecTauFormat : public RecParticleFormat friend class DetectorDelphes; friend class DetectorDelphesMA5tune; friend class DelphesMemoryInterface; + friend class SFSTaggerBase; // ------------------------------------------------------------- // data members diff --git a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h index 9de39994..b154a245 100644 --- a/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h +++ b/tools/SampleAnalyzer/Commons/DataFormat/WeightCollection.h @@ -2,30 +2,28 @@ // // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef WEIGHT_COLLECTION_H #define WEIGHT_COLLECTION_H - // STL headers #include #include @@ -38,132 +36,140 @@ #include "SampleAnalyzer/Commons/Service/LogService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - namespace MA5 { -class WeightCollection -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private: - std::map weights_; - static const MAfloat64 emptyvalue_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor withtout arguments - WeightCollection() - { } - - /// Destructor - ~WeightCollection() - { } - - /// Clear all the content - void Reset() - { weights_.clear(); } - void clear() {Reset();} - - /// Size - MAuint32 size() const - { return weights_.size(); } - - /// Add a new weight group - MAbool Add(MAuint32 id, MAfloat64 value) + class WeightCollection { - // Try to add the item - std::pair::iterator,bool> ret; - ret = weights_.insert(std::pair(id,value)); - // Is it added? - try + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + private: + std::map weights_; + static const MAfloat64 emptyvalue_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// Constructor withtout arguments + WeightCollection() { - if (!ret.second) - { - std::stringstream str; - str << id; - std::string idname; - str >> idname; - throw EXCEPTION_WARNING("The Weight '"+idname+ - "' is defined at two times. Redundant values are skipped.","",0); - } } - catch(const std::exception& e) + + /// Destructor + ~WeightCollection() { - MANAGE_EXCEPTION(e); - return false; } - return true; - } - + /// Clear all the content + void Reset() + { + weights_.clear(); + } + void clear() { Reset(); } - /// Get all the Weight Collection - const std::map& GetWeights() const - { return weights_; } + /// Size + MAuint32 size() const + { + return weights_.size(); + } - /// Get a weight - const MAfloat64& Get(MAuint32 id) const - { - // Try to get the item - std::map::const_iterator it= weights_.find(id); - try + /// Add a new weight group + MAbool Add(MAuint32 id, MAfloat64 value) { - if (it!=weights_.end()) + // Try to add the item + std::pair::iterator, bool> ret; + ret = weights_.insert(std::pair(id, value)); + + // Is it added? + try { - std::stringstream str; - str << id; - std::string idname; - str >> idname; - throw EXCEPTION_ERROR("The Weight '"+idname+ - "' is not defined. Return null value.","",0); + if (!ret.second) + { + std::stringstream str; + str << id; + std::string idname; + str >> idname; + throw EXCEPTION_WARNING("The Weight '" + idname + + "' is defined at two times. Redundant values are skipped.", + "", 0); + } } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return false; + } + + return true; } - catch(const std::exception& e) + + /// Get all the Weight Collection + const std::map &GetWeights() const { - MANAGE_EXCEPTION(e); - return emptyvalue_; + return weights_; } - return it->second; - } - - - /// Get a weight - const MAfloat64& operator[](MAuint32 id) const - { return Get(id); } - - - /// Add a new weight group - void Print() const - { - if (weights_.empty()) return; - - // Loop over weights for getting max - MAuint32 maxi=0; - for (std::map::const_iterator - it=weights_.begin();it!=weights_.end();it++) + /// Get a weight + const MAfloat64 &Get(MAuint32 id) const { - if (it->first>maxi) maxi=it->first; + // Try to get the item + std::map::const_iterator it = weights_.find(id); + try + { + if (it == weights_.end()) + { + std::stringstream str; + str << id; + std::string idname; + str >> idname; + throw EXCEPTION_ERROR("The Weight '" + idname + + "' is not defined. Return null value.", + "", 0); + } + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return emptyvalue_; + } + + return it->second; } - // Loop over weights - for (std::map::const_iterator - it=weights_.begin();it!=weights_.end();it++) + /// Get a weight + const MAfloat64 &operator[](MAuint32 id) const { - INFO << "ID=" << it->first << " : " << it->second << endmsg; + return Get(id); } - } + /// Add a new weight group + void Print() const + { + if (weights_.empty()) + return; + + // Loop over weights for getting max + MAuint32 maxi = 0; + for (std::map::const_iterator + it = weights_.begin(); + it != weights_.end(); it++) + { + if (it->first > maxi) + maxi = it->first; + } -}; + // Loop over weights + for (std::map::const_iterator + it = weights_.begin(); + it != weights_.end(); it++) + { + INFO << "ID=" << it->first << " : " << it->second << endmsg; + } + } + }; } diff --git a/tools/SampleAnalyzer/Commons/Service/Utils.h b/tools/SampleAnalyzer/Commons/Service/Utils.h index 1acb5fdb..da5a5aae 100644 --- a/tools/SampleAnalyzer/Commons/Service/Utils.h +++ b/tools/SampleAnalyzer/Commons/Service/Utils.h @@ -42,6 +42,33 @@ namespace MA5 { + // ============================= // + // ===== Vector operations ===== // + // ============================= // + + /// Create a new vector by adding two vectors together. + /// @attention this wont change the content of two original vectors + template + std::vector operator+(const std::vector &A, const std::vector &B) + { + std::vector AB; + AB.reserve(A.size() + B.size()); // preallocate memory + AB.insert(AB.end(), A.begin(), A.end()); // add A; + AB.insert(AB.end(), B.begin(), B.end()); // add B; + return AB; + } + + /// Add second vector to the first vector + /// @attention this wont create a new vector but + /// will add the second to the first + template + std::vector &operator+=(std::vector &A, const std::vector &B) + { + A.reserve(A.size() + B.size()); // preallocate memory without erase original data + A.insert(A.end(), B.begin(), B.end()); // add B; + return A; // here A could be named AB + } + //===========// // Filtering // //===========// @@ -60,6 +87,20 @@ namespace MA5 return filtered; } + // Example: std::vector signaljets = filter(signaljets, ptmin, etamax); + template + std::vector filter(std::vector& objects, MAfloat64 ptmin, + MAfloat64 absetamax=20., MAfloat64 absetamin=-1.) + { + std::vector filtered; + for(auto & obj: objects) + { + if(obj->pt() < ptmin || obj->abseta() > absetamax || obj->abseta() < absetamin) continue; + filtered.push_back(obj); + } + return filtered; + } + // Example: std::vector filtered_jets = filter_select(event.rec()->jets(), // [] (RecJetFormat jet) { return jet->pt()>50.; }); template @@ -88,34 +129,42 @@ namespace MA5 // Overlap Removal // //=================// - // Overlap Removal + /// @brief Overlap Removal + /// Remove overlaping objects from the first collection (v1) with + /// respect to a minimum deltaR distance from the second collection (v2) template std::vector - OverlapRemoval(std::vector &v1, std::vector &v2, - const MAdouble64 &drmin) + OverlapRemoval(std::vector &v1, std::vector &v2, + const MAdouble64 &drmin) { - // Determining with objects should be removed - std::vector mask(v1.size(),false); - for (MAuint32 j=0;jdr(v1[j]) < drmin) - { - mask[j]=true; - break; - } - - // Building the cleaned container - std::vector cleaned_v1; - for (MAuint32 i=0;i mask(v1.size(),false); + for (MAuint32 j=0;jdr(v1[j]) < drmin) + { + mask[j]=true; + break; + } + + // Building the cleaned container + std::vector cleaned_v1; + for (MAuint32 i=0;idr(el) > 0.2;}); + /// Example: + /// @code + /// signaljets = conditional_removal(signaljets,signalel, + /// [] (const RecJetFormat * jet, const RecLeptonFormat * el) + /// {return jet->dr(el) > 0.2;}); + /// @endcode + /// Remove objects from the first collection (v1) with respect + /// to a boolean function between v1 and second collection. template std::vector conditional_removal( - std::vector &v1, std::vector &v2, FN func + std::vector &v1, std::vector &v2, FN func ) { // Determining with objects should be removed diff --git a/tools/SampleAnalyzer/Commons/Vector/MABoost.h b/tools/SampleAnalyzer/Commons/Vector/MABoost.h index 4b368642..2ffce657 100644 --- a/tools/SampleAnalyzer/Commons/Vector/MABoost.h +++ b/tools/SampleAnalyzer/Commons/Vector/MABoost.h @@ -2,30 +2,28 @@ // // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef MABoost_h #define MABoost_h - // STL headers #include #include @@ -39,97 +37,132 @@ #include "SampleAnalyzer/Commons/Service/LogService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - namespace MA5 { -class MABoost -{ - - public : - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - protected: - - MAdouble64 bx_; - MAdouble64 by_; - MAdouble64 bz_; - - MAdouble64 b2_; - MAdouble64 gamma_; - MAdouble64 gamma2_; - - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - // Constructors - MABoost() - { - bx_=0.; by_=0.; bz_=0; - b2_=0; gamma_=0; gamma2_=0; - } - - MABoost(MAdouble64 bx, MAdouble64 by, MAdouble64 bz) - { setBoostVector(bx,by,bz); } - - // Destructor - ~MABoost() - {} - - // Setting the boost vector - void setBoostVector(MAdouble64 bx, MAdouble64 by, MAdouble64 bz) - { - // boost component - bx_ = bx; - by_ = by; - bz_ = bz; - - // intermediate results - b2_ = bx_*bx_ + by_*by_ + bz_*bz_; - gamma_ = 1.0 / std::sqrt(1.0 - b2_); - gamma2_ = b2_ > 0 ? (gamma_ - 1.0)/b2_ : 0.0; - } - - // Setting the boost vector - void setBoostVector(const MALorentzVector& q) - { - try + class MABoost { - if (q.T()==0) throw EXCEPTION_WARNING("Energy equal to zero. Impossible to compute the boost.","",0); - setBoostVector(q.X()/q.T(),q.Y()/q.T(),q.Z()/q.T()); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - MABoost(); - } - } - - // Boost a MALorentzVector - void boost(MALorentzVector& p) const - { - MAdouble64 bp = bx_*p.X() + by_*p.Y() + bz_*p.Z(); - p.SetX(p.X() + gamma2_*bp*bx_ + gamma_*bx_*p.T()); - p.SetY(p.Y() + gamma2_*bp*by_ + gamma_*by_*p.T()); - p.SetZ(p.Z() + gamma2_*bp*bz_ + gamma_*bz_*p.T()); - p.SetT(gamma_*(p.T() + bp)); - } - - // Operator * - MALorentzVector operator* (const MALorentzVector& q) const - { - MALorentzVector q2 = q; - boost(q2); - return q2; - } - -}; - + + public: + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + protected: + /// @brief value of the velocity on x-axis (px / E) + MAdouble64 bx_; + + /// @brief value of the velocity on y-axis (py / E) + MAdouble64 by_; + + /// @brief value of the velocity on z-axis (pz / E) + MAdouble64 bz_; + + MAdouble64 b2_; + MAdouble64 gamma_; + MAdouble64 gamma2_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + // Constructors + MABoost() + { + bx_ = 0.; + by_ = 0.; + bz_ = 0; + b2_ = 0; + gamma_ = 0; + gamma2_ = 0; + } + + /// @brief Initialise the boost vector + /// @param bx value of the velocity on x-axis (px / E) + /// @param by value of the velocity on y-axis (py / E) + /// @param bz value of the velocity on z-axis (pz / E) + MABoost(MAdouble64 bx, MAdouble64 by, MAdouble64 bz) + { + setBoostVector(bx, by, bz); + } + + /// @brief Initialise boost vector with LorentzVector + /// @param q lorentz vector + MABoost(const MALorentzVector &q) + { + setBoostVector(q); + } + + // Destructor + ~MABoost() {} + + /// @brief Setting the boost vector + /// @param bx value of the velocity on x-axis + /// @param by value of the velocity on y-axis + /// @param bz value of the velocity on z-axis + void setBoostVector(MAdouble64 bx, MAdouble64 by, MAdouble64 bz) + { + // boost component + bx_ = bx; + by_ = by; + bz_ = bz; + + // intermediate results + b2_ = bx_ * bx_ + by_ * by_ + bz_ * bz_; + gamma_ = 1.0 / std::sqrt(1.0 - b2_); + gamma2_ = b2_ > 0 ? (gamma_ - 1.0) / b2_ : 0.0; + } + + /// @brief Setting the boost vector + /// @param q Lorentz vector input + void setBoostVector(const MALorentzVector &q) + { + try + { + if (q.T() == 0) + throw EXCEPTION_WARNING("Energy equal to zero. Impossible to compute the boost.", "", 0); + setBoostVector(q.X() / q.T(), q.Y() / q.T(), q.Z() / q.T()); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + MABoost(); + } + } + + /// @brief Accessor to Beta + /// @return beta value + const MAdouble64 beta() const { return b2_; } + + /// @brief Accessor to gamma + /// @return gamma value + const MAdouble64 gamma() const { return gamma_; } + + /// @brief Accessor to beta vector + /// @return beta vector as MAVector3 + const MAVector3 velocity() const { return MAVector3(bx_, by_, bz_); } + + /// @brief Boost a given lorentz vector + /// @param p lorentz vector to be boosted + void boost(MALorentzVector &p) const + { + MAdouble64 bp = bx_ * p.X() + by_ * p.Y() + bz_ * p.Z(); + p.SetX(p.X() + gamma2_ * bp * bx_ + gamma_ * bx_ * p.T()); + p.SetY(p.Y() + gamma2_ * bp * by_ + gamma_ * by_ * p.T()); + p.SetZ(p.Z() + gamma2_ * bp * bz_ + gamma_ * bz_ * p.T()); + p.SetT(gamma_ * (p.T() + bp)); + } + + /// @brief Boost the given lorentz vector + /// @param q lorentz vector + /// @return boosted lorentz vector + MALorentzVector operator*(const MALorentzVector &q) const + { + MALorentzVector q2 = q; + boost(q2); + return q2; + } + }; + } #endif diff --git a/tools/SampleAnalyzer/Interfaces/HEPTopTagger/HTT.cpp b/tools/SampleAnalyzer/Interfaces/HEPTopTagger/HTT.cpp new file mode 100644 index 00000000..8e9a0dbf --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/HEPTopTagger/HTT.cpp @@ -0,0 +1,177 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#include "HEPTopTagger/HEPTopTagger.hh" + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/HEPTopTagger/HTT.h" + +namespace MA5 { + namespace Substructure { + + HTT::~HTT() { delete _tagger; } + + //============================// + // Initialization // + //============================// + + void HTT::Initialize(InputParameters& param) + { + _tagger = new fastjet::HEPTopTagger::HEPTopTagger(); + + // Optimal R + _tagger->do_optimalR(param.do_optimalR); + _tagger->set_optimalR_min(param.optimalR_min); + _tagger->set_optimalR_step(param.optimalR_step); + _tagger->set_optimalR_threshold(param.optimalR_threshold); + + // Candidate selection + fastjet::HEPTopTagger::Mode mode; + if (param.mode == HTT::EARLY_MASSRATIO_SORT_MASS) + mode = fastjet::HEPTopTagger::EARLY_MASSRATIO_SORT_MASS; + else if (param.mode == HTT::LATE_MASSRATIO_SORT_MASS) + mode = fastjet::HEPTopTagger::LATE_MASSRATIO_SORT_MASS; + else if (param.mode == HTT::EARLY_MASSRATIO_SORT_MODDJADE) + mode = fastjet::HEPTopTagger::EARLY_MASSRATIO_SORT_MODDJADE; + else if (param.mode == HTT::LATE_MASSRATIO_SORT_MODDJADE) + mode = fastjet::HEPTopTagger::LATE_MASSRATIO_SORT_MODDJADE; + else + mode = fastjet::HEPTopTagger::TWO_STEP_FILTER; + _tagger->set_mode(mode); + _tagger->set_mt(param.top_mass); + _tagger->set_mw(param.W_mass); + _tagger->set_top_mass_range(param.Mtop_min, param.Mtop_max); + _tagger->set_fw(param.fw); + _tagger->set_mass_ratio_range(param.mass_ratio_range_min, param.mass_ratio_range_max); + _tagger->set_mass_ratio_cut(param.m23cut, param.m13cutmin, param.m13cutmax); + + // Filtering + _tagger->set_filtering_n(param.filt_N); + _tagger->set_filtering_R(param.filtering_R); + _tagger->set_filtering_minpt_subjet(param.filtering_minpt); + + fastjet::JetAlgorithm algo_ = fastjet::antikt_algorithm; + if (param.filtering_algorithm == Substructure::cambridge) algo_ = fastjet::cambridge_algorithm; + else if (param.filtering_algorithm == Substructure::kt) algo_ = fastjet::kt_algorithm; + _tagger->set_filtering_jetalgorithm(algo_); + + // Reclustering + algo_ = fastjet::antikt_algorithm; + if (param.reclustering_algorithm == Substructure::cambridge) algo_ = fastjet::cambridge_algorithm; + else if (param.reclustering_algorithm == Substructure::kt) algo_ = fastjet::kt_algorithm; + _tagger->set_reclustering_jetalgorithm(algo_); + + // MassDrop + _tagger->set_mass_drop_threshold(param.mass_drop); + _tagger->set_mass_drop_threshold(param.mass_drop); + + // Pruning + _tagger->set_pruning_rcut_factor(param.prun_rcut); + _tagger->set_pruning_zcut(param.prun_zcut); + } + + //====================// + // Execute // + //====================// + + // Method to run top tagger + void HTT::Execute(const RecJetFormat *jet) { _tagger->run(jet->pseudojet()); } + + //======================// + // Accessors // + //======================// + + // accessor to the top jet + const RecJetFormat * HTT::top() const + { + RecJetFormat * NewJet = new RecJetFormat(const_cast(_tagger->t())); + return NewJet; + } + + // accessor to the bottom jet inside the top + const RecJetFormat * HTT::b() const + { + RecJetFormat * NewJet = new RecJetFormat(const_cast(_tagger->b())); + return NewJet; + } + + // accessor to the W jet inside the top + const RecJetFormat * HTT::W() const + { + RecJetFormat * NewJet = new RecJetFormat(const_cast(_tagger->W())); + return NewJet; + } + + // accessor to the leading subjet inside the W jet + const RecJetFormat * HTT::W1() const + { + RecJetFormat * NewJet = new RecJetFormat(const_cast(_tagger->W1())); + return NewJet; + } + + // accessor to second leading subjet inside the W jet + const RecJetFormat * HTT::W2() const + { + RecJetFormat * NewJet = new RecJetFormat(const_cast(_tagger->W2())); + return NewJet; + } + + // accessor to all PT-ordered subjets + std::vector HTT::subjets() const + { + std::vector output; + output.reserve(3); + RecJetFormat * j1 = new RecJetFormat(const_cast(_tagger->j1())); + RecJetFormat * j2 = new RecJetFormat(const_cast(_tagger->j2())); + RecJetFormat * j3 = new RecJetFormat(const_cast(_tagger->j3())); + output.push_back(j1); + output.push_back(j2); + output.push_back(j3); + return output; + } + + // print tagger information + void HTT::get_info() const { _tagger->get_info(); } + + // print tagger settings + void HTT::get_settings() const { _tagger->get_setting(); } + + // accessor to the pruned mass + MAfloat32 HTT::pruned_mass() const { return _tagger->pruned_mass(); } + + // accessor to the unfiltered mass + MAfloat32 HTT::unfiltered_mass() const { return _tagger->unfiltered_mass(); } + + // accessor to the difference between the reconstructed top mass and the true top mass + MAfloat32 HTT::delta_top() const { return _tagger->delta_top(); } + + // Is a given jet top-tagged + MAbool HTT::is_tagged() const { return _tagger->is_tagged(); } + + // Is the top mass window requirement satisfied? + MAbool HTT::is_maybe_top() const { return _tagger->is_maybe_top(); } + + // Are 2D mass plane requirements satisfied? + MAbool HTT::is_masscut_passed() const { return _tagger->is_masscut_passed(); } + } +} diff --git a/tools/SampleAnalyzer/Interfaces/HEPTopTagger/HTT.h b/tools/SampleAnalyzer/Interfaces/HEPTopTagger/HTT.h new file mode 100644 index 00000000..f56b3cbb --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/HEPTopTagger/HTT.h @@ -0,0 +1,168 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_HTT_H +#define MADANALYSIS5_HTT_H + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/Commons.h" + +namespace fastjet { + namespace HEPTopTagger { + class HEPTopTagger; + } +} + +namespace MA5 { + namespace Substructure { + class HTT { + + protected: + fastjet::HEPTopTagger::HEPTopTagger* _tagger; + + public: + + enum Mode { + EARLY_MASSRATIO_SORT_MASS, // applies 2D mass plane requirements then select the candidate which minimizes |m_cand-mt| + LATE_MASSRATIO_SORT_MASS, // selects the candidate which minimizes |m_cand-mt| + EARLY_MASSRATIO_SORT_MODDJADE, // applies the 2D mass plane requirements then select the candidate with highest jade distance + LATE_MASSRATIO_SORT_MODDJADE, // selects the candidate with highest modified jade distance + TWO_STEP_FILTER // only analyzes the candidate built with the highest pT(t) after unclustering + }; + + struct InputParameters { + Mode mode = EARLY_MASSRATIO_SORT_MASS; // execution mode + + MAbool do_optimalR = true; // initialize optimal R or set to fixed R + // optimal R parameters + MAfloat32 optimalR_min = 0.5; // min jet size + MAfloat32 optimalR_step = 0.1; // step size + MAfloat32 optimalR_threshold = 0.2; // step size + + // massdrop - unclustering + MAfloat32 mass_drop = 0.8; + MAfloat32 max_subjet = 30.; // set_max_subjet_mass + + // filtering + MAuint32 filt_N = 5; // set_nfilt + MAfloat32 filtering_R = 0.3; // max subjet distance for filtering + MAfloat32 filtering_minpt = 0.; // min subjet pt for filtering + // jet algorithm for filtering + Algorithm filtering_algorithm = Algorithm::cambridge; + + // Reclustering + // reclustering jet algorithm + Algorithm reclustering_algorithm = Algorithm::cambridge; + + //top mass range + MAfloat32 top_mass = 172.3; + MAfloat32 W_mass = 80.4; + MAfloat32 Mtop_min = 150.; + MAfloat32 Mtop_max = 200.; //set_top_range(min,max) + + // set top mass ratio range + MAfloat32 fw = 0.15; + MAfloat32 mass_ratio_range_min = (1.-fw)*W_mass/top_mass; + MAfloat32 mass_ratio_range_max = (1.+fw)*W_mass/top_mass; + + //mass ratio cuts + MAfloat32 m23cut = 0.35; + MAfloat32 m13cutmin = 0.2; + MAfloat32 m13cutmax = 1.3; + + // pruning + MAfloat32 prun_zcut = 0.1; // set_prun_zcut + MAfloat32 prun_rcut = .5; // set_prun_rcut + }; + + // Constructor without arguments + HTT() {} + + // Destructor + ~HTT(); + + //============================// + // Initialization // + //============================// + + HTT(HTT::InputParameters& param) { Initialize(param); } + + void Initialize(HTT::InputParameters& param); + + //====================// + // Execute // + //====================// + + // Method run top tagger. + void Execute(const RecJetFormat *jet); + + //======================// + // Accessors // + //======================// + + // accessor to top jet + const RecJetFormat * top() const; + + //accessor to bottom jet + const RecJetFormat * b() const; + + //accessor to W jet + const RecJetFormat * W() const; + + //accessor to leading subjet from W + const RecJetFormat * W1() const; + + //accessor to second leading subjet from W + const RecJetFormat * W2() const; + + // accessor to PT ordered subjets + std::vector subjets() const; + + // print tagger information + void get_info() const; + + // print tagger settings + void get_settings() const; + + // accessor to pruned mass + MAfloat32 pruned_mass() const; + + // accessor to unfiltered mass + MAfloat32 unfiltered_mass() const; + + // accessor to delta top + MAfloat32 delta_top() const; + + // Is given jet tagged + MAbool is_tagged() const; + + // top mass window requirement passed? + MAbool is_maybe_top() const; + + // 2D mass plane requirements passed? + MAbool is_masscut_passed() const; + }; + } +} + +#endif //MADANALYSIS5_HTT_H diff --git a/tools/SampleAnalyzer/Interfaces/HEPTopTagger/README.md b/tools/SampleAnalyzer/Interfaces/HEPTopTagger/README.md new file mode 100644 index 00000000..ee3e0bcb --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/HEPTopTagger/README.md @@ -0,0 +1,107 @@ +# HEPTopTagger for MadAnalysis 5 +This module is based on the `Substructure` module of MadAnalysis 5, and is thus +constructed following the same principle. The corresponding class consists of an +`Initialize` and an `Execute` function. However, due to the complexity of the +HEPTopTgger algorithm, the `Execute` function does not return anything. Instead +it is equipped with various accessors. +For details see `tools/SampleAnalyzer/Interfaces/substructure/README.md`. + +## Installation +Simply call the `install HEPTopTagger` command through the MadAnalysis 5 command +line interface. Please make sure that the `FastJet` and `FastJet contrib` +packages have already been installed, and that they are available from +MadAnalysis 5. + +## Examples +```c++ +#ifndef analysis_test_h +#define analysis_test_h + +#include "SampleAnalyzer/Process/Analyzer/AnalyzerBase.h" + +namespace MA5 +{ + + class test : public AnalyzerBase + { + INIT_ANALYSIS(test,"test") + + private: + Substructure::HTT tagger; + public: + virtual bool Initialize(const MA5::Configuration& cfg, const std::map& parameters) + { + // Initializing PhysicsService for MC + PHYSICS->mcConfig().Reset(); + AddDefaultHadronic(); + AddDefaultInvisible(); + + // Initializing PhysicsService for RECO + PHYSICS->recConfig().Reset(); + + // Initialize filtering + Substructure::InputParameters parameters; + parameters.mode = Substructure::HTT::EARLY_MASSRATIO_SORT_MASS; // execution mode + + parameters.do_optimalR = true; // initialize optimal R or set to fixed R + // optimal R parameters + parameters.optimalR_min = 0.5; // min jet size + parameters.optimalR_step = 0.1; // step size + parameters.optimalR_threshold = 0.2; // step size + + // massdrop - unclustering + parameters.mass_drop = 0.8; + parameters.max_subjet = 30.; // set_max_subjet_mass + + // filtering + parameters.filt_N = 5; // set_nfilt + parameters.filtering_R = 0.3; // max subjet distance for filtering + parameters.filtering_minpt = 0.; // min subjet pt for filtering + // jet algorithm for filtering + parameters.filtering_algorithm = Substructure::cambridge; + + // Reclustering + // reclustering jet algorithm + parameters.reclustering_algorithm = Substructure::Algorithm::cambridge; + + //top mass range + parameters.top_mass = 172.3; + parameters.W_mass = 80.4; + parameters.Mtop_min = 150.; + parameters.Mtop_max = 200.; //set_top_range(min,max) + + // set top mass ratio range + parameters.fw = 0.15; + parameters.mass_ratio_range_min = (1-parameters.fw)*parameters.W_mass/parameters.top_mass; + parameters.mass_ratio_range_max = (1+parameters.fw)*parameters.W_mass/parameters.top_mass; + + //mass ratio cuts + parameters.m23cut = 0.35; + parameters.m13cutmin = 0.2; + parameters.m13cutmax = 1.3; + + // pruning + parameters.prun_zcut = 0.1; // set_prun_zcut + parameters.prun_rcut = .5; // set_prun_rcut + tagger.Initialize(parameters); + return true; + } + virtual void Finalize(const SampleFormat& summary, const std::vector& files){} + virtual bool Execute(SampleFormat& sample, const EventFormat& event) + { + // Get antikt R=0.8 jets with pT > 200 |eta| < 2.5 + RecJets AK08 = filter(event.rec()->jets("AK08"), 200., 2.5); + + if (AK08.size() > 0) + { + taggedJet = tagger.Execute(AK08[0]); + if (taggedJet->is_tagged()) + INFO << "Top pT = " << taggedJet.top()->pt() << endmsg; + } + return true; + } + }; +} + +#endif +``` diff --git a/tools/SampleAnalyzer/Interfaces/delphes/DelphesMemoryInterface.cpp b/tools/SampleAnalyzer/Interfaces/delphes/DelphesMemoryInterface.cpp index eae7cb05..b0a66301 100644 --- a/tools/SampleAnalyzer/Interfaces/delphes/DelphesMemoryInterface.cpp +++ b/tools/SampleAnalyzer/Interfaces/delphes/DelphesMemoryInterface.cpp @@ -184,7 +184,7 @@ MAbool DelphesMemoryInterface::TransfertDELPHEStoMA5(SampleFormat& mySample, Eve { RecJetFormat* jet = myEvent.rec()->GetNewJet(); jet->momentum_.SetPxPyPzE(cand->Momentum.Px(),cand->Momentum.Py(),cand->Momentum.Pz(),cand->Momentum.E()); - jet->btag_ = cand->BTag; + jet->loose_btag_ = cand->BTag; if (cand->Eem!=0) jet->HEoverEE_ = cand->Ehad/cand->Eem; else jet->HEoverEE_ = 999.; jet->ntracks_ = 0; // To fix later } @@ -204,7 +204,7 @@ MAbool DelphesMemoryInterface::TransfertDELPHEStoMA5(SampleFormat& mySample, Eve } RecJetFormat* genjet = myEvent.rec()->GetNewGenJet(); genjet->momentum_ = cand->Momentum; - genjet->btag_ = cand->BTag; + genjet->loose_btag_ = cand->BTag; } }*/ diff --git a/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp b/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp index 7204ce0f..c956ac60 100644 --- a/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp +++ b/tools/SampleAnalyzer/Interfaces/delphes/DelphesTreeReader.cpp @@ -117,12 +117,12 @@ StatusCode::Type DelphesTreeReader::ReadEvent(EventFormat& myEvent, SampleFormat MAbool DelphesTreeReader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) { // MHT & THT - for (MAuint32 i=0; ijets_.size();i++) + for (MAuint32 i=0; ijets().size();i++) { - myEvent.rec()->MHT_ -= myEvent.rec()->jets_[i].momentum(); - if (data_.branchHT_==0) myEvent.rec()->THT_ += myEvent.rec()->jets_[i].pt(); - myEvent.rec()->TET_ += myEvent.rec()->jets_[i].pt(); - myEvent.rec()->Meff_ += myEvent.rec()->jets_[i].pt(); + myEvent.rec()->MHT_ -= myEvent.rec()->jets()[i].momentum(); + if (data_.branchHT_==0) myEvent.rec()->THT_ += myEvent.rec()->jets()[i].pt(); + myEvent.rec()->TET_ += myEvent.rec()->jets()[i].pt(); + myEvent.rec()->Meff_ += myEvent.rec()->jets()[i].pt(); } // TET @@ -562,7 +562,9 @@ void DelphesTreeReader::FillEvent(EventFormat& myEvent, SampleFormat& mySample) if (data_.Jet_!=0) { MAuint32 njets = static_cast(data_.Jet_->GetEntries()); - myEvent.rec()->jets_.reserve(njets); +// myEvent.rec()->jets_.reserve(njets); + std::vector output_jets; + output_jets.reserve(njets); for (MAuint32 i=0;iGetNewJet(); - - // Setting jet info - jet->momentum_.SetPtEtaPhiM(part->PT,part->Eta,part->Phi,part->Mass); - jet->ntracks_ = 0; // To fix later - jet->btag_ = part->BTag; - jet->HEoverEE_ = part->EhadOverEem; + output_jets.emplace_back(part->PT,part->Eta,part->Phi,part->Mass); + output_jets.back().ntracks_ = 0; // To fix later + output_jets.back().loose_btag_ = part->BTag; + output_jets.back().HEoverEE_ = part->EhadOverEem; // Setting corresponding gen particle /* for (MAuint32 j=0;j(part->Particles.GetEntries());j++) @@ -604,6 +603,7 @@ void DelphesTreeReader::FillEvent(EventFormat& myEvent, SampleFormat& mySample) }*/ } } + myEvent.rec()->jetcollection_.insert(std::make_pair(myEvent.rec()->PrimaryJetID_, output_jets)); } // --------------------------------------------------------------------------- @@ -612,7 +612,7 @@ void DelphesTreeReader::FillEvent(EventFormat& myEvent, SampleFormat& mySample) if (data_.FatJet_!=0) { MAuint32 njets = static_cast(data_.FatJet_->GetEntries()); - myEvent.rec()->fatjets_.reserve(njets); + // myEvent.rec()->fatjets_.reserve(njets); for (MAuint32 i=0;imomentum_.SetPtEtaPhiM(part->PT,part->Eta,part->Phi,part->Mass); - jet->ntracks_ = 0; // To fix later - jet->btag_ = part->BTag; - jet->HEoverEE_ = part->EhadOverEem; + jet->ntracks_ = 0; // To fix later + jet->loose_btag_ = part->BTag; + jet->HEoverEE_ = part->EhadOverEem; } } diff --git a/tools/SampleAnalyzer/Interfaces/delphesMA5tune/DelphesMA5tuneTreeReader.cpp b/tools/SampleAnalyzer/Interfaces/delphesMA5tune/DelphesMA5tuneTreeReader.cpp index 7378fcf2..76d95c3a 100644 --- a/tools/SampleAnalyzer/Interfaces/delphesMA5tune/DelphesMA5tuneTreeReader.cpp +++ b/tools/SampleAnalyzer/Interfaces/delphesMA5tune/DelphesMA5tuneTreeReader.cpp @@ -146,12 +146,12 @@ StatusCode::Type DelphesMA5tuneTreeReader::ReadEvent(EventFormat& myEvent, Sampl MAbool DelphesMA5tuneTreeReader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) { // MHT & THT - for (MAuint32 i=0; ijets_.size();i++) + for (MAuint32 i=0; ijets().size();i++) { - myEvent.rec()->MHT_ -= myEvent.rec()->jets_[i].momentum(); - if (branchScalarHT_==0) myEvent.rec()->THT_ += myEvent.rec()->jets_[i].pt(); - myEvent.rec()->TET_ += myEvent.rec()->jets_[i].pt(); - myEvent.rec()->Meff_ += myEvent.rec()->jets_[i].pt(); + myEvent.rec()->MHT_ -= myEvent.rec()->jets()[i].momentum(); + if (branchScalarHT_==0) myEvent.rec()->THT_ += myEvent.rec()->jets()[i].pt(); + myEvent.rec()->TET_ += myEvent.rec()->jets()[i].pt(); + myEvent.rec()->Meff_ += myEvent.rec()->jets()[i].pt(); } // TET diff --git a/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoFastJet.cpp b/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoFastJet.cpp index 979d2f7b..2b84d614 100644 --- a/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoFastJet.cpp +++ b/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoFastJet.cpp @@ -24,176 +24,129 @@ // SampleAnalyser headers #include "SampleAnalyzer/Interfaces/fastjet/ClusterAlgoFastJet.h" -#include "SampleAnalyzer/Commons/Service/LoopService.h" -#include "SampleAnalyzer/Commons/Service/Physics.h" -#include "SampleAnalyzer/Commons/Service/PDGService.h" -#include "SampleAnalyzer/Commons/Base/SmearerBase.h" - -// FastJet headers -#include -#include - using namespace MA5; ClusterAlgoFastJet::ClusterAlgoFastJet(std::string Algo):ClusterAlgoBase(Algo) { JetAlgorithm_=Algo; JetDefinition_=0; } -ClusterAlgoFastJet::~ClusterAlgoFastJet() +ClusterAlgoFastJet::~ClusterAlgoFastJet() { if (JetDefinition_!=0) delete JetDefinition_; } -template -void SetConeRadius(std::vector cone_radius, std::vector& objects, - MCParticleFormat part, MAbool ischarged=false, MAbool addself=false) + +MAbool ClusterAlgoFastJet::Execute(SampleFormat& mySample, EventFormat& myEvent, SmearerBase* smearer) { - for (MAuint32 iR=0; iRaddsumPT(part.pt()); - current_isocone->addSumET(part.et()); - if (addself) - { - current_isocone->setSelfPT(objects[i].pt()); - current_isocone->setSelfET(objects[i].et()); - } - // if (ischarged) current_isocone->addNtracks(1); - // ntracks depends on track matching - } - } - } -} + // Clustering + clust_seq.reset(new fastjet::ClusterSequence(myEvent.rec()->cluster_inputs(), *JetDefinition_)); + // Getting jets with PTmin = 0 + std::vector jets; + if (Exclusive_) jets = clust_seq->exclusive_jets(0.); + else jets = clust_seq->inclusive_jets(0.); -MAbool ClusterAlgoFastJet::Execute(SampleFormat& mySample, EventFormat& myEvent, MAbool ExclusiveId, - const std::vector& vetos, - const std::set vetos2, - SmearerBase* smearer) -{ - // Creating a container for inputs - std::vector inputs; - - // Putting the good inputs into the containter - // Good inputs = - final state - // - visible - // - if exclusiveID=1: particles not vetoed - // - if exclusiveID=0: all particles except muons - for (MAuint32 i=0;iparticles().size();i++) - { - const MCParticleFormat& part = myEvent.mc()->particles()[i]; - - // Selecting input for jet clustering - // | final state only - if (part.statuscode()!=1) continue; - // ! not invisible: reject neutrinos, neutralinos, ... - if (PHYSICS->Id->IsInvisible(part)) continue; - - // ExclusiveId mode - if (ExclusiveId) - { - if (vetos[i]) continue; - if (vetos2.find(&part)!=vetos2.end()) continue; - } + // Calculating the MET + ParticleBaseFormat* MET = myEvent.rec()->GetNewMet(); + ParticleBaseFormat* MHT = myEvent.rec()->GetNewMht(); - // NonExclusive Id mode - else if (std::abs(part.pdgid())==13) continue; - - - // Smearer module returns a smeared MCParticleFormat object - // Default: NullSmearer, that does nothing - // Reminder: 0 is reserved for the jet constituents - MCParticleFormat smeared = smearer->Execute(&part, 0); - if (smeared.pt() <= 1e-10) continue; - - // Filling good particle for clustering - inputs.push_back(fastjet::PseudoJet(smeared.px(), - smeared.py(), - smeared.pz(), - smeared.e() )); - inputs.back().set_user_index(i); - - // Set track isolation - // Isolation cone is applied to each particle that deposits energy in HCAL; - // all hadronic activity assumed to reach to HCAL - MAbool isCharged = PDG->IsCharged(myEvent.mc()->particles()[i].pdgid()); - SetConeRadius(isocone_track_radius_, myEvent.rec()->tracks(), smeared, isCharged, false); - // Set Electron isolation - SetConeRadius(isocone_electron_radius_, myEvent.rec()->electrons(), smeared, isCharged, !ExclusiveId); - // Set Muon isolation - SetConeRadius(isocone_muon_radius_, myEvent.rec()->muons(), smeared, isCharged, false); - // Set Photon isolation - SetConeRadius(isocone_photon_radius_, myEvent.rec()->photons(), smeared, isCharged, !ExclusiveId); - - } - - // Clustering - fastjet::ClusterSequence clust_seq(inputs, *JetDefinition_); - - // Getting jets with PTmin = 0 - std::vector jets; - if (Exclusive_) jets = clust_seq.exclusive_jets(0.); - else jets = clust_seq.inclusive_jets(0.); - - // Smearing if necessary - if (smearer->isJetSmearerOn()) - { - for (MAuint32 i=0;iExecute(dynamic_cast(¤t_jet), 21); - jets[i].reset_momentum(smeared.px(),smeared.py(),smeared.pz(),smeared.e()); - } - // Sort pseudojets - jets = fastjet::sorted_by_pt(jets); - } - - // Calculating the MET - ParticleBaseFormat* MET = myEvent.rec()->GetNewMet(); - ParticleBaseFormat* MHT = myEvent.rec()->GetNewMht(); - - // shortcut for Meff, TET & THT - MAfloat64 & TET = myEvent.rec()->TET(); - MAfloat64 & THT = myEvent.rec()->THT(); - MAfloat64 & Meff= myEvent.rec()->Meff(); - - // Storing - for (MAuint32 i=0;iGetNewJet(); - jet->setMomentum(MALorentzVector(jets[i].px(),jets[i].py(),jets[i].pz(),jets[i].e())); - std::vector constituents = clust_seq.constituents(jets[i]); - MAuint32 tracks = 0; - for (MAuint32 j=0;jTET(); + MAfloat64 & THT = myEvent.rec()->THT(); + MAfloat64 & Meff= myEvent.rec()->Meff(); + + // Storing + for (auto &jet: jets) { - jet->AddConstituent(constituents[j].user_index()); - if (PDG->IsCharged(myEvent.mc()->particles()[constituents[j].user_index()].pdgid())) tracks++; + if (jet.pt() <= 1e-10) continue; + + if (smearer->isJetSmearerOn()) + { + // Smearer module returns a smeared MCParticleFormat object + // Default: NullSmearer, that does nothing + // Reminder: 21 is reserved for the reco-jets + MCParticleFormat current_jet(jet.px(),jet.py(),jet.pz(),jet.e()); + MCParticleFormat smeared = smearer->Execute( + dynamic_cast(¤t_jet), 21 + ); + jet.reset_momentum(smeared.px(),smeared.py(),smeared.pz(),smeared.e()); + } + + MALorentzVector q(jet.px(),jet.py(),jet.pz(),jet.e()); + (*MET) -= q; + (*MHT) -= q; + THT += jet.pt(); + TET += jet.pt(); + Meff += jet.pt(); + + if(jet.pt() < Ptmin_) continue; + + // Saving jet information + RecJetFormat * RecJet = myEvent.rec()->GetNewJet(); + RecJet->pseudojet_=jet; + RecJet->setMomentum(MALorentzVector(jet.px(),jet.py(),jet.pz(),jet.e())); + + std::vector constituents = clust_seq->constituents(jet); + RecJet->Constituents_.reserve(constituents.size()); + RecJet->ntracks_ = 0; + for (auto &constit: constituents) + { + RecJet->Constituents_.emplace_back(constit.user_index()); + if (PDG->IsCharged(myEvent.mc()->particles()[constit.user_index()].pdgid())) + RecJet->ntracks_++; + } } - jet->ntracks_ = tracks; + // Create an empty accessor if there are no jets. Jets are not sorted at this point!! + if (jets.size() == 0) myEvent.rec()->CreateEmptyJetAccesor(); + else { + std::sort( + myEvent.rec()->jetcollection_[myEvent.rec()->PrimaryJetID_].begin(), + myEvent.rec()->jetcollection_[myEvent.rec()->PrimaryJetID_].end(), + [](RecJetFormat const &j1, RecJetFormat const &j2) { return j1.pt() > j2.pt(); } + ); + } - } - Meff += MET->pt(); + /// @attention in the earlier version of the code Meff is filled with MET->pt() at this point + /// we now switched to MHT because in the earlier version of the code when this function + /// executed MET was empty. For numerical consistency we use MHT here. + /// For details see JetClusterer.cpp and ClusterAlgoFastjet.cpp in v1.10.x + /// BENJ" changed back to MET; to be discussed. + Meff += MET->pt(); - // Filling the dataformat with jets - return true; + // Exit + return true; } +// Additional jet clustering. needs execute to run before!! +MAbool ClusterAlgoFastJet::Cluster(EventFormat& myEvent, std::string JetID) +{ + // Clustering + clust_seq.reset(new fastjet::ClusterSequence(myEvent.rec()->cluster_inputs(), *JetDefinition_)); + + std::vector jets; + if (Exclusive_) jets = clust_seq->exclusive_jets(Ptmin_); + else jets = clust_seq->inclusive_jets(Ptmin_); + + std::vector output_jets; + output_jets.reserve(jets.size()); + // Storing + for (auto &jet: fastjet::sorted_by_pt(jets)) + { + // Saving jet information + output_jets.emplace_back(jet); + std::vector constituents = clust_seq->constituents(jet); + output_jets.back().Constituents_.reserve(constituents.size()); + output_jets.back().ntracks_ = 0; + for (auto &constit: constituents) + { + output_jets.back().Constituents_.emplace_back(constit.user_index()); + if (PDG->IsCharged(myEvent.mc()->particles()[constit.user_index()].pdgid())) + output_jets.back().ntracks_++; + } + } + + // Filling the dataformat with jets + myEvent.rec()->jetcollection_.insert(std::make_pair(JetID, output_jets)); + + return true; +} diff --git a/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoFastJet.h b/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoFastJet.h index 0681aad7..1da2dce9 100644 --- a/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoFastJet.h +++ b/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoFastJet.h @@ -25,6 +25,8 @@ #ifndef JET_CLUSTERING_FASTJET_H #define JET_CLUSTERING_FASTJET_H +// FastJet headers +#include // SampleAnalyser headers #include "SampleAnalyzer/Commons/DataFormat/EventFormat.h" @@ -58,6 +60,9 @@ class ClusterAlgoFastJet: public ClusterAlgoBase /// Jet definition fastjet::JetDefinition* JetDefinition_; + // Shared Cluster sequence for primary jet + std::shared_ptr clust_seq; + //--------------------------------------------------------------------------------- // method members @@ -71,14 +76,14 @@ class ClusterAlgoFastJet: public ClusterAlgoBase virtual ~ClusterAlgoFastJet(); /// Jet clustering - virtual MAbool Execute(SampleFormat& mySample, EventFormat& myEvent, MAbool ExclusiveId, - const std::vector& vetos, - const std::set vetos2, - SmearerBase* smearer); + virtual MAbool Execute(SampleFormat& mySample, EventFormat& myEvent, + SmearerBase* smearer); /// Initialization virtual MAbool Initialize()=0; - + + /// Cluster additional jets + virtual MAbool Cluster(EventFormat& myEvent, std::string JetID); }; } diff --git a/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoStandard.cpp b/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoStandard.cpp index 31da2b11..21bc9f3d 100644 --- a/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoStandard.cpp +++ b/tools/SampleAnalyzer/Interfaces/fastjet/ClusterAlgoStandard.cpp @@ -97,20 +97,6 @@ MAbool ClusterAlgoStandard::SetParameter(const std::string& key, const std::stri } } - // isolation radius for track - else if (key.substr(0,9)=="isolation") - { - std::stringstream str(value); - for (MAfloat64 tmp; str >> tmp;) - { - if (tmp>0. && key.substr(10) == "track.radius") isocone_track_radius_.push_back(tmp); - if (tmp>0. && key.substr(10) == "electron.radius") isocone_electron_radius_.push_back(tmp); - if (tmp>0. && key.substr(10) == "muon.radius") isocone_muon_radius_.push_back(tmp); - if (tmp>0. && key.substr(10) == "photon.radius") isocone_photon_radius_.push_back(tmp); - if (str.peek() == ',' || str.peek() == ' ') str.ignore(); - } - } - // other else return false; diff --git a/tools/SampleAnalyzer/Process/JetClustering/NullSmearer.h b/tools/SampleAnalyzer/Interfaces/substructure/Cluster.cpp similarity index 100% rename from tools/SampleAnalyzer/Process/JetClustering/NullSmearer.h rename to tools/SampleAnalyzer/Interfaces/substructure/Cluster.cpp diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Cluster.h b/tools/SampleAnalyzer/Interfaces/substructure/Cluster.h new file mode 100644 index 00000000..6b6887ce --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Cluster.h @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_CLUSTER_H +#define MADANALYSIS5_CLUSTER_H + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/ClusterBase.h" + +namespace MA5 { + namespace Substructure{ + class Cluster : public ClusterBase { + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + + /// Constructor without argument + Cluster() {} + + /// Destructor + ~Cluster() {} + + //============================// + // Initialization // + //============================// + // Initialize the parameters of the algorithm. Initialization includes multiple if conditions + // Hence it would be optimum execution to initialize the algorithm during the initialisation + // of the analysis + + // Constructor with arguments + Cluster(Algorithm algorithm, MAfloat32 radius, MAfloat32 ptmin=0., MAbool isExclusive = false) + { Initialize(algorithm, radius, ptmin, isExclusive); } + + void Initialize( + Algorithm algorithm, MAfloat32 radius, MAfloat32 ptmin=0., MAbool isExclusive = false + ); + + }; + } +} + +#endif //MADANALYSIS5_CLUSTER_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/ClusterBase.cpp b/tools/SampleAnalyzer/Interfaces/substructure/ClusterBase.cpp new file mode 100644 index 00000000..cd928858 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/ClusterBase.cpp @@ -0,0 +1,209 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// FastJet headers +#include "fastjet/ClusterSequence.hh" +#include "fastjet/PseudoJet.hh" + +#include "SampleAnalyzer/Interfaces/substructure/ClusterBase.h" + +namespace MA5 { + namespace Substructure { + + //=======================// + // Initialize // + //=======================// + + // Set the Jet definition using algorithm and radius input + void ClusterBase::SetJetDef(Algorithm algorithm, MAfloat32 radius) + { + isPlugin_ = false; + JetDefinition_ = new fastjet::JetDefinition(__get_clustering_algorithm(algorithm), radius); + } + + //=======================// + // Execution // + //=======================// + + // Wrapper for event based execution + void ClusterBase::Execute(const EventFormat& event, std::string JetID) + { __execute(const_cast(event), JetID); } + + // Execute with a single jet. This method reclusters the given jet using its constituents + std::vector ClusterBase::Execute(const RecJetFormat *jet) + { + std::vector reclustered_jets = __cluster(jet->pseudojet().constituents()); + return __transform_jets(reclustered_jets); + } + + // Execute with a single jet. This method reclusters the given jet using its constituents by filtering + // reclustered events with respect to the initial jet + template + std::vector ClusterBase::Execute(const RecJetFormat *jet, Func func) + { + std::vector output_jets; + std::vector reclustered_jets = __cluster(jet->pseudojet().constituents()); + + for (auto &recjet: reclustered_jets) + { + RecJetFormat *NewJet = __transform_jet(recjet); + if (func(jet, const_cast(NewJet))) output_jets.push_back(NewJet); + } + + return output_jets; + } + + // Execute with a list of jets. This method reclusters the given collection + // of jets by combining their constituents + std::vector ClusterBase::Execute(std::vector &jets) + { + std::vector constituents; + for (auto &jet: jets) + { + std::vector current_constituents = jet->pseudojet().constituents(); + constituents.reserve(constituents.size() + current_constituents.size()); + constituents.insert( + constituents.end(), current_constituents.begin(), current_constituents.end() + ); + } + + std::vector reclustered_jets = __cluster(constituents); + + return __transform_jets(reclustered_jets); + } + + // Handler for clustering step + void ClusterBase::cluster(const RecJetFormat *jet) + { + if (isPlugin_) + { + fastjet::JetDefinition jetDefinition(JetDefPlugin_); + clust_seq.reset(new fastjet::ClusterSequence(jet->pseudojet().constituents(), jetDefinition)); + } else { + clust_seq.reset(new fastjet::ClusterSequence( + jet->pseudojet().constituents(), + const_cast(*JetDefinition_) + )); + } + isClustered_ = true; + } + + // return a vector of all jets when the event is clustered (in the exclusive sense) to exactly njets. + // If there are fewer than njets particles in the ClusterSequence the function just returns however many + // particles there were. + std::vector ClusterBase::exclusive_jets_up_to(MAint32 njets) + { + if (!isClustered_) throw EXCEPTION_ERROR("No clustered jet available", "", 1); + std::vector clustered_jets = fastjet::sorted_by_pt( + clust_seq->exclusive_jets_up_to(njets) + ); + return __transform_jets(clustered_jets); + } + + //=======================// + // Private Functions // + //=======================// + + // Generic clustering method + std::vector ClusterBase::__cluster(std::vector particles) + { + if (isPlugin_) + { + fastjet::JetDefinition jetDefinition(JetDefPlugin_); + clust_seq.reset(new fastjet::ClusterSequence(particles, jetDefinition)); + } else { + clust_seq.reset(new fastjet::ClusterSequence( + particles, const_cast(*JetDefinition_) + )); + } + isClustered_ = true; + std::vector jets; + if (isExclusive_) jets = clust_seq->exclusive_jets(ptmin_); + else jets = clust_seq->inclusive_jets(ptmin_); + + return fastjet::sorted_by_pt(jets); + } + + // Method to transform pseudojet into recjetformat + RecJetFormat * ClusterBase::__transform_jet(fastjet::PseudoJet jet) const + { + RecJetFormat * NewJet = new RecJetFormat(jet); + return NewJet; + } + + // Transform pseudojets into RecJetFormat + std::vector ClusterBase::__transform_jets(std::vector jets) const + { + std::vector output_jets; + output_jets.reserve(jets.size()); + for (auto &jet: jets) + output_jets.push_back(__transform_jet(jet)); + return output_jets; + } + + // Method to get jet algorithm + fastjet::JetAlgorithm ClusterBase::__get_clustering_algorithm(Substructure::Algorithm algorithm) const + { + fastjet::JetAlgorithm algo_; + if (algorithm == Substructure::antikt) algo_ = fastjet::antikt_algorithm; + else if (algorithm == Substructure::cambridge) algo_ = fastjet::cambridge_algorithm; + else if (algorithm == Substructure::kt) algo_ = fastjet::kt_algorithm; + else throw EXCEPTION_ERROR("Unknown algorithm","",1); + return algo_; + } + + // Execute with the Reconstructed event. This method creates a new Jet in RecEventFormat which + // can be accessed via JetID. The algorithm will only be executed if a unique JetID is given + MAbool ClusterBase::__execute(EventFormat& myEvent, std::string JetID) + { + try { + if (myEvent.rec()->hasJetID(JetID)) + throw EXCEPTION_ERROR("Substructure::ClusterBase - Jet ID `" + JetID + \ + "` already exits. Skipping execution.","",1); + } catch (const std::exception& err) { + MANAGE_EXCEPTION(err); + return false; + } + + std::vector jets = __cluster(myEvent.rec()->cluster_inputs()); + + std::vector output_jets; + output_jets.reserve(jets.size()); + + for (auto &jet: jets) { + output_jets.emplace_back(jet); + std::vector constituents = clust_seq->constituents(jet); + output_jets.back().Constituents_.reserve(constituents.size()); + output_jets.back().ntracks_ = 0; + for (auto &constit: constituents) { + output_jets.back().Constituents_.emplace_back(constit.user_index()); + if (PDG->IsCharged(myEvent.mc()->particles()[constit.user_index()].pdgid())) + output_jets.back().ntracks_++; + } + } + myEvent.rec()->jetcollection_.insert(std::make_pair(JetID, output_jets)); + isClustered_ = false; + return true; + } + } +} diff --git a/tools/SampleAnalyzer/Interfaces/substructure/ClusterBase.h b/tools/SampleAnalyzer/Interfaces/substructure/ClusterBase.h new file mode 100644 index 00000000..a5f1a155 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/ClusterBase.h @@ -0,0 +1,140 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_CLUSTERBASE_H +#define MADANALYSIS5_CLUSTERBASE_H + +// STL headers +#include +#include + +// FastJet headers +#include "fastjet/ClusterSequence.hh" + +// SampleAnalyser headers +#include "SampleAnalyzer/Commons/DataFormat/EventFormat.h" +#include "SampleAnalyzer/Commons/Service/PDGService.h" +#include "SampleAnalyzer/Commons/Service/LogService.h" +#include "SampleAnalyzer/Interfaces/substructure/Commons.h" + +namespace fastjet +{ + class JetDefinition; + class PseudoJet; +} + +namespace MA5{ + namespace Substructure { + + class Recluster; + + class ClusterBase { + + friend class Recluster; + + //--------------------------------------------------------------------------------- + // data members + //--------------------------------------------------------------------------------- + protected: + + // External parameters + MAfloat32 ptmin_; // minimum transverse momentum + MAbool isExclusive_; // if false return a vector of all jets (in the sense of the inclusive algorithm) + // with pt >= ptmin. Time taken should be of the order of the number of jets + // returned. if True return a vector of all jets (in the sense of the exclusive + // algorithm) that would be obtained when running the algorithm with the given ptmin. + + /// Jet definition + fastjet::JetDefinition* JetDefinition_; + fastjet::JetDefinition::Plugin* JetDefPlugin_; + MAbool isPlugin_; + MAbool isClustered_; + + // Shared Cluster sequence + std::shared_ptr clust_seq; + + public: + + /// Constructor without argument + ClusterBase() {} + + /// Destructor + virtual ~ClusterBase() + { + // clean heap allocation + delete JetDefinition_; + delete JetDefPlugin_; + } + + // Set the Jet definition using algorithm and radius input + void SetJetDef(Algorithm algorithm, MAfloat32 radius); + + //=======================// + // Execution // + //=======================// + + // Wrapper for event based execution + virtual void Execute(const EventFormat& event, std::string JetID); + + // Execute with a single jet. This method reclusters the given jet using its constituents + std::vector Execute(const RecJetFormat *jet); + + // Execute with a single jet. This method reclusters the given jet using its constituents by filtering + // reclustered events with respect to the initial jet + template + std::vector Execute(const RecJetFormat *jet, Func func); + + // Execute with a list of jets. This method reclusters the given collection + // of jets by combining their constituents + virtual std::vector Execute(std::vector &jets); + + // Handler for clustering step + void cluster(const RecJetFormat *jet); + + // return a vector of all jets when the event is clustered (in the exclusive sense) to exactly njets. + // If there are fewer than njets particles in the ClusterSequence the function just returns however many + // particles there were. + std::vector exclusive_jets_up_to(MAint32 njets); + + private: + + // Generic clustering method + std::vector __cluster(std::vector particles); + + // Method to transform pseudojet into recjetformat + RecJetFormat * __transform_jet(fastjet::PseudoJet jet) const; + + // Transform pseudojets into RecJetFormat + std::vector __transform_jets(std::vector jets) const; + + // Method to get jet algorithm + fastjet::JetAlgorithm __get_clustering_algorithm(Substructure::Algorithm algorithm) const; + + // Execute with the Reconstructed event. This method creates a new Jet in RecEventFormat which + // can be accessed via JetID. The algorithm will only be executed if a unique JetID is given + MAbool __execute(EventFormat& myEvent, std::string JetID); + }; + } +} + +#endif //MADANALYSIS5_CLUSTERBASE_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Commons.h b/tools/SampleAnalyzer/Interfaces/substructure/Commons.h new file mode 100644 index 00000000..31d06963 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Commons.h @@ -0,0 +1,42 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_COMMONS_H +#define MADANALYSIS5_COMMONS_H + +// SampleAnalyser headers +#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" +#include "SampleAnalyzer/Commons/DataFormat/RecJetFormat.h" + +namespace MA5{ + namespace Substructure { + + // Accessor for jet clustering algorithms + enum Algorithm { + antikt = 0, akt = 0, AKT = 0, ANTIKT = 0, cambridge = 1, ca = 1, CA = 1, CAMBRIDGE = 1, kt = 2, KT = 2 + }; + + } +} + +#endif //MADANALYSIS5_COMMONS_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/EnergyCorrelator.cpp b/tools/SampleAnalyzer/Interfaces/substructure/EnergyCorrelator.cpp new file mode 100644 index 00000000..872fe09d --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/EnergyCorrelator.cpp @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// FastJet headers +#include "fastjet/contrib/EnergyCorrelator.hh" + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/EnergyCorrelator.h" + +namespace MA5 { + namespace Substructure { + + EnergyCorrelator::~EnergyCorrelator() + { + delete _EC; + } + + void EnergyCorrelator::Initialize( + MAuint32 N, + MAfloat32 beta, + EnergyCorrelator::Measure measure, + EnergyCorrelator::Strategy strategy + ) + { + fastjet::contrib::EnergyCorrelator::Measure measure_; + fastjet::contrib::EnergyCorrelator::Strategy strategy_; + + if (measure == EnergyCorrelator::Measure::pt_R) + measure_ = fastjet::contrib::EnergyCorrelator::Measure::pt_R; + else if (measure == EnergyCorrelator::Measure::E_theta) + measure_ = fastjet::contrib::EnergyCorrelator::Measure::E_theta; + else + measure_ = fastjet::contrib::EnergyCorrelator::Measure::E_inv; + + if (strategy == EnergyCorrelator::Strategy::storage_array) + strategy_ = fastjet::contrib::EnergyCorrelator::Strategy::storage_array; + else strategy_ = fastjet::contrib::EnergyCorrelator::Strategy::slow; + + _EC = new fastjet::contrib::EnergyCorrelator(N, beta, measure_, strategy_); + } + + // Method to execute with a single jet + MAdouble64 EnergyCorrelator::Execute(const RecJetFormat* jet) const + { return (*_EC)(jet->pseudojet()); } + } +} \ No newline at end of file diff --git a/tools/SampleAnalyzer/Interfaces/substructure/EnergyCorrelator.h b/tools/SampleAnalyzer/Interfaces/substructure/EnergyCorrelator.h new file mode 100644 index 00000000..9afc2d5d --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/EnergyCorrelator.h @@ -0,0 +1,101 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_ENERGYCORRELATOR_H +#define MADANALYSIS5_ENERGYCORRELATOR_H + +// STL headers +#include +#include + +// SampleAnalyser headers +#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" +#include "SampleAnalyzer/Commons/DataFormat/RecJetFormat.h" + +using namespace std; + +namespace fastjet { + namespace contrib { + class EnergyCorrelator; + } +} + +namespace MA5 { + namespace Substructure { + class EnergyCorrelator { + + //--------------------------------------------------------------------------------- + // data members + //--------------------------------------------------------------------------------- + protected: + fastjet::contrib::EnergyCorrelator * _EC; + + public: + enum Measure { + pt_R, ///< use transverse momenta and boost-invariant angles, + ///< eg \f$\mathrm{ECF}(2,\beta) = \sum_{i=3 this leads to many expensive recomputations, + ///< but has only O(n) memory usage for n particles + storage_array /// the interparticle angles are cached. This gives a significant speed + /// improvement for N>=3, but has a memory requirement of (4n^2) bytes. + }; + + /// Constructor without argument + EnergyCorrelator() {} + + /// Destructor + ~EnergyCorrelator(); + + /// constructs an N-point correlator with angular exponent beta, + /// using the specified choice of energy and angular measure as well + /// one of two possible underlying computational Strategy + EnergyCorrelator( + MAuint32 N, + MAfloat32 beta, + EnergyCorrelator::Measure measure = EnergyCorrelator::Measure::pt_R, + EnergyCorrelator::Strategy strategy = EnergyCorrelator::Strategy::storage_array + ) { Initialize(N, beta, measure, strategy); } + + void Initialize( + MAuint32 N, + MAfloat32 beta, + EnergyCorrelator::Measure measure = EnergyCorrelator::Measure::pt_R, + EnergyCorrelator::Strategy strategy = EnergyCorrelator::Strategy::storage_array + ); + + // Method to execute with a single jet + MAdouble64 Execute(const RecJetFormat* jet) const; + }; + } +} + +#endif //MADANALYSIS5_ENERGYCORRELATOR_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Filter.cpp b/tools/SampleAnalyzer/Interfaces/substructure/Filter.cpp new file mode 100644 index 00000000..404971ed --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Filter.cpp @@ -0,0 +1,100 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// FastJet headers +#include "fastjet/tools/Filter.hh" + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/Filter.h" + +namespace MA5 { + namespace Substructure { + + Filter::~Filter() + { + if (JetDefinition_ != 0) delete JetDefinition_; + if (JetFilter_ != 0) delete JetFilter_; + } + + //============================// + // Initialization // + //============================// + + void Filter::Initialize(Algorithm algorithm, MAfloat32 radius, Selector selector, MAfloat32 rho) + { + fastjet::JetAlgorithm algo_ = fastjet::antikt_algorithm; + if (algorithm == Substructure::cambridge) algo_ = fastjet::cambridge_algorithm; + else if (algorithm == Substructure::kt) algo_ = fastjet::kt_algorithm; + + JetDefinition_ = new fastjet::JetDefinition(algo_, radius); + Rfilt_=-1.; rho_=rho; + init_filter(selector, true); + } + + void Filter::Initialize(MAfloat32 Rfilt, Selector selector, MAfloat32 rho) + { + Rfilt_=Rfilt; rho_=rho; JetDefinition_ = 0; + init_filter(selector,false); + } + + void Filter::init_filter(Selector selector, MAbool isJetDefined) + { + if (isJetDefined) + JetFilter_ = new fastjet::Filter(*JetDefinition_, selector.selector_, rho_); + else + JetFilter_ = new fastjet::Filter(Rfilt_, selector.selector_, rho_); + } + + //=======================// + // Execution // + //=======================// + + // Method to filter a given jet. + const RecJetFormat* Filter::Execute(const RecJetFormat *jet) const + { + fastjet::PseudoJet filtered_jet = (*JetFilter_)(jet->pseudojet()); + RecJetFormat * NewJet = new RecJetFormat(filtered_jet); + return NewJet; + } + + // Method to filter all the jets in a vector + std::vector Filter::Execute(std::vector &jets) const + { + std::vector output_jets; + output_jets.reserve(jets.size()); + for (auto &jet: jets) + output_jets.push_back(Execute(jet)); + + std::sort( + output_jets.begin(), + output_jets.end(), + [](const RecJetFormat *j1, const RecJetFormat *j2) + { + return (j1->pt() > j2->pt()); + } + ); + + return output_jets; + } + } +} diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Filter.h b/tools/SampleAnalyzer/Interfaces/substructure/Filter.h new file mode 100644 index 00000000..f9cb7508 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Filter.h @@ -0,0 +1,112 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_FILTER_H +#define MADANALYSIS5_FILTER_H + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/Commons.h" +#include "SampleAnalyzer/Interfaces/substructure/Selector.h" + +namespace fastjet { + class Filter; + class JetDefinition; +} + +namespace MA5 { + namespace Substructure { + class Filter { + + /// Class that helps perform filtering (Butterworth, Davison, Rubin + /// and Salam, arXiv:0802.2470) and trimming (Krohn, Thaler and Wang, + /// arXiv:0912.1342) on jets, optionally in conjunction with + /// subtraction (Cacciari and Salam, arXiv:0707.1378). + + /// For example, to apply filtering that reclusters a jet's + /// constituents with the Cambridge/Aachen jet algorithm with R=0.3 + /// and then selects the 3 hardest subjets, one can use the following + + /// To obtain trimming, involving for example the selection of all + /// subjets carrying at least 3% of the original jet's pt, the + /// selector would be replaced by SelectorPtFractionMin(0.03). + + //--------------------------------------------------------------------------------- + // data members + //--------------------------------------------------------------------------------- + protected: + + /// Jet definition + fastjet::JetDefinition* JetDefinition_; // the jet definition applied to obtain the subjets + + MAfloat32 rho_; // if non-zero, backgruond-subtract each subjet befor selection + MAfloat32 Rfilt_; // the filtering radius + + fastjet::Filter * JetFilter_; + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + + /// Constructor without argument + Filter() { + JetDefinition_ = 0; + JetFilter_ = 0; + } + + /// Destructor + ~Filter(); + + //============================// + // Initialization // + //============================// + + // Constructor with arguments + Filter(Algorithm algorithm, MAfloat32 radius, Selector selector, MAfloat32 rho=0.) + { Initialize(algorithm, radius, selector, rho); } + + Filter(MAfloat32 Rfilt, Selector selector, MAfloat32 rho=0.) + { Initialize(Rfilt, selector, rho); } + + void Initialize(Algorithm algorithm, MAfloat32 radius, Selector selector, MAfloat32 rho=0.); + void Initialize(MAfloat32 Rfilt, Selector selector, MAfloat32 rho=0.); + + //=======================// + // Execution // + //=======================// + + // Method to filter a given jet. + const RecJetFormat* Execute(const RecJetFormat *jet) const; + + // Method to filter all the jets in a vector + std::vector Execute(std::vector &jets) const; + + private: + + void init_filter(Selector selector, MAbool isJetDefined); + + + }; + } +} + +#endif //MADANALYSIS5_FILTER_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Nsubjettiness.cpp b/tools/SampleAnalyzer/Interfaces/substructure/Nsubjettiness.cpp new file mode 100644 index 00000000..9472d904 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Nsubjettiness.cpp @@ -0,0 +1,125 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// FastJet headers +#include "fastjet/contrib/Nsubjettiness.hh" + +#include "SampleAnalyzer/Interfaces/substructure/Nsubjettiness.h" + +namespace MA5 { + namespace Substructure { + + Nsubjettiness::~Nsubjettiness() + { + // clean heap allocation + delete axesdef_; + delete measuredef_; + } + + //============================// + // Initialization // + //============================// + // Initialize the parameters of the algorithm. Initialization includes multiple if conditions + // Hence it would be optimum execution to initialize the algorithm during the initialisation + // of the analysis + + void Nsubjettiness::Initialize( + MAint32 order, + AxesDef axesdef, + MeasureDef measuredef, + MAfloat32 beta, + MAfloat32 R0, + MAfloat32 Rcutoff + ) + { + if (axesdef == Substructure::Nsubjettiness::KT_Axes) + axesdef_ = new fastjet::contrib::KT_Axes(); + else if (axesdef == Substructure::Nsubjettiness::CA_Axes) + axesdef_ = new fastjet::contrib::CA_Axes(); + else if (axesdef == Substructure::Nsubjettiness::AntiKT_Axes) + axesdef_ = new fastjet::contrib::AntiKT_Axes(R0); + else if (axesdef == Substructure::Nsubjettiness::WTA_KT_Axes) + axesdef_ = new fastjet::contrib::WTA_KT_Axes(); + else if (axesdef == Substructure::Nsubjettiness::WTA_CA_Axes) + axesdef_ = new fastjet::contrib::WTA_CA_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::GenKT_Axes) +// axesdef_ = new fastjet::contrib::GenKT_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::WTA_GenKT_Axes) +// axesdef_ = new fastjet::contrib::WTA_GenKT_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::GenET_GenKT_Axes) +// axesdef_ = new fastjet::contrib::GenET_GenKT_Axes(); + else if (axesdef == Substructure::Nsubjettiness::Manual_Axes) + axesdef_ = new fastjet::contrib::Manual_Axes(); + else if (axesdef == Substructure::Nsubjettiness::OnePass_KT_Axes) + axesdef_ = new fastjet::contrib::OnePass_KT_Axes(); + else if (axesdef == Substructure::Nsubjettiness::OnePass_CA_Axes) + axesdef_ = new fastjet::contrib::OnePass_CA_Axes(); + else if (axesdef == Substructure::Nsubjettiness::OnePass_AntiKT_Axes) + axesdef_ = new fastjet::contrib::OnePass_AntiKT_Axes(R0); + else if (axesdef == Substructure::Nsubjettiness::OnePass_WTA_KT_Axes) + axesdef_ = new fastjet::contrib::OnePass_WTA_KT_Axes(); + else if (axesdef == Substructure::Nsubjettiness::OnePass_WTA_CA_Axes) + axesdef_ = new fastjet::contrib::OnePass_WTA_CA_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::OnePass_GenKT_Axes) +// axesdef_ = new fastjet::contrib::OnePass_GenKT_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::OnePass_WTA_GenKT_Axes) +// axesdef_ = new fastjet::contrib::OnePass_WTA_GenKT_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::OnePass_GenET_GenKT_Axes) +// axesdef_ = new fastjet::contrib::OnePass_GenET_GenKT_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::OnePass_Manual_Axes) +// axesdef_ = new fastjet::contrib::OnePass_Manual_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::MultiPass_Axes) +// axesdef_ = new fastjet::contrib::MultiPass_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::MultiPass_Manual_Axes) +// axesdef_ = new fastjet::contrib::MultiPass_Manual_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::Comb_GenKT_Axes) +// axesdef_ = new fastjet::contrib::Comb_GenKT_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::Comb_WTA_GenKT_Axes) +// axesdef_ = new fastjet::contrib::Comb_WTA_GenKT_Axes(); +// else if (axesdef == Substructure::Nsubjettiness::Comb_GenET_GenKT_Axes) +// axesdef_ = new fastjet::contrib::Comb_GenET_GenKT_Axes(); + + if (measuredef == Substructure::Nsubjettiness::NormalizedCutoffMeasure) + measuredef_ = new fastjet::contrib::NormalizedCutoffMeasure(beta, R0, Rcutoff); + else if (measuredef == Substructure::Nsubjettiness::NormalizedMeasure) + measuredef_ = new fastjet::contrib::NormalizedMeasure(beta, R0); + else if (measuredef == Substructure::Nsubjettiness::UnnormalizedMeasure) + measuredef_ = new fastjet::contrib::UnnormalizedMeasure(beta); + else if (measuredef == Substructure::Nsubjettiness::UnnormalizedCutoffMeasure) + measuredef_ = new fastjet::contrib::UnnormalizedCutoffMeasure(beta, Rcutoff); + + order_ = order; + } + + //=======================// + // Execution // + //=======================// + + // Method to calculate nsub for a given jet with respect to initialization parameters + MAdouble64 Nsubjettiness::Execute(const RecJetFormat *jet) const + { + fastjet::contrib::Nsubjettiness nsubjettiness(order_, *axesdef_, *measuredef_); + return nsubjettiness(jet->pseudojet()); + } + } +} \ No newline at end of file diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Nsubjettiness.h b/tools/SampleAnalyzer/Interfaces/substructure/Nsubjettiness.h new file mode 100644 index 00000000..908aae81 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Nsubjettiness.h @@ -0,0 +1,132 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_NSUBJETTINESS_H +#define MADANALYSIS5_NSUBJETTINESS_H + +// STL headers +#include + +// SampleAnalyser headers +#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" +#include "SampleAnalyzer/Commons/DataFormat/RecJetFormat.h" + +using namespace std; + +namespace fastjet { + namespace contrib { + class AxesDefinition; + class MeasureDefinition; + } +} + +namespace MA5 { + namespace Substructure { + class Nsubjettiness { + //--------------------------------------------------------------------------------- + // data members + //--------------------------------------------------------------------------------- + protected: + MAint32 order_; + fastjet::contrib::AxesDefinition* axesdef_; + fastjet::contrib::MeasureDefinition* measuredef_; + + public: + + enum AxesDef { + KT_Axes, + CA_Axes, + AntiKT_Axes, // (R0) + WTA_KT_Axes, + WTA_CA_Axes, + // GenKT_Axes, // (p, R0 = infinity) + // WTA_GenKT_Axes, // (p, R0 = infinity) + // GenET_GenKT_Axes, // (delta, p, R0 = infinity) + Manual_Axes, + OnePass_KT_Axes, + OnePass_CA_Axes, + OnePass_AntiKT_Axes, // (R0) + OnePass_WTA_KT_Axes, + OnePass_WTA_CA_Axes, + // OnePass_GenKT_Axes, // (p, R0 = infinity) + // OnePass_WTA_GenKT_Axes, // (p, R0 = infinity) + // OnePass_GenET_GenKT_Axes, // (delta, p, R0 = infinity) + // OnePass_Manual_Axes, + // MultiPass_Axes, // (NPass) (currently only defined for KT_Axes) + // MultiPass_Manual_Axes, // (NPass) + // Comb_GenKT_Axes, // (nExtra, p, R0 = infinity) + // Comb_WTA_GenKT_Axes, // (nExtra, p, R0 = infinity) + // Comb_GenET_GenKT_Axes, // (nExtra, delta, p, R0 = infinity) + }; + + enum MeasureDef { + NormalizedMeasure, // (beta,R0) + UnnormalizedMeasure, // (beta) + NormalizedCutoffMeasure, // (beta,R0,Rcutoff) + UnnormalizedCutoffMeasure, // (beta,Rcutoff) + }; + + /// Constructor without argument + Nsubjettiness() {} + + /// Destructor + ~Nsubjettiness(); + + //============================// + // Initialization // + //============================// + // Initialize the parameters of the algorithm. Initialization includes multiple if conditions + // Hence it would be optimum execution to initialize the algorithm during the initialisation + // of the analysis + + // Constructor with arguments + Nsubjettiness( + MAint32 order, + AxesDef axesdef, + MeasureDef measuredef, + MAfloat32 beta, + MAfloat32 R0, + MAfloat32 Rcutoff=std::numeric_limits::max() + ) + { Initialize(order, axesdef, measuredef, beta, R0, Rcutoff); } + + void Initialize( + MAint32 order, + AxesDef axesdef, + MeasureDef measuredef, + MAfloat32 beta, + MAfloat32 R0, + MAfloat32 Rcutoff=std::numeric_limits::max() + ); + + //=======================// + // Execution // + //=======================// + + // Method to calculate nsub for a given jet with respect to initialization parameters + MAdouble64 Execute(const RecJetFormat *jet) const; + }; + } +} + +#endif //MADANALYSIS5_NSUBJETTINESS_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Pruner.cpp b/tools/SampleAnalyzer/Interfaces/substructure/Pruner.cpp new file mode 100644 index 00000000..85e38a34 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Pruner.cpp @@ -0,0 +1,85 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// FastJet headers +#include "fastjet/tools/Pruner.hh" + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/Pruner.h" + +namespace MA5 { + namespace Substructure { + + Pruner::~Pruner() + { + delete JetDefinition_; + } + + // Initialize with all the arguments. Note that if R <= 0 max allowable radius will be used + void Pruner::Initialize( + Substructure::Algorithm algorithm, MAfloat32 R, MAfloat32 zcut, MAfloat32 Rcut_factor + ) + { + fastjet::JetAlgorithm algo_ = fastjet::antikt_algorithm; + if (algorithm == Substructure::cambridge) algo_ = fastjet::cambridge_algorithm; + else if (algorithm == Substructure::kt) algo_ = fastjet::kt_algorithm; + + if (R<=0.) + JetDefinition_ = new fastjet::JetDefinition(algo_, fastjet::JetDefinition::max_allowable_R); + else + JetDefinition_ = new fastjet::JetDefinition(algo_, R); + + zcut_ = zcut; Rcut_factor_=Rcut_factor; + } + + //=======================// + // Execution // + //=======================// + + // Method to prune a given jet with respect to initialization parameters + const RecJetFormat * Pruner::Execute(const RecJetFormat *jet) const + { + fastjet::PseudoJet pruned_jet = __prune(jet->pseudojet()); + RecJetFormat * NewJet = new RecJetFormat(pruned_jet); + return NewJet; + } + + // Method to prune each given jet individually with respect to initialization parameters + std::vector Pruner::Execute(std::vector &jets) const + { + std::vector output_jets; + output_jets.reserve(jets.size()); + for (auto &jet: jets) + output_jets.push_back(Execute(jet)); + return output_jets; + } + + fastjet::PseudoJet Pruner::__prune(fastjet::PseudoJet jet) const + { + fastjet::Pruner pruner( + *const_cast(JetDefinition_), zcut_, Rcut_factor_ + ); + return pruner(jet); + } + } +} \ No newline at end of file diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Pruner.h b/tools/SampleAnalyzer/Interfaces/substructure/Pruner.h new file mode 100644 index 00000000..2dbf8db6 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Pruner.h @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_PRUNER_H +#define MADANALYSIS5_PRUNER_H + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/Commons.h" + +namespace fastjet { + class JetDefinition; +} + +namespace MA5 { + namespace Substructure { + class Pruner { + //--------------------------------------------------------------------------------- + // data members + //--------------------------------------------------------------------------------- + protected: + + /// Jet definition + fastjet::JetDefinition *JetDefinition_; + + MAfloat32 zcut_; // pt-fraction cut in the pruning + MAfloat32 Rcut_factor_; // the angular distance cut in the pruning will be Rcut_factor * 2m/pt + + public: + + /// Constructor without argument + Pruner() {} + + /// Destructor + ~Pruner(); + + //============================// + // Initialization // + //============================// + // Initialize the parameters of the algorithm. Initialization includes multiple if conditions + // Hence it would be optimum execution to initialize the algorithm during the initialisation + // of the analysis + + // Constructor with arguments + Pruner(Substructure::Algorithm algorithm, MAfloat32 R, MAfloat32 zcut, MAfloat32 Rcut_factor) + { Initialize(algorithm, R, zcut, Rcut_factor); } + + // Constructor with arguments + Pruner(Substructure::Algorithm algorithm, MAfloat32 zcut, MAfloat32 Rcut_factor) + { Initialize(algorithm, -1., zcut, Rcut_factor); } + + void Initialize(Substructure::Algorithm algorithm, MAfloat32 zcut, MAfloat32 Rcut_factor) + { Initialize(algorithm, -1., zcut, Rcut_factor); } + + // Initialize with all the arguments. Note that if R <= 0 max allowable radius will be used + void Initialize( + Substructure::Algorithm algorithm, MAfloat32 R, MAfloat32 zcut, MAfloat32 Rcut_factor + ); + + //=======================// + // Execution // + //=======================// + + // Method to prune a given jet with respect to initialization parameters + const RecJetFormat * Execute(const RecJetFormat *jet) const; + + // Method to prune each given jet individually with respect to initialization parameters + std::vector Execute(std::vector &jets) const; + + private: + + fastjet::PseudoJet __prune(fastjet::PseudoJet jet) const; + + }; + } +} + +#endif //MADANALYSIS5_PRUNER_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/README.md b/tools/SampleAnalyzer/Interfaces/substructure/README.md new file mode 100644 index 00000000..3dd0e43a --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/README.md @@ -0,0 +1,456 @@ +# Usage of the substructure module shipped with MadAnalysis 5 + +The Substructure module of MadAnalysis 5 has been designed to be used within the +[SFS framework](https://arxiv.org/abs/2006.09387), in which jet clustering +information is preserved and used throughout the analysis execution. This allows +users to use the `Substructure` interface to the `FastJet` libraries without +having to deal with how jets are treated internally (in particular with respect +to memory management). The`Substructure` interface uses the clustering history +to link `RecJetFormat` objects to `FastJet`'s `PseudoJet` objects, and converts +the two types of object seamlesly in the background. + +Each class that has been constructed under the `Substructure` namespace has been +equiped with an `Initialize` and an `Execute` function. The `Initialize` +function creates a memory allocation for the corresponding `FastJet` (or +`fjcontib` backend). + +**Note:** Initialising any given of the `Substructure` classes during the +execution of the analysis can slow down the code and might create memory +allocation problems. The best practice requires to **always** initialise the +used substructure classes in the analysis initialisation routine. Examples are +provided below. + +Depending on the nature of the jet substructure tool considered, the `Execute` +function can take as an argument a `const RecJetFormat *` pointer or a +`std::vector` vector of pointers. The former possibility +is designed to work with a single jet, whereas the latter is designed to work +with a collection of jets. The precise action of the `Execute` function depends +on the substructure tools to be used. The `Execute` function, as suggested by +its name, needs to be executed during the analysis execution. + +## Outline +* [Examples](#examples) + * [SoftDrop](#softdrop) + * [Filtering](#filtering) + * [Energy Correlator](#energy-correlator) + * [Nsubjettiness](#nsubjettiness) + * [Clustering](#clustering) + * [VariableR](#variabler) + * [Pruning](#pruning) + * [Reclustering](#reclustering) + +# Examples +The examples below are designed to illutrate only analysis header files, but can +easily be generalised to be used separately in a header and a source file. We +only made this choice as it is easier to examplify the functionalities through a +single file. To create an environment compatible with the substructure module, +we begin with writing a file named `substructure_example.ma5` including the +commands shown below: +``` +# Define standard AK04 jet +set main.fastsim.package = fastjet +set main.fastsim.algorithm = antikt +set main.fastsim.radius = 0.4 +set main.fastsim.JetID = AK04 +set main.fastsim.bjet_id.matching_dr = 0.3 +set main.fastsim.bjet_id.exclusive = true +set main.fastsim.exclusive_id = false +set main.fastsim.ptmin = 20.0 + +# Define AK08 jet +define jet_algorithm AK08 antikt radius=0.8 ptmin=200 + +# Define a VariableR algorithm name "varR" +define jet_algorithm varR VariableR rho=2000 +set varR.minR = 0 +set varR.maxR = 2 +set varR.ptmin = 20 +``` +This will generate a MadAnalysis 5 workspace which includes a definition of a +primary jet class named `AK04`, and clustered according to the `antikt` +algorithm with the parameters `R=0.4` and `ptmin=20` GeV. Furthermore, the +commands lead to the initialisation of two additional jet classes named `AK08` +and `varR`. In the former case, jets are clustered with the `antikt` algorithm +with parameters `R=0.8` and `ptmin=200` GeV. The latter definition leads to a +jet definition through the `VariableR` algorithm. All available `jet_algorithm` +definitions are shown with their default values in the table below. + +| Algorithm | Parameters & Default values | +|:---------------------:|:-----------------------------------------------------------------------------------| +| `antikt`, `cambridge` | `radius=0.4`, `ptmin=5.` | +| `genkt` | `radius=0.4`, `ptmin=5.`, `exclusive=False`, `p=-1` | +| `kt` | `radius=0.4`, `ptmin=5.`, `exclusive=False` | +| `gridjet` | `ymax=3.`, `ptmin=5.` | +| `cdfjetclu` | `radius=0.4`, `ptmin=5.`, `overlap=0.5`, `seed=1.`, `iratch=0.` | +| `cdfmidpoint` | `radius=0.4`, `ptmin=5.`, `overlap=0.5`, `seed=1.`, `iratch=0.`, `areafraction=1.` | +| `siscone` | `radius=0.4`, `ptmin=5.`, `overlap=0.5`, `input_ptmin=5.`, `npassmax=1.` | +| `VariableR` | `rho=2000.`, `minR=0.`, `maxR=2.`, `ptmin=20.` `exclusive=False` `clustertype=CALIKE` `strategy=Best` | + +The above MadAnalysis 5 script can be executed as: +```bash +cd madanalysis5 +./bin/ma5 -Re my_workspace test substructure_example.ma5 +``` +This will create a MadAnalysus 5 workspace in the Expert mode of the code. The +workspace is named `my_workspace` and the analysis file is named `test`. The +`test.h` and `test.cpp` files can be found under + `my_workspace/Build/SampleAnalyzer/User/Analyzer`. +The structure of `test.h` reads: + +`my_workspace/Build/SampleAnalyzer/User/Analyzer/test.h`: +```c++ +#ifndef analysis_test_h +#define analysis_test_h + +#include "SampleAnalyzer/Process/Analyzer/AnalyzerBase.h" + +namespace MA5 +{ +class test : public AnalyzerBase +{ + INIT_ANALYSIS(test,"test") + + public: + virtual bool Initialize(const MA5::Configuration& cfg, const std::map& parameters); + virtual void Finalize(const SampleFormat& summary, const std::vector& files); + virtual bool Execute(SampleFormat& sample, const EventFormat& event); + + private: +}; +} + +#endif +``` +For the purposes of this example `test.cpp` is not be used and can hence be +removed. We will only modify `test.h` from now on. + +[Back to top](#outline) + +## SoftDrop: + +First we need to create a private `softdrop` object to be able to access it +thorough the different functions of the `test` class +```c++ +private: + Substructure::SoftDrop softDrop; +``` +Then during the `Initialize` function, it can be called as +```c++ +virtual bool Initialize(const MA5::Configuration& cfg, const std::map& parameters) +{ + // Initialize SoftDrop + MAfloat32 z_cut = 0.10; + MAfloat32 beta = 2.0; + softDrop.Initialize(beta, z_cut); + return true; +} +``` +Note that it is possible to define a `SoftDrop` object through a pointer, + `Substructure::SoftDrop* softDrop;` +In this case, the class should be initialised as: + `softDrop = new Substructure::SoftDrop(beta, z_cut);`. + +The `SoftDrop` object can then be further used during the execution of the code. +```c++ +virtual bool Execute(SampleFormat& sample, const EventFormat& event) +{ + // Get antikt R=0.8 jets with pT > 200 |eta| < 2.5 + RecJets AK08 = filter(event.rec()->jets("AK08"), 200., 2.5); + + if (AK08.size() > 0) + { + INFO << "SoftDrop on leading AK08 jet:" << endmsg; + const RecJet softdrop_jet = softDrop.Execute(AK08[0]); + INFO << "M_SD = " << softdrop_jet->m() << " M(j_1) = " << AK08[0]->m() << endmsg; + } + return true; +} +``` +Note that if `SoftDrop` is defined as a pointer it needs to be executed as + `const RecJet softdrop_jet = softDrop->Execute(AK08[0]);`. +Here the `filter` function cleans the "AK08" jet collection defined +[above](#examples) and removes from it any jet with $p_T<200$ GeV and $|\eta|>2.5$. In +the following we apply the `softDrop` method on the leading `AK08` jet, which +results in a `const RecJetFormat *` object, the `RecJet` definition used here +having been defined in the `SampleAnalyzer` backend. + +**Note:** All substructure classes are desinged in the same way. Therefore, from +now on we only show simple examples of usage without any detailed explanations. + +[Back to top](#outline) + +## Filtering +```c++ + private: + Substructure::Filter JetFilter; + public: + virtual bool Initialize(const MA5::Configuration& cfg, const std::map& parameters) + { + // Initializing PhysicsService for MC + PHYSICS->mcConfig().Reset(); + AddDefaultHadronic(); + AddDefaultInvisible(); + + // Initializing PhysicsService for RECO + PHYSICS->recConfig().Reset(); + + // Initialize filtering + MAfloat32 Rfilt = 0.2; + INFO << "Initializing Filter" << endmsg; + JetFilter.Initialize(Rfilt, Substructure::SelectorPtFractionMin(0.03)); + return true; + } + virtual bool Execute(SampleFormat& sample, const EventFormat& event) + { + // Get antikt R=0.8 jets with pT > 200 |eta| < 2.5 + RecJets AK08 = filter(event.rec()->jets("AK08"), 200., 2.5); + + if (AK08.size() > 0) + { + INFO << "Filter the leading AK08 jet:" << endmsg; + const RecJet filteredJet = JetFilter.Execute(AK08[0]); + INFO << "pT(j_filt) = " << filteredJet->pt() << " pT(j_1) = " << AK08[0]->pt() << endmsg; + } + + // RecJets shorthand for `std::vector` + RecJets AK08_filtered = JetFilter.Execute(AK08); + for (MAuint32 i=0; i 0) + { + INFO << "EnergyCorrelator:" << endmsg; + MAdouble64 ec = EC.Execute(AK08[0]); + INFO << "EC = " << ec << endmsg; + } + return true; + } +``` +[Back to top](#outline) +## Nsubjettiness +```c++ + private: + Substructure::Nsubjettiness nsub; + public: + virtual bool Initialize(const MA5::Configuration& cfg, const std::map& parameters) + { + // Initializing PhysicsService for MC + PHYSICS->mcConfig().Reset(); + AddDefaultHadronic(); + AddDefaultInvisible(); + + // Initializing PhysicsService for RECO + PHYSICS->recConfig().Reset(); + + // Initialize Nsubjettiness + MAfloat32 beta = 0.1, R0 = 0.2; + nsub.Initialize( + 1., + Substructure::Nsubjettiness::KT_Axes, + Substructure::Nsubjettiness::NormalizedMeasure, + beta, + R0, + ); + return true; + } + virtual bool Execute(SampleFormat& sample, const EventFormat& event) + { + // Get antikt R=0.8 jets with pT > 200 |eta| < 2.5 + RecJets AK08 = filter(event.rec()->jets("AK08"), 200., 2.5); + if (AK08.size() > 0) + { + MAdouble64 tau1 = nsub.Execute(AK08[0]); + INFO << "tau1 = " << tau1 << endmsg; + } + return true; + } +``` +[Back to top](#outline) +## Clustering +```c++ + private: + Substructure::Cluster cluster; + public: + virtual bool Initialize(const MA5::Configuration& cfg, const std::map& parameters) + { + // Initializing PhysicsService for MC + PHYSICS->mcConfig().Reset(); + AddDefaultHadronic(); + AddDefaultInvisible(); + + // Initializing PhysicsService for RECO + PHYSICS->recConfig().Reset(); + + // Initialize Cluster + cluster.Initialize(Substructure::cambridge, 0.8, 200., true); + return true; + } + virtual bool Execute(SampleFormat& sample, const EventFormat& event) + { + // Get antikt R=0.8 jets with pT > 200 |eta| < 2.5 + RecJets AK08 = filter(event.rec()->jets("AK08"), 200., 2.5); + if (AK08.size() > 0) + { + RecJets clusteredFromLeading = cluster.Execute(AK08[0]); + RecJets CAJets = cluster.Execute(AK08); + RecJets CAJetsFiltered = cluster.Execute( + AK08[0], [](const RecJet mainjet, const RecJet subjet) + { return (subjet->pt() > mainjet->pt()*0.05);} + ); + } + return true; + } +``` +[Back to top](#outline) +## VariableR +```c++ + private: + Substructure::VariableR varR; + public: + virtual bool Initialize(const MA5::Configuration& cfg, const std::map& parameters) + { + // Initializing PhysicsService for MC + PHYSICS->mcConfig().Reset(); + AddDefaultHadronic(); + AddDefaultInvisible(); + + // Initializing PhysicsService for RECO + PHYSICS->recConfig().Reset(); + + // Initialize Energy Correlator + varR.Initialize( + 2000., // mass scale for effective radius (i.e. R ~ rho/pT) + 0., //minimum jet radius + 2., // maximum jet radius + Substructure::VariableR::CALIKE, + Substructure::VariableR::Best, + 200.,// Minimum pT + false // isexclusive + ); + return true; + } + virtual bool Execute(SampleFormat& sample, const EventFormat& event) + { + // Get antikt R=0.8 jets with pT > 200 |eta| < 2.5 + RecJets AK08 = filter(event.rec()->jets("AK08"), 200., 2.5); + if (AK08.size() > 0) + { + RecJets clusteredFromLeading = varR.Execute(AK08[0]); + RecJets varRJets = varR.Execute(AK08); + RecJets varRJetsFiltered = varR.Execute( + AK08[0], [](const RecJet mainjet, const RecJet subjet) + { return (subjet->pt() > mainjet->pt()*0.05);} + ); + } + return true; + } +``` +[Back to top](#outline) +## Pruning +```c++ + private: + Substructure::Pruner pruner; + public: + virtual bool Initialize(const MA5::Configuration& cfg, const std::map& parameters) + { + // Initializing PhysicsService for MC + PHYSICS->mcConfig().Reset(); + AddDefaultHadronic(); + AddDefaultInvisible(); + + // Initializing PhysicsService for RECO + PHYSICS->recConfig().Reset(); + + // Initialize pruner + pruner.Initialize(Substructure::cambridge, 0.2, 0.2, 0.3); + return true; + } + virtual bool Execute(SampleFormat& sample, const EventFormat& event) + { + // Get antikt R=0.8 jets with pT > 200 |eta| < 2.5 + RecJets AK08 = filter(event.rec()->jets("AK08"), 200., 2.5); + + if (AK08.size() > 0) + { + INFO << "Prune the leading AK08 jet:" << endmsg; + const RecJet prunedjet = pruner.Execute(AK08[0]); + INFO << "pT(j_filt) = " << prunedjet->pt() << " pT(j_1) = " << AK08[0]->pt() << endmsg; + } + + // RecJets shorthand for `std::vector` + RecJets AK08_pruned = pruner.Execute(AK08); + for (MAuint32 i=0; i 0) + { + const RecJet reclusteredJet = recluster.Execute(AK08[0]); + RecJets reclusteredJets = recluster.Execute(AK08); + } + return true; + } +``` +[Back to top](#outline) diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Recluster.cpp b/tools/SampleAnalyzer/Interfaces/substructure/Recluster.cpp new file mode 100644 index 00000000..0b8bfbd9 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Recluster.cpp @@ -0,0 +1,86 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// FastJet headers +#include "fastjet/contrib/Recluster.hh" + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/Recluster.h" + +namespace MA5 { + namespace Substructure { + + //=======================// + // Execution // + //=======================// + + // Method to recluster a given jet. Returns only the hardest reclustered jet. + const RecJetFormat* Recluster::Execute(const RecJetFormat *jet) + { + fastjet::contrib::Recluster recluster(*JetDefinition_); + fastjet::PseudoJet reclustered_jet = recluster(jet->pseudojet()); + return __transform_jet(reclustered_jet); + } + + // Method to recluster each jet in a given vector + std::vector Recluster::Execute(std::vector &jets) + { + std::vector output_jets; + for (auto &jet: jets) + output_jets.push_back(Execute(jet)); + + std::sort( + output_jets.begin(), + output_jets.end(), + [](const RecJetFormat *j1, const RecJetFormat *j2) + { + return (j1->pt() > j2->pt()); + } + ); + + return output_jets; + } + + //=============================// + // NOT IMPLEMENTED // + //=============================// + + void Recluster::Execute(const EventFormat& event, std::string JetID) + { + try { throw EXCEPTION_ERROR("This method has not been implemented", "", 1); } + catch (const std::exception& err) { + MANAGE_EXCEPTION(err); + } + } + + template + std::vector Recluster::Execute(const RecJetFormat *jet, Func func) + { + try { throw EXCEPTION_ERROR("This method has not been implemented", "", 1); } + catch (const std::exception& err) { + MANAGE_EXCEPTION(err); + return std::vector(); + } + } + } +} \ No newline at end of file diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Recluster.h b/tools/SampleAnalyzer/Interfaces/substructure/Recluster.h new file mode 100644 index 00000000..2c7e19ab --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Recluster.h @@ -0,0 +1,81 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_RECLUSTER_H +#define MADANALYSIS5_RECLUSTER_H + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/ClusterBase.h" + +using namespace std; + +namespace MA5 { + namespace Substructure { + class Recluster : public ClusterBase{ + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + + /// Constructor without argument + Recluster() {} + + /// Destructor + ~Recluster() {} + + //============================// + // Initialization // + //============================// + // Initialize the parameters of the algorithm. Initialization includes multiple if conditions + // Hence it would be optimum execution to initialize the algorithm during the initialisation + // of the analysis + + // Constructor with arguments + Recluster(Algorithm algorithm, MAfloat32 radius) { Initialize(algorithm, radius); } + + void Initialize(Algorithm algorithm, MAfloat32 radius) { SetJetDef(algorithm, radius); } + + //=======================// + // Execution // + //=======================// + + // Method to recluster a given jet. Returns only the hardest reclustered jet. + const RecJetFormat* Execute(const RecJetFormat *jet); + + // Method to recluster each jet in a given vector + std::vector Execute(std::vector &jets) override; + + //=============================// + // NOT IMPLEMENTED // + //=============================// + + void Execute(const EventFormat& event, std::string JetID) override; + + template + std::vector Execute(const RecJetFormat *jet, Func func); + }; + } +} + +#endif //MADANALYSIS5_RECLUSTER_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/Selector.h b/tools/SampleAnalyzer/Interfaces/substructure/Selector.h new file mode 100644 index 00000000..fc5624bf --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/Selector.h @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_SELECTOR_H +#define MADANALYSIS5_SELECTOR_H + +// FastJet headers +#include "fastjet/Selector.hh" + +// SampleAnalyser headers +#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" + +using namespace std; + +namespace MA5 { + namespace Substructure { + + class Filter; + // These classes act as placeholder for Fastjet selectors + + class Selector { + friend class SelectorNHardest; + friend class SelectorPtFractionMin; + friend class Filter; + + protected: + fastjet::Selector selector_; + + public: + Selector() {} + virtual ~Selector( ) {} + Selector operator * (Selector & s2) + { + Selector new_selector; + fastjet::Selector selector = this->__get() * s2.__get(); + new_selector.__set(selector); + return new_selector; + } + + private: + fastjet::Selector __get() {return selector_;} + void __set(fastjet::Selector selector) { selector_ = selector;} + }; + + class SelectorNHardest: public Selector { + public: + SelectorNHardest(){} + virtual ~SelectorNHardest() {} + SelectorNHardest(MAint32 n) + { selector_ = fastjet::SelectorNHardest(n); } + }; + + class SelectorPtFractionMin: public Selector { + public: + SelectorPtFractionMin(){} + virtual ~SelectorPtFractionMin() {} + SelectorPtFractionMin(MAfloat32 frac) + { selector_ = fastjet::SelectorPtFractionMin(frac); } + }; + + } +} + +#endif //MADANALYSIS5_SELECTOR_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/SoftDrop.cpp b/tools/SampleAnalyzer/Interfaces/substructure/SoftDrop.cpp new file mode 100644 index 00000000..9984af68 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/SoftDrop.cpp @@ -0,0 +1,75 @@ +////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +////////////////////////////////////////////////////// + +// FastJet headers +#include "fastjet/contrib/SoftDrop.hh" + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/SoftDrop.h" + +namespace MA5 { + namespace Substructure { + + SoftDrop::~SoftDrop() { delete softDrop_; } + + //============================// + // Initialization // + //============================// + + void SoftDrop::Initialize(MAfloat32 beta, MAfloat32 symmetry_cut, MAfloat32 R0) + { softDrop_ = new fastjet::contrib::SoftDrop(beta, symmetry_cut, R0); } + + //=======================// + // Execution // + //=======================// + + // Execute with a single jet + const RecJetFormat * SoftDrop::Execute(const RecJetFormat *jet) const + { + fastjet::PseudoJet sd_jet = (*softDrop_)(jet->pseudojet()); + RecJetFormat * NewJet = new RecJetFormat(sd_jet); + return NewJet; + } + + // Execute with a list of jets + std::vector SoftDrop::Execute(std::vector &jets) const + { + std::vector output_jets; + output_jets.reserve(jets.size()); + for (auto &jet: jets) + output_jets.push_back(Execute(jet)); + + // Sort with respect to jet pT + std::sort( + output_jets.begin(), + output_jets.end(), + [](const RecJetFormat *j1, const RecJetFormat *j2) + { + return (j1->pt() > j2->pt()); + } + ); + + return output_jets; + } + } +} \ No newline at end of file diff --git a/tools/SampleAnalyzer/Interfaces/substructure/SoftDrop.h b/tools/SampleAnalyzer/Interfaces/substructure/SoftDrop.h new file mode 100644 index 00000000..9e6e2880 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/SoftDrop.h @@ -0,0 +1,104 @@ +////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_SOFTDROP_H +#define MADANALYSIS5_SOFTDROP_H + +// SampleAnalyser headers +#include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" +#include "SampleAnalyzer/Commons/DataFormat/RecJetFormat.h" + +namespace fastjet { + namespace contrib { + class SoftDrop; + } +} + +namespace MA5 { + namespace Substructure { + class SoftDrop { + + // SoftDrop wrapper arXiv:1402.2657. + // + // For the basic functionalities, we refer the reader to the + // documentation of the RecursiveSymmetryCutBase from which SoftDrop + // inherits. Here, we mostly put the emphasis on things specific to + // SoftDrop: + // + // - the cut applied recursively is + // \f[ + // z > z_{\rm cut} (\theta/R0)^\beta + // \f] + // with z the asymmetry measure and \f$\theta\f$ the geometrical + // distance between the two subjets. R0 is set to 1 by default. + // + // - by default, we work in "grooming mode" i.s. if no substructure + // is found, we return a jet made of a single parton. Note that + // this behaviour differs from the mMDT (and can be a source of + // differences when running SoftDrop with beta=0.) + // + + //--------------------------------------------------------------------------------- + // data members + //--------------------------------------------------------------------------------- + protected : + fastjet::contrib::SoftDrop * softDrop_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + + // Constructor without argument + SoftDrop() {} + + // Destructor + ~SoftDrop(); + + //============================// + // Initialization // + //============================// + + // Constructor with arguments + SoftDrop( + MAfloat32 beta, // the value of the beta parameter + MAfloat32 symmetry_cut, // the value of the cut on the symmetry measure + MAfloat32 R0=1. // the angular distance normalisation [1 by default] + ) + { Initialize(beta, symmetry_cut, R0); } + + void Initialize(MAfloat32 beta, MAfloat32 symmetry_cut, MAfloat32 R0=1.); + + //=======================// + // Execution // + //=======================// + + // Execute with a single jet + const RecJetFormat * Execute(const RecJetFormat *jet) const; + + // Execute with a list of jets + std::vector Execute(std::vector &jets) const; + }; + } +} +#endif //MADANALYSIS5_SOFTDROP_H diff --git a/tools/SampleAnalyzer/Interfaces/substructure/VariableR.cpp b/tools/SampleAnalyzer/Interfaces/substructure/VariableR.cpp new file mode 100644 index 00000000..a6aeb1e7 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/VariableR.cpp @@ -0,0 +1,80 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/VariableR.h" + +// FastJet headers +#include "fastjet/contrib/VariableRPlugin.hh" + +namespace MA5 { + namespace Substructure { + // Initialization method + void VariableR::Initialize( + MAfloat32 rho, + MAfloat32 minR, + MAfloat32 maxR, + Substructure::VariableR::ClusterType clusterType, + Substructure::VariableR::Strategy strategy, + MAfloat32 ptmin, + MAbool isExclusive + ) + { + fastjet::contrib::VariableRPlugin::ClusterType clusterType_ = fastjet::contrib::VariableRPlugin::AKTLIKE; + // whether to use CA-like, kT-like, + // or anti-kT-like distance measure + // (this value is the same as the p exponent in + // generalized-kt, with anti-kt = -1.0, CA = 0.0, and + // kT = 1.0) + if (clusterType == Substructure::VariableR::CALIKE) + clusterType_ = fastjet::contrib::VariableRPlugin::CALIKE; + else if (clusterType == Substructure::VariableR::KTLIKE) + clusterType_ = fastjet::contrib::VariableRPlugin::KTLIKE; + + fastjet::contrib::VariableRPlugin::Strategy strategy_; + // decodes which algorithm to apply for the clustering + + if (strategy == Substructure::VariableR::Best) + strategy_ = fastjet::contrib::VariableRPlugin::Best; + else if (strategy == Substructure::VariableR::N2Tiled) + strategy_ = fastjet::contrib::VariableRPlugin::N2Tiled; + else if (strategy == Substructure::VariableR::N2Plain) + strategy_ = fastjet::contrib::VariableRPlugin::N2Plain; + else if (strategy == Substructure::VariableR::NNH) + strategy_ = fastjet::contrib::VariableRPlugin::NNH; + else if (strategy == Substructure::VariableR::Native) + strategy_ = fastjet::contrib::VariableRPlugin::Native; + + ptmin_ = ptmin; isExclusive_ = isExclusive; + + JetDefPlugin_ = new fastjet::contrib::VariableRPlugin( + rho, minR, maxR, clusterType_, false, strategy_ + ); + isPlugin_ = true; + + /// Note that pre-clustering is deprecated and will likely be + /// removed in a future releasse of this contrib. + /// (precluster = false at the moment) + } + } +} \ No newline at end of file diff --git a/tools/SampleAnalyzer/Interfaces/substructure/VariableR.h b/tools/SampleAnalyzer/Interfaces/substructure/VariableR.h new file mode 100644 index 00000000..c9824b98 --- /dev/null +++ b/tools/SampleAnalyzer/Interfaces/substructure/VariableR.h @@ -0,0 +1,85 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MADANALYSIS5_VARIABLER_H +#define MADANALYSIS5_VARIABLER_H + +// SampleAnalyser headers +#include "SampleAnalyzer/Interfaces/substructure/ClusterBase.h" + +namespace MA5 { + namespace Substructure { + class VariableR : public ClusterBase { + public: + + enum ClusterType {CALIKE, KTLIKE, AKTLIKE}; + + enum Strategy { + Best, ///< currently N2Tiled or N2Plain for FJ>3.2.0, Native for FastJet<3.2.0 + N2Tiled, ///< the default (faster in most cases) [requires FastJet>=3.2.0] + N2Plain, ///< [requires FastJet>=3.2.0] + NNH, ///< slower but already available for FastJet<3.2.0 + Native ///< original local implemtation of the clustering [the default for FastJet<3.2.0] + }; + + /// Constructor without argument + VariableR() {} + + /// Destructor + ~VariableR() {} + + //============================// + // Initialization // + //============================// + // Initialize the parameters of the algorithm. Initialization includes multiple if conditions + // Hence it would be optimum execution to initialize the algorithm during the initialisation + // of the analysis + + // Constructor with arguments + VariableR( + MAfloat32 rho, // mass scale for effective radius (i.e. R ~ rho/pT) + MAfloat32 minR, //minimum jet radius + MAfloat32 maxR, // maximum jet radius + Substructure::VariableR::ClusterType clusterType, + Substructure::VariableR::Strategy strategy = Substructure::VariableR::Best, + MAfloat32 ptmin = 0., // Minimum pT + MAbool isExclusive = false + ) + { Initialize(rho, minR, maxR, clusterType, strategy, ptmin, isExclusive); } + + // Initialization method + void Initialize( + MAfloat32 rho, + MAfloat32 minR, + MAfloat32 maxR, + Substructure::VariableR::ClusterType clusterType, + Substructure::VariableR::Strategy strategy = Substructure::VariableR::Best, + MAfloat32 ptmin = 0., + MAbool isExclusive = false + ); + }; + } +} + + +#endif //MADANALYSIS5_VARIABLER_H diff --git a/tools/SampleAnalyzer/Process/Analyzer/AnalyzerBase.h b/tools/SampleAnalyzer/Process/Analyzer/AnalyzerBase.h index 87bfe24f..d5e53aa9 100644 --- a/tools/SampleAnalyzer/Process/Analyzer/AnalyzerBase.h +++ b/tools/SampleAnalyzer/Process/Analyzer/AnalyzerBase.h @@ -40,6 +40,20 @@ #include "SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h" #include "SampleAnalyzer/Commons/Base/PortableDatatypes.h" +// FJcontrib tools +#ifdef MA5_FASTJET_MODE +#include "SampleAnalyzer/Interfaces/substructure/SoftDrop.h" +#include "SampleAnalyzer/Interfaces/substructure/Cluster.h" +#include "SampleAnalyzer/Interfaces/substructure/Recluster.h" +#include "SampleAnalyzer/Interfaces/substructure/Nsubjettiness.h" +#include "SampleAnalyzer/Interfaces/substructure/VariableR.h" +#include "SampleAnalyzer/Interfaces/substructure/Pruner.h" +#include "SampleAnalyzer/Interfaces/substructure/Selector.h" +#include "SampleAnalyzer/Interfaces/substructure/Filter.h" +#include "SampleAnalyzer/Interfaces/substructure/EnergyCorrelator.h" +#include "SampleAnalyzer/Interfaces/HEPTopTagger/HTT.h" +#endif + // STL headers #include #include @@ -47,184 +61,194 @@ #include #include - // initializing MACRO #define INIT_ANALYSIS(CLASS,NAME) public: CLASS() {setName(NAME);} virtual ~CLASS() {} private: -namespace MA5 -{ - -class AnalyzerBase -{ - - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - public : - - /// name of the analysis - std::string name_; +// Introduce shorthand for widely used reconstructed objects +#define RecJet MA5::RecJetFormat * +typedef std::vector RecJets; +#define RecTau MA5::RecTauFormat * +typedef std::vector RecTaus; +#define RecLepton MA5::RecLeptonFormat * +typedef std::vector RecLeptons; +#define RecPhoton MA5::RecPhotonFormat * +typedef std::vector RecPhotons; +#define RecTrack MA5::RecTrackFormat * +typedef std::vector RecTracks; + + +namespace MA5 { + class AnalyzerBase + { - /// Weighted events mode - MAbool weighted_events_; + // ------------------------------------------------------------- + // data members + // ------------------------------------------------------------- + public : - /// A RS manager is associated with each analysis - RegionSelectionManager manager_; - std::string outputdir_; + /// name of the analysis + std::string name_; - /// Writer SAF - SAFWriter out_; + /// Weighted events mode + MAbool weighted_events_; - // options - std::map options_; - - // parameters - std::map parameters_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public : - - /// Constructor without argument - AnalyzerBase() - { name_="unknown"; outputdir_=""; } - - /// Destructor - virtual ~AnalyzerBase() - { } - - /// Initialize (common part to all analyses) - MAbool PreInitialize(const std::string& outputName, - const Configuration* cfg) - { - weighted_events_ = !cfg->IsNoEventWeight(); - out_.Initialize(cfg,outputName.c_str()); - options_ = cfg->Options(); - return true; - } - - /// Initialize (specific to the analysis) - virtual MAbool Initialize(const Configuration& cfg, - const std::map& parameters)=0; - - MAbool Initialize(const Configuration& cfg) - { - return Initialize(cfg, parameters_); - } - - /// PreFinalize - void PreFinalize(const SampleFormat& summary, - const std::vector& samples) - { - out_.WriteHeader(summary); - out_.WriteFiles(samples); - } - - /// Finalize - virtual void Finalize(const SampleFormat& summary, - const std::vector& samples)=0; - - /// PostFinalize - void PostFinalize(const SampleFormat& summary, - const std::vector& samples) - { - // Closing output file - out_.WriteFoot(summary); - out_.Finalize(); - } - - /// Execute - MAbool PreExecute(const SampleFormat& mySample, - const EventFormat& myEvent) - { - PHYSICS->Id->SetFinalState(myEvent.mc()); - PHYSICS->Id->SetInitialState(myEvent.mc()); - return true; - } - - virtual MAbool Execute(SampleFormat& mySample, - const EventFormat& myEvent)=0; - - /// Accessor to analysis name - const std::string name() const {return name_;} - - /// Accessor to the manager - RegionSelectionManager *Manager() { return &manager_; } - - /// Mutator to analysis name - void setName(const std::string& Name) {name_=Name;} - - /// Accessor to the output directory name - const std::string Output() const {return outputdir_;} - - /// Mutator to the output directory name - void SetOutputDir(const std::string &name) {outputdir_=name;} - - - SAFWriter& out() - { return out_; } - - // Set command line options - void SetOptions(std::map options) {options_=options;} - - // Set parameters, initialized in main.cpp - void SetParameters(std::map params) {parameters_=params;} - - // Accessor to parameters - const std::map GetParameters() {return parameters_;} - - /// Get an option for this analysis instance as a string. - std::string getOption(std::string optname) const - { - if ( options_.find(optname) != options_.end() ) - return options_.find(optname)->second; - return ""; - } - - /// Get an option for this analysis instance converted to a specific type - /// The return type is given by the specified @a def value, or by an explicit template - /// type-argument, e.g. getOption("FOO", 3). - template - T getOption(std::string optname, T def) const { - if (options_.find(optname) == options_.end()) return def; - std::stringstream ss; - ss << options_.find(optname)->second; - T ret; - ss >> ret; - return ret; - } - - /// overload for literal character strings (which don't play well with stringstream) - /// Note this isn't a template specialisation, because we can't return a non-static - /// char*, and T-as-return-type is built into the template function definition. - std::string getOption(std::string optname, const char* def) { - return getOption(optname, def); - } - - // backwards compatibility - void AddDefaultHadronic() - { - try { - throw EXCEPTION_WARNING("This function is deprecated.", "", 1); - } catch (const std::exception& err) { - MANAGE_EXCEPTION(err); - } - } - - void AddDefaultInvisible() - { - try { - throw EXCEPTION_WARNING("This function is deprecated.", "", 1); - } catch (const std::exception& err) { - MANAGE_EXCEPTION(err); + /// A RS manager is associated with each analysis + RegionSelectionManager manager_; + std::string outputdir_; + + /// Writer SAF + SAFWriter out_; + + // options + std::map options_; + + // parameters + std::map parameters_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public : + + /// Constructor without argument + AnalyzerBase() + { name_="unknown"; outputdir_=""; } + + /// Destructor + virtual ~AnalyzerBase() + { } + + /// Initialize (common part to all analyses) + MAbool PreInitialize(const std::string& outputName, + const Configuration* cfg) + { + weighted_events_ = !cfg->IsNoEventWeight(); + out_.Initialize(cfg,outputName.c_str()); + options_ = cfg->Options(); + return true; + } + + /// Initialize (specific to the analysis) + virtual MAbool Initialize(const Configuration& cfg, + const std::map& parameters)=0; + + MAbool Initialize(const Configuration& cfg) + { + return Initialize(cfg, parameters_); + } + + /// PreFinalize + void PreFinalize(const SampleFormat& summary, + const std::vector& samples) + { + out_.WriteHeader(summary); + out_.WriteFiles(samples); + } + + /// Finalize + virtual void Finalize(const SampleFormat& summary, + const std::vector& samples)=0; + + /// PostFinalize + void PostFinalize(const SampleFormat& summary, + const std::vector& samples) + { + // Closing output file + out_.WriteFoot(summary); + out_.Finalize(); + } + + /// Execute + MAbool PreExecute(const SampleFormat& mySample, + const EventFormat& myEvent) + { + PHYSICS->Id->SetFinalState(myEvent.mc()); + PHYSICS->Id->SetInitialState(myEvent.mc()); + return true; } - } - protected : + virtual MAbool Execute(SampleFormat& mySample, + const EventFormat& myEvent)=0; + + /// Accessor to analysis name + const std::string name() const {return name_;} + + /// Accessor to the manager + RegionSelectionManager *Manager() { return &manager_; } + + /// Mutator to analysis name + void setName(const std::string& Name) {name_=Name;} + + /// Accessor to the output directory name + const std::string Output() const {return outputdir_;} + + /// Mutator to the output directory name + void SetOutputDir(const std::string &name) {outputdir_=name;} + + + SAFWriter& out() + { return out_; } + + // Set command line options + void SetOptions(std::map options) {options_=options;} + + // Set parameters, initialized in main.cpp + void SetParameters(std::map params) {parameters_=params;} + + // Accessor to parameters + const std::map GetParameters() {return parameters_;} + + /// Get an option for this analysis instance as a string. + std::string getOption(std::string optname) const + { + if ( options_.find(optname) != options_.end() ) + return options_.find(optname)->second; + return ""; + } + + /// Get an option for this analysis instance converted to a specific type + /// The return type is given by the specified @a def value, or by an explicit template + /// type-argument, e.g. getOption("FOO", 3). + template + T getOption(std::string optname, T def) const { + if (options_.find(optname) == options_.end()) return def; + std::stringstream ss; + ss << options_.find(optname)->second; + T ret; + ss >> ret; + return ret; + } + + /// overload for literal character strings (which don't play well with stringstream) + /// Note this isn't a template specialisation, because we can't return a non-static + /// char*, and T-as-return-type is built into the template function definition. + std::string getOption(std::string optname, const char* def) { + return getOption(optname, def); + } + + + // backwards compatibility + void AddDefaultHadronic() + { + try { + throw EXCEPTION_WARNING("This function is deprecated.", "", 1); + } catch (const std::exception& err) { + MANAGE_EXCEPTION(err); + } + } + + void AddDefaultInvisible() + { + try { + throw EXCEPTION_WARNING("This function is deprecated.", "", 1); + } catch (const std::exception& err) { + MANAGE_EXCEPTION(err); + } + } -}; + protected : + }; } diff --git a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp index 22ab72e6..7956d57f 100644 --- a/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp +++ b/tools/SampleAnalyzer/Process/Core/SampleAnalyzer.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // STL headers #include #include @@ -39,1282 +38,1364 @@ #include "SampleAnalyzer/Commons/Service/ExceptionService.h" #include "SampleAnalyzer/Commons/Service/Physics.h" - using namespace MA5; /// Constructor without arguments -SampleAnalyzer::SampleAnalyzer() +SampleAnalyzer::SampleAnalyzer() { - // Initializing service - MA5::Terminate::Initialize(); - MA5::LogService::GetInstance(); - MA5::ExceptionService::GetInstance(); - MA5::TimeService::GetInstance(); - MA5::PDGService::GetInstance(); - - // Check datatypes - CheckDatatypes(); - - // Initializing pointer to 0 - progressBar_=0; - LastFileFail_=false; - - // Header - INFO << " * SampleAnalyzer for MadAnalysis 5 - Welcome."; - INFO << endmsg; - + // Initializing service + MA5::Terminate::Initialize(); + MA5::LogService::GetInstance(); + MA5::ExceptionService::GetInstance(); + MA5::TimeService::GetInstance(); + MA5::PDGService::GetInstance(); + + // Check datatypes + CheckDatatypes(); + + // Initializing pointer to 0 + progressBar_ = 0; + LastFileFail_ = false; + + // Header + INFO << " * SampleAnalyzer for MadAnalysis 5 - Welcome."; + INFO << endmsg; } - /// CheckDatatypes void SampleAnalyzer::CheckDatatypes() const { - MAuint32 value = 0; - - // MAint8 - try - { - value = sizeof(MAint8); - if (value!=1) throw EXCEPTION_WARNING("MAint8 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(std::exception const& e) - { - MANAGE_EXCEPTION(e); - } - - // MAuint8 - try - { - value = sizeof(MAuint8); - if (value!=1) throw EXCEPTION_WARNING("MAuint8 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - - // MAint16 - try - { - value = sizeof(MAint16); - if (value!=2) throw EXCEPTION_WARNING("MAint16 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - // MAuint16 - try - { - value = sizeof(MAuint16); - if (value!=2) throw EXCEPTION_WARNING("MAuint16 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - // MAint32 - try - { - value = sizeof(MAint32); - if (value!=4) throw EXCEPTION_WARNING("MAint32 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - // MAuint32 - try - { - value = sizeof(MAuint32); - if (value!=4) throw EXCEPTION_WARNING("MAuint32 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - // MAint64 - try - { - value = sizeof(MAint64); - if (value!=8) throw EXCEPTION_WARNING("MAint64 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - // MAuint64 - try - { - value = sizeof(MAuint64); - if (value!=8) throw EXCEPTION_WARNING("MAuint64 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - // MAfloat32 - try - { - value = sizeof(MAfloat32); - if (value!=4) throw EXCEPTION_WARNING("MAfloat32 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - // MAfloat64 - try - { - value = sizeof(MAfloat64); - if (value!=8) throw EXCEPTION_WARNING("MAfloat64 type corresponds to "+CONVERT->ToString(value*8)+" bits","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } + MAuint32 value = 0; + + // MAint8 + try + { + value = sizeof(MAint8); + if (value != 1) + throw EXCEPTION_WARNING("MAint8 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (std::exception const &e) + { + MANAGE_EXCEPTION(e); + } + + // MAuint8 + try + { + value = sizeof(MAuint8); + if (value != 1) + throw EXCEPTION_WARNING("MAuint8 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + // MAint16 + try + { + value = sizeof(MAint16); + if (value != 2) + throw EXCEPTION_WARNING("MAint16 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + // MAuint16 + try + { + value = sizeof(MAuint16); + if (value != 2) + throw EXCEPTION_WARNING("MAuint16 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + // MAint32 + try + { + value = sizeof(MAint32); + if (value != 4) + throw EXCEPTION_WARNING("MAint32 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + // MAuint32 + try + { + value = sizeof(MAuint32); + if (value != 4) + throw EXCEPTION_WARNING("MAuint32 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + // MAint64 + try + { + value = sizeof(MAint64); + if (value != 8) + throw EXCEPTION_WARNING("MAint64 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + // MAuint64 + try + { + value = sizeof(MAuint64); + if (value != 8) + throw EXCEPTION_WARNING("MAuint64 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + // MAfloat32 + try + { + value = sizeof(MAfloat32); + if (value != 4) + throw EXCEPTION_WARNING("MAfloat32 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + + // MAfloat64 + try + { + value = sizeof(MAfloat64); + if (value != 8) + throw EXCEPTION_WARNING("MAfloat64 type corresponds to " + CONVERT->ToString(value * 8) + " bits", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } } - /// Initialization of the SampleAnalyzer -MAbool SampleAnalyzer::Initialize(MAint32 argc, MAchar**argv, - const std::string& pdgFileName) +MAbool SampleAnalyzer::Initialize(MAint32 argc, MAchar **argv, + const std::string &pdgFileName) { - // Initializing general pointers - myReader_ = 0; - - // Configuration - if (!cfg_.Initialize(argc,argv)) return false; - - // Displaying configuration - cfg_.Display(); - - // Treating PDG MA5 : to do - if (pdgFileName=="") {} - - // Getting the list of input files - std::string filename = cfg_.GetInputListName(); - - // Checks if a file has been provided - INFO << " - extracting the list of event samples..." << endmsg; - std::ifstream input(filename.c_str()); - if (!input) - { - ERROR << "The file list '"<< filename << "' is not existing." << endmsg; - return 1; - } - - // Extracting the event filenames from the list - std::string tmp; - while(!input.eof() && !input.fail()) - { - getline(input,tmp); - std::stringstream str; str<>tmp; - if (!tmp.empty()) inputs_.push_back(tmp); - } - input.close(); - - // Checking if the list is empty - if (inputs_.size()==0) - { - ERROR << "The file list '"<< filename << "' is empty." << endmsg; - return false; - } - - // Extracting the analysis name - datasetName_ = filename; - std::string::size_type pos=datasetName_.rfind('.'); - if (pos!=std::string::npos) datasetName_.resize(pos); - pos=datasetName_.rfind('/'); - if (pos!=std::string::npos) datasetName_.erase(0,pos+1); - - // Initializing counters - counter_read_.resize(inputs_.size(),0); - counter_passed_.resize(inputs_.size(),0); - - // Build tables - fullWriters_.BuildTable(); - fullReaders_.BuildTable(); - fullAnalyses_.BuildPredefinedTable(); - fullJetClusterers_.BuildTable(); - fullDetectors_.BuildTable(); - - // Reset counter - file_index_=0; - next_file_=true; - - return true; + // Initializing general pointers + myReader_ = 0; + + // Configuration + if (!cfg_.Initialize(argc, argv)) + return false; + + // Displaying configuration + cfg_.Display(); + + // Treating PDG MA5 : to do + if (pdgFileName == "") + { + } + + // Getting the list of input files + std::string filename = cfg_.GetInputListName(); + + // Checks if a file has been provided + INFO << " - extracting the list of event samples..." << endmsg; + std::ifstream input(filename.c_str()); + if (!input) + { + ERROR << "The file list '" << filename << "' is not existing." << endmsg; + return 1; + } + + // Extracting the event filenames from the list + std::string tmp; + while (!input.eof() && !input.fail()) + { + getline(input, tmp); + std::stringstream str; + str << tmp; + tmp = ""; + str >> tmp; + if (!tmp.empty()) + inputs_.push_back(tmp); + } + input.close(); + + // Checking if the list is empty + if (inputs_.size() == 0) + { + ERROR << "The file list '" << filename << "' is empty." << endmsg; + return false; + } + + // Extracting the analysis name + datasetName_ = filename; + std::string::size_type pos = datasetName_.rfind('.'); + if (pos != std::string::npos) + datasetName_.resize(pos); + pos = datasetName_.rfind('/'); + if (pos != std::string::npos) + datasetName_.erase(0, pos + 1); + + // Initializing counters + counter_read_.resize(inputs_.size(), 0); + counter_passed_.resize(inputs_.size(), 0); + + // Build tables + fullWriters_.BuildTable(); + fullReaders_.BuildTable(); + fullAnalyses_.BuildPredefinedTable(); + fullJetClusterers_.BuildTable(); + fullDetectors_.BuildTable(); + + // Reset counter + file_index_ = 0; + next_file_ = true; + + return true; } -AnalyzerBase* SampleAnalyzer::InitializeAnalyzer(const std::string& name, - const std::string& outputname, - const std::map& parameters) +AnalyzerBase *SampleAnalyzer::InitializeAnalyzer(const std::string &name, + const std::string &outputname, + const std::map ¶meters) { - // Display - INFO << " - analyzer '" - << name << "'" << endmsg; - - // Getting the analysis - AnalyzerBase* myAnalysis = fullAnalyses_.Get(name); - - // Analysis found ? - if (myAnalysis==0) - { - ERROR << "analysis called '" << name << "' is not found" - << endmsg; - return 0; - } - - // Putting the analysis in container - analyzers_.push_back(myAnalysis); - - // Initialize (common part to all analyses) - if (!myAnalysis->PreInitialize(outputname, - &cfg_)) - { - ERROR << "problem during the pre-initialization of the analysis called '" - << name << "'" << endmsg; - return 0; - } - - myAnalysis->SetParameters(parameters); - - // Returning the analysis - return myAnalysis; + // Display + INFO << " - analyzer '" + << name << "'" << endmsg; + + // Getting the analysis + AnalyzerBase *myAnalysis = fullAnalyses_.Get(name); + + // Analysis found ? + if (myAnalysis == 0) + { + ERROR << "analysis called '" << name << "' is not found" + << endmsg; + return 0; + } + + // Putting the analysis in container + analyzers_.push_back(myAnalysis); + + // Initialize (common part to all analyses) + if (!myAnalysis->PreInitialize(outputname, + &cfg_)) + { + ERROR << "problem during the pre-initialization of the analysis called '" + << name << "'" << endmsg; + return 0; + } + + myAnalysis->SetParameters(parameters); + + // Returning the analysis + return myAnalysis; } /// Post initialization: creation of the output directory structure inline MAint32 CreateDir(std::string dirname) { - struct stat myStat; - if (!((stat(dirname.c_str(), &myStat) == 0) && (((myStat.st_mode) & S_IFMT) == S_IFDIR))) - { if(mkdir(dirname.c_str(),0755) != 0) { return -1; } } - else { return 1; } - return 0; + struct stat myStat; + if (!((stat(dirname.c_str(), &myStat) == 0) && (((myStat.st_mode) & S_IFMT) == S_IFDIR))) + { + if (mkdir(dirname.c_str(), 0755) != 0) + { + return -1; + } + } + else + { + return 1; + } + return 0; } /// Creating the Output directory and its sub-structure MAbool SampleAnalyzer::CreateDirectoryStructure() { - // Check if the output directory exists -> if not: create it - std::string dirname="../Output"; - if (CreateDir(dirname)==-1) return false; - - // Check if the SAF directory exists -> if not: create it - dirname="../Output/SAF"; - if (CreateDir(dirname)==-1) return false; - - // Check whether a directory for the investigated dataset exists -> if not create it - dirname = cfg_.GetInputFileName(); - size_t pos = dirname.find_last_of('/'); - if(pos!=std::string::npos) dirname = "../Output/SAF/" + dirname.substr(pos+1); - else dirname = "../Output/SAF/" + dirname; - size_t found = dirname.find(".list"); - if(found!=std::string::npos) dirname.replace(found,5,""); - if(CreateDir(dirname)==-1) { return false; } - - // Creating one subdirectory for each analysis - for(MAuint32 i=0;iname(); - MAint32 check = -1; - for(MAuint32 ii=0; check!=0 ; ii++) - { - std::stringstream ss; ss << ii; - check = CreateDir(newdirname + "_" + ss.str()); - if(check==-1) { return false; } - else { analyzers_[i]->SetOutputDir( newdirname + "_" + ss.str()); } - } - - // Creating one suybdirectory for the histograms and another one for the cutflow - if(CreateDir(analyzers_[i]->Output() + "/Histograms")==-1) { return false; } - if(CreateDir(analyzers_[i]->Output() + "/Cutflows")==-1) { return false; } - } - - // Everything is fine - return true; + // Check if the output directory exists -> if not: create it + std::string dirname = "../Output"; + if (CreateDir(dirname) == -1) + return false; + + // Check if the SAF directory exists -> if not: create it + dirname = "../Output/SAF"; + if (CreateDir(dirname) == -1) + return false; + + // Check whether a directory for the investigated dataset exists -> if not create it + dirname = cfg_.GetInputFileName(); + size_t pos = dirname.find_last_of('/'); + if (pos != std::string::npos) + dirname = "../Output/SAF/" + dirname.substr(pos + 1); + else + dirname = "../Output/SAF/" + dirname; + size_t found = dirname.find(".list"); + if (found != std::string::npos) + dirname.replace(found, 5, ""); + if (CreateDir(dirname) == -1) + { + return false; + } + + // Creating one subdirectory for each analysis + for (MAuint32 i = 0; i < analyzers_.size(); i++) + { + std::string newdirname = dirname + "/" + analyzers_[i]->name(); + MAint32 check = -1; + for (MAuint32 ii = 0; check != 0; ii++) + { + std::stringstream ss; + ss << ii; + check = CreateDir(newdirname + "_" + ss.str()); + if (check == -1) + { + return false; + } + else + { + analyzers_[i]->SetOutputDir(newdirname + "_" + ss.str()); + } + } + + // Creating one suybdirectory for the histograms and another one for the cutflow + if (CreateDir(analyzers_[i]->Output() + "/Histograms") == -1) + { + return false; + } + if (CreateDir(analyzers_[i]->Output() + "/Cutflows") == -1) + { + return false; + } + } + + // Everything is fine + return true; } MAbool SampleAnalyzer::PostInitialize() { - // Creating the directory structure - if(!CreateDirectoryStructure()) - { - ERROR << "The output directory structure cannot be created properly" << endmsg; - return false; - } - - // Initialize (specific to the analysis) - // @JACK: this way analysis will have access to output and name information at initialization - // this is particularly important if one wants to build their own output style where they can - // output the file to the proper directory. - for(auto myAnalysis: analyzers_) - { - if (!myAnalysis->Initialize(cfg_)) - { - ERROR << "problem during the initialization of the analysis called '" - << myAnalysis->name() << "'" << endmsg; - return 0; - } - } - - // Everything was fine - return true; + // Creating the directory structure + if (!CreateDirectoryStructure()) + { + ERROR << "The output directory structure cannot be created properly" << endmsg; + return false; + } + + // Initialize (specific to the analysis) + // @JACK: this way analysis will have access to output and name information at initialization + // this is particularly important if one wants to build their own output style where they can + // output the file to the proper directory. + for (auto myAnalysis : analyzers_) + { + if (!myAnalysis->Initialize(cfg_)) + { + ERROR << "problem during the initialization of the analysis called '" + << myAnalysis->name() << "'" << endmsg; + return 0; + } + } + + // Everything was fine + return true; } - -WriterBase* SampleAnalyzer::InitializeWriter(const std::string& name, - const std::string& outputname) +WriterBase *SampleAnalyzer::InitializeWriter(const std::string &name, + const std::string &outputname) { - // Display - INFO << " - writer corresponding to output file '" - << outputname << "'" << endmsg; - - // Getting the analysis - WriterBase* myWriter = fullWriters_.Get(name); - - // Analysis found ? - if (myWriter==0) - { - ERROR << "writer called '" << name << "' is not found" - << endmsg; - return 0; - } - - // Putting the analysis in container - writers_.push_back(myWriter); - - // Creating the directory structure - // Check if the output directory exists -> if not: create it - std::string dirname="../Output"; - if(CreateDir(dirname)==-1) { return 0; } - - // Check if the SAF directory exists -> if not: create it - dirname="../Output/SAF"; - if(CreateDir(dirname)==-1) { return 0; } - - // Check whether a directory for the investigated dataset exists -> if not create it - dirname = cfg_.GetInputFileName(); - size_t pos = dirname.find_last_of('/'); - if(pos!=std::string::npos) dirname = "../Output/SAF/" + dirname.substr(pos+1); - else dirname = "../Output/SAF/" + dirname; - size_t found = dirname.find(".list"); - if(found!=std::string::npos) dirname.replace(found,5,""); - if(CreateDir(dirname)==-1) { return 0; } - - // Creating one ouptput subdirectory for the writer - std::string newoutdirname=""; - std::stringstream ss0; ss0 << (writers_.size()-1); - MAint32 check = -1; - for(MAuint32 ii=0; check!=0 ; ii++) - { - std::stringstream ss; ss << ii; - newoutdirname = dirname + "/" + name + "Events" + ss0.str() + "_" + ss.str(); - check = CreateDir(newoutdirname); - if(check==-1) { return 0; } - } - - // Initializing - if (!myWriter->Initialize(&cfg_,newoutdirname+'/'+outputname)) - { - ERROR << "problem during the initialization of the writer called '" - << name << "'" << endmsg; - return 0; - } - - // Returning the analysis - return myWriter; + // Display + INFO << " - writer corresponding to output file '" + << outputname << "'" << endmsg; + + // Getting the analysis + WriterBase *myWriter = fullWriters_.Get(name); + + // Analysis found ? + if (myWriter == 0) + { + ERROR << "writer called '" << name << "' is not found" + << endmsg; + return 0; + } + + // Putting the analysis in container + writers_.push_back(myWriter); + + // Creating the directory structure + // Check if the output directory exists -> if not: create it + std::string dirname = "../Output"; + if (CreateDir(dirname) == -1) + { + return 0; + } + + // Check if the SAF directory exists -> if not: create it + dirname = "../Output/SAF"; + if (CreateDir(dirname) == -1) + { + return 0; + } + + // Check whether a directory for the investigated dataset exists -> if not create it + dirname = cfg_.GetInputFileName(); + size_t pos = dirname.find_last_of('/'); + if (pos != std::string::npos) + dirname = "../Output/SAF/" + dirname.substr(pos + 1); + else + dirname = "../Output/SAF/" + dirname; + size_t found = dirname.find(".list"); + if (found != std::string::npos) + dirname.replace(found, 5, ""); + if (CreateDir(dirname) == -1) + { + return 0; + } + + // Creating one ouptput subdirectory for the writer + std::string newoutdirname = ""; + std::stringstream ss0; + ss0 << (writers_.size() - 1); + MAint32 check = -1; + for (MAuint32 ii = 0; check != 0; ii++) + { + std::stringstream ss; + ss << ii; + newoutdirname = dirname + "/" + name + "Events" + ss0.str() + "_" + ss.str(); + check = CreateDir(newoutdirname); + if (check == -1) + { + return 0; + } + } + + // Initializing + if (!myWriter->Initialize(&cfg_, newoutdirname + '/' + outputname)) + { + ERROR << "problem during the initialization of the writer called '" + << name << "'" << endmsg; + return 0; + } + + // Returning the analysis + return myWriter; } - -JetClusterer* SampleAnalyzer::InitializeJetClusterer( - const std::string& name, - const std::map& parameters) +JetClusterer *SampleAnalyzer::InitializeJetClusterer( + const std::string &name, + const std::map ¶meters) { - // Getting the analysis - JetClusterer* myClusterer = fullJetClusterers_.Get(name); - - // Analysis found ? - if (myClusterer==0) - { - ERROR << "jet clustering algorithm called '" << name << "' is not found" - << endmsg; - return 0; - } - - // Display - INFO << " - jet clusterer '" - << myClusterer->GetName() << "'" << endmsg; - - // Putting the analysis in container - clusters_.push_back(myClusterer); - - // Initialize (specific to the analysis) - if (!myClusterer->Initialize(parameters)) - { - ERROR << "problem during the initialization of the jet clusterer called '" - << name << "'" << endmsg; - return 0; - } - - // Display - INFO << " with algo: " << myClusterer->GetParameters() << endmsg; - INFO << " with bjet: " << myClusterer->bParameters() << endmsg; - INFO << " with tau: " << myClusterer->tauParameters() << endmsg; - - // Returning the clusterer - return myClusterer; + // Getting the analysis + JetClusterer *myClusterer = fullJetClusterers_.Get(name); + + // Analysis found ? + if (myClusterer == 0) + { + ERROR << "jet clustering algorithm called '" << name << "' is not found" + << endmsg; + return 0; + } + + // Display + INFO << " - jet clusterer '" + << myClusterer->GetName() << "'" << endmsg; + + // Putting the analysis in container + clusters_.push_back(myClusterer); + + // Initialize (specific to the analysis) + if (!myClusterer->Initialize(parameters)) + { + ERROR << "problem during the initialization of the jet clusterer called '" + << name << "'" << endmsg; + return 0; + } + + // Display + INFO << " with algo: " << myClusterer->GetParameters() << endmsg; + myClusterer->TaggerParameters(); + + // Returning the clusterer + return myClusterer; } - -DetectorBase* SampleAnalyzer::InitializeDetector( - const std::string& name, const std::string& configFile, - const std::map& parameters) +DetectorBase *SampleAnalyzer::InitializeDetector( + const std::string &name, const std::string &configFile, + const std::map ¶meters) { - // Getting the detector - DetectorBase* myDetector = fullDetectors_.Get(name); - - // Detector found ? - if (myDetector==0) - { - ERROR << "detector algorithm called '" << name << "' is not found" - << endmsg; - return 0; - } - - // Display - INFO << " - fast-simulation package '" - << myDetector->GetName() << "'" << endmsg; - - // Putting the detector in container - detectors_.push_back(myDetector); - - // Creating the directory structure - // Check if the output directory exists -> if not: create it - std::string dirname="../Output"; - if(CreateDir(dirname)==-1) { return 0; } - - // Check if the SAF directory exists -> if not: create it - dirname="../SAF"; - if(CreateDir(dirname)==-1) { return 0; } - - // Check whether a directory for the investigated dataset exists -> if not create it - dirname = cfg_.GetInputFileName(); - size_t pos = dirname.find_last_of('/'); - if(pos!=std::string::npos) dirname = "../Output/SAF/" + dirname.substr(pos+1); - else dirname = "../Output/SAF/" + dirname; - size_t found = dirname.find(".list"); - if(found!=std::string::npos) dirname.replace(found,5,""); - if(CreateDir(dirname)==-1) { return 0; } - - // Creating one ouptput subdirectory for the writer - std::string newoutdirname=""; - std::stringstream ss0; ss0 << (detectors_.size()-1); - MAint32 check = -1; - for(MAuint32 ii=0; check!=0 ; ii++) - { - std::stringstream ss; ss << ii; - newoutdirname = dirname + "/RecoEvents" + ss0.str() + "_" + ss.str(); - check = CreateDir(newoutdirname); - if(check==-1) { return 0; } - } - std::map prm2 = parameters; - prm2["outputdir"] = newoutdirname; - - // Initialize (specific to the detector) - std::string ma5dir = std::getenv("MA5_BASE"); - // std::string config = ma5dir+"/tools/SampleAnalyzer/"+configFile; - std::string config = configFile; - if (!myDetector->Initialize(config, prm2)) - { - ERROR << "problem during the initialization of the fast-simulation package called '" - << name << "'" << endmsg; - return 0; - } - - // Display - INFO << myDetector->PrintConfigFile() << endmsg; - - // Returning the clusterer - return myDetector; + // Getting the detector + DetectorBase *myDetector = fullDetectors_.Get(name); + + // Detector found ? + if (myDetector == 0) + { + ERROR << "detector algorithm called '" << name << "' is not found" + << endmsg; + return 0; + } + + // Display + INFO << " - fast-simulation package '" + << myDetector->GetName() << "'" << endmsg; + + // Putting the detector in container + detectors_.push_back(myDetector); + + // Creating the directory structure + // Check if the output directory exists -> if not: create it + std::string dirname = "../Output"; + if (CreateDir(dirname) == -1) + { + return 0; + } + + // Check if the SAF directory exists -> if not: create it + dirname = "../SAF"; + if (CreateDir(dirname) == -1) + { + return 0; + } + + // Check whether a directory for the investigated dataset exists -> if not create it + dirname = cfg_.GetInputFileName(); + size_t pos = dirname.find_last_of('/'); + if (pos != std::string::npos) + dirname = "../Output/SAF/" + dirname.substr(pos + 1); + else + dirname = "../Output/SAF/" + dirname; + size_t found = dirname.find(".list"); + if (found != std::string::npos) + dirname.replace(found, 5, ""); + if (CreateDir(dirname) == -1) + { + return 0; + } + + // Creating one ouptput subdirectory for the writer + std::string newoutdirname = ""; + std::stringstream ss0; + ss0 << (detectors_.size() - 1); + MAint32 check = -1; + for (MAuint32 ii = 0; check != 0; ii++) + { + std::stringstream ss; + ss << ii; + newoutdirname = dirname + "/RecoEvents" + ss0.str() + "_" + ss.str(); + check = CreateDir(newoutdirname); + if (check == -1) + { + return 0; + } + } + std::map prm2 = parameters; + prm2["outputdir"] = newoutdirname; + + // Initialize (specific to the detector) + std::string ma5dir = std::getenv("MA5_BASE"); + // std::string config = ma5dir+"/tools/SampleAnalyzer/"+configFile; + std::string config = configFile; + if (!myDetector->Initialize(config, prm2)) + { + ERROR << "problem during the initialization of the fast-simulation package called '" + << name << "'" << endmsg; + return 0; + } + + // Display + INFO << myDetector->PrintConfigFile() << endmsg; + + // Returning the clusterer + return myDetector; } /// Reading the next event -StatusCode::Type SampleAnalyzer::NextFile(SampleFormat& mySample) +StatusCode::Type SampleAnalyzer::NextFile(SampleFormat &mySample) { - // Finalize previous file - if (myReader_!=0) - { - myReader_->Finalize(); - } - - // Finalize previous progress bar - if (!LastFileFail_ && progressBar_!=0) - { - progressBar_->Finalize(); - INFO << " => total number of events: " << counter_read_[file_index_-1] - << " ( analyzed: " << counter_passed_[file_index_-1] - << " ; skipped: " << counter_read_[file_index_-1] - counter_passed_[file_index_-1] - << " ) " << endmsg; - } - LastFileFail_=false; - - // Next file - file_index_++; - - // Have we read the last file ? - if (file_index_>inputs_.size()) return StatusCode::FAILURE; - next_file_=false; - - // Progression bar - INFO << " * " << file_index_ <<"/" << inputs_.size() << " "; - INFO << " " << inputs_[file_index_-1] << endmsg; - - // Data format - mySample.setName(inputs_[file_index_-1]); - - // Find an appropiate reader for the file - myReader_ = fullReaders_.GetByFileExtension(inputs_[file_index_-1]); - if (myReader_==0) - { - ERROR << "the format of the input file is not supported. " - << "The file is skipped." - << endmsg; - LastFileFail_=true; - return StatusCode::SKIP; - } - - // Initialize the reader - if (!myReader_->Initialize(inputs_[file_index_-1], cfg_)) - { - LastFileFail_=true; - return StatusCode::SKIP; - } - - // Displaying the size of the file - MAint64 length = myReader_->GetFileSize(); - if (length<0) INFO << " => file size: unknown" << endmsg; - else - { - MAuint32 unit = 0; - MAfloat64 value=0; - if (length>1e12) - { - value = static_cast(length)/(1024.*1024.*1024.*1024.); - unit=5; - } - if (length>1e9) - { - value = static_cast(length)/(1024.*1024.*1024.); - unit=4; - } - else if (length>1e6) - { - value = static_cast(length)/(1024.*1024.); - unit=3; - } - else if (length>1e3) - { - value = static_cast(length)/1024.; - unit=2; - } - else - { - value = length; - unit=1; - } - std::stringstream str; - if (unit==1) str << static_cast(value); - else str << std::fixed << std::setprecision(2) << value; - str << " "; - if (unit==1) str << "octets"; - else if (unit==2) str << "ko"; - else if (unit==3) str << "Mo"; - else if (unit==4) str << "Go"; - else if (unit==5) str << "To"; - else str << "muf"; - - INFO << " => file size: " << str.str() << endmsg; - } - length = myReader_->GetFinalPosition(); - - // Read the header block - if (!myReader_->ReadHeader(mySample)) - { - ERROR << "No header has been found. " - << "The file is skipped." << endmsg; - LastFileFail_=true; - return StatusCode::SKIP; - } - - // Finalize the header block - myReader_->FinalizeHeader(mySample); - - // Dump the header block - mySample.printSubtitle(); - - // Initialize the progress bar - if (progressBar_==0) progressBar_ = new ProgressBar(); - progressBar_->Initialize(35,0,length); - - // Ok ! - return StatusCode::KEEP; + // Finalize previous file + if (myReader_ != 0) + { + myReader_->Finalize(); + } + + // Finalize previous progress bar + if (!LastFileFail_ && progressBar_ != 0) + { + progressBar_->Finalize(); + INFO << " => total number of events: " << counter_read_[file_index_ - 1] + << " ( analyzed: " << counter_passed_[file_index_ - 1] + << " ; skipped: " << counter_read_[file_index_ - 1] - counter_passed_[file_index_ - 1] + << " ) " << endmsg; + } + LastFileFail_ = false; + + // Next file + file_index_++; + + // Have we read the last file ? + if (file_index_ > inputs_.size()) + return StatusCode::FAILURE; + next_file_ = false; + + // Progression bar + INFO << " * " << file_index_ << "/" << inputs_.size() << " "; + INFO << " " << inputs_[file_index_ - 1] << endmsg; + + // Data format + mySample.setName(inputs_[file_index_ - 1]); + + // Find an appropiate reader for the file + myReader_ = fullReaders_.GetByFileExtension(inputs_[file_index_ - 1]); + if (myReader_ == 0) + { + ERROR << "the format of the input file is not supported. " + << "The file is skipped." + << endmsg; + LastFileFail_ = true; + return StatusCode::SKIP; + } + + // Initialize the reader + if (!myReader_->Initialize(inputs_[file_index_ - 1], cfg_)) + { + LastFileFail_ = true; + return StatusCode::SKIP; + } + + // Displaying the size of the file + MAint64 length = myReader_->GetFileSize(); + if (length < 0) + INFO << " => file size: unknown" << endmsg; + else + { + MAuint32 unit = 0; + MAfloat64 value = 0; + if (length > 1e12) + { + value = static_cast(length) / (1024. * 1024. * 1024. * 1024.); + unit = 5; + } + if (length > 1e9) + { + value = static_cast(length) / (1024. * 1024. * 1024.); + unit = 4; + } + else if (length > 1e6) + { + value = static_cast(length) / (1024. * 1024.); + unit = 3; + } + else if (length > 1e3) + { + value = static_cast(length) / 1024.; + unit = 2; + } + else + { + value = length; + unit = 1; + } + std::stringstream str; + if (unit == 1) + str << static_cast(value); + else + str << std::fixed << std::setprecision(2) << value; + str << " "; + if (unit == 1) + str << "octets"; + else if (unit == 2) + str << "ko"; + else if (unit == 3) + str << "Mo"; + else if (unit == 4) + str << "Go"; + else if (unit == 5) + str << "To"; + else + str << "muf"; + + INFO << " => file size: " << str.str() << endmsg; + } + length = myReader_->GetFinalPosition(); + + // Read the header block + if (!myReader_->ReadHeader(mySample)) + { + ERROR << "No header has been found. " + << "The file is skipped." << endmsg; + LastFileFail_ = true; + return StatusCode::SKIP; + } + + // Finalize the header block + myReader_->FinalizeHeader(mySample); + + // Dump the header block + mySample.printSubtitle(); + + // Initialize the progress bar + if (progressBar_ == 0) + progressBar_ = new ProgressBar(); + progressBar_->Initialize(35, 0, length); + + // Ok ! + return StatusCode::KEEP; } - /// Reading the next event -StatusCode::Type SampleAnalyzer::NextEvent(SampleFormat& mySample, EventFormat& myEvent) +StatusCode::Type SampleAnalyzer::NextEvent(SampleFormat &mySample, EventFormat &myEvent) { - // Read an event - StatusCode::Type test=myReader_->ReadEvent(myEvent, mySample); - - // GOOD case - if (test==StatusCode::KEEP) - { - // Incrementing counter of number of read events - counter_read_[file_index_-1]++; - - // Finalize the event and filter the event - if (!myReader_->FinalizeEvent(mySample,myEvent)) return StatusCode::SKIP; - - // Incrementing counter of number of good events - counter_passed_[file_index_-1]++; - - // Ok ! - return StatusCode::KEEP; - } - - // SKIP case - else if (test==StatusCode::SKIP) - { - counter_read_[file_index_-1]++; - return test; - } - - // FAILURE case - else if (test==StatusCode::FAILURE) return test; - - return StatusCode::KEEP; + // Read an event + StatusCode::Type test = myReader_->ReadEvent(myEvent, mySample); + + // GOOD case + if (test == StatusCode::KEEP) + { + // Incrementing counter of number of read events + counter_read_[file_index_ - 1]++; + + // Finalize the event and filter the event + if (!myReader_->FinalizeEvent(mySample, myEvent)) + return StatusCode::SKIP; + + // Incrementing counter of number of good events + counter_passed_[file_index_ - 1]++; + + // Ok ! + return StatusCode::KEEP; + } + + // SKIP case + else if (test == StatusCode::SKIP) + { + counter_read_[file_index_ - 1]++; + return test; + } + + // FAILURE case + else if (test == StatusCode::FAILURE) + return test; + + return StatusCode::KEEP; } - /// Home made functions to make reasonnable filenames inline void ReplaceAll(std::string &name, const std::string &In, const std::string &Out) { - size_t pos = name.find(In); - while(pos!=std::string::npos) - { - name.replace(pos,In.size(),Out); - pos = name.find(In); - } + size_t pos = name.find(In); + while (pos != std::string::npos) + { + name.replace(pos, In.size(), Out); + pos = name.find(In); + } } inline std::string CleanName(const std::string &name) { - std::string tmp=name; - ReplaceAll(tmp, "/", "_slash_"); - ReplaceAll(tmp, "->", "_to_"); - ReplaceAll(tmp, ">=", "_greater_than_or_equal_to_"); - ReplaceAll(tmp, ">", "_greater_than_"); - ReplaceAll(tmp, "<=", "_smaller_than_or_equal_to_"); - ReplaceAll(tmp, "<", "_smaller_than_"); - ReplaceAll(tmp, " ", "_"); - ReplaceAll(tmp, ",", "_"); - ReplaceAll(tmp, "+", "_"); - ReplaceAll(tmp, "-", "_"); - ReplaceAll(tmp, "(", "_lp_"); - ReplaceAll(tmp, ")", "_rp_"); - return tmp; + std::string tmp = name; + ReplaceAll(tmp, "/", "_slash_"); + ReplaceAll(tmp, "->", "_to_"); + ReplaceAll(tmp, ">=", "_greater_than_or_equal_to_"); + ReplaceAll(tmp, ">", "_greater_than_"); + ReplaceAll(tmp, "<=", "_smaller_than_or_equal_to_"); + ReplaceAll(tmp, "<", "_smaller_than_"); + ReplaceAll(tmp, " ", "_"); + ReplaceAll(tmp, ",", "_"); + ReplaceAll(tmp, "+", "_"); + ReplaceAll(tmp, "-", "_"); + ReplaceAll(tmp, "(", "_lp_"); + ReplaceAll(tmp, ")", "_rp_"); + return tmp; } /// Finalize fuction -MAbool SampleAnalyzer::Finalize(std::vector& mySamples, - EventFormat& myEvent) +MAbool SampleAnalyzer::Finalize(std::vector &mySamples, + EventFormat &myEvent) { - // ----------------------------------------------------------------------- - // DUMP NUMBER OF EVENT - // ----------------------------------------------------------------------- - INFO << " * Total number of processed events: "; - MAuint64 nInitial = 0; - MAuint64 nPassed = 0; - - for (MAuint32 i=0;iOutput() + "/Histograms/histos.saf"; - out.Initialize(&cfg_, safname.c_str()); - out.WriteHeader(); - analyzers_[i]->Manager()->GetPlotManager()->Write_TextFormat(out); - out.WriteFoot(); - out.Finalize(); - } - - // Linking the histos to the SRs - for(MAuint32 i=0; iOutput() + "/" + analyzers_[i]->name() + ".saf"; - out.Initialize(&cfg_, safname.c_str()); - out.WriteHeader(); - analyzers_[i]->Manager()->WriteHistoDefinition(out); - out.WriteFoot(); - out.Finalize(); - } - - - // Saving the cut flows - for(MAuint32 i=0; iManager()->Regions().size(); j++) - { - RegionSelection *myRS = myanalysis->Manager()->Regions()[j]; - std::string safname = myanalysis->Output() + "/Cutflows/" + - CleanName(myRS->GetName()) + ".saf"; - out.Initialize(&cfg_, safname.c_str()); - out.WriteHeader(); - myRS->WriteCutflow(out); - out.WriteFoot(); - out.Finalize(); - } - } - - // The user-defined stuff - for(MAuint32 i=0; iFinalize(summary,mySamples); - - // Finalize clusters - for (MAuint32 i=0;iFinalize(); - } - - // Finalize wrtiers - for(MAuint32 i=0; iWriteFoot(summary); - writers_[i]->Finalize(); - } - - // Finalize detectors - for (MAuint32 i=0;iFinalize(); - } - - // Display reports - MA5::TimeService::GetInstance()->WriteGenericReport(); - MA5::ExceptionService::GetInstance()->WarningReport().WriteGenericReport(); - MA5::ExceptionService::GetInstance()->ErrorReport().WriteGenericReport(); - - // Kill all singleton services - MA5::LogService::Kill(); - MA5::ExceptionService::Kill(); - MA5::TimeService::Kill(); - MA5::PDGService::Kill(); - MA5::PhysicsService::kill(); - - // ----------------------------------------------------------------------- - // Bye bye message - // ----------------------------------------------------------------------- - INFO << " * Goodbye."<Output() + "/Histograms/histos.saf"; + out.Initialize(&cfg_, safname.c_str()); + out.WriteHeader(); + analyzers_[i]->Manager()->GetPlotManager()->Write_TextFormat(out); + out.WriteFoot(); + out.Finalize(); + } + + // Linking the histos to the SRs + for (MAuint32 i = 0; i < analyzers_.size(); i++) + { + std::string safname = analyzers_[i]->Output() + "/" + analyzers_[i]->name() + ".saf"; + out.Initialize(&cfg_, safname.c_str()); + out.WriteHeader(); + analyzers_[i]->Manager()->WriteHistoDefinition(out); + out.WriteFoot(); + out.Finalize(); + } + + // Saving the cut flows + for (MAuint32 i = 0; i < analyzers_.size(); i++) + { + AnalyzerBase *myanalysis = analyzers_[i]; + for (MAuint32 j = 0; j < myanalysis->Manager()->Regions().size(); j++) + { + RegionSelection *myRS = myanalysis->Manager()->Regions()[j]; + std::string safname = myanalysis->Output() + "/Cutflows/" + + CleanName(myRS->GetName()) + ".saf"; + out.Initialize(&cfg_, safname.c_str()); + out.WriteHeader(); + myRS->WriteCutflow(out); + out.WriteFoot(); + out.Finalize(); + } + } + + // The user-defined stuff + for (MAuint32 i = 0; i < analyzers_.size(); i++) + analyzers_[i]->Finalize(summary, mySamples); + + // Finalize clusters + for (MAuint32 i = 0; i < clusters_.size(); i++) + { + clusters_[i]->Finalize(); + } + + // Finalize wrtiers + for (MAuint32 i = 0; i < writers_.size(); i++) + { + writers_[i]->WriteFoot(summary); + writers_[i]->Finalize(); + } + + // Finalize detectors + for (MAuint32 i = 0; i < detectors_.size(); i++) + { + detectors_[i]->Finalize(); + } + + // Display reports + MA5::TimeService::GetInstance()->WriteGenericReport(); + MA5::ExceptionService::GetInstance()->WarningReport().WriteGenericReport(); + MA5::ExceptionService::GetInstance()->ErrorReport().WriteGenericReport(); + + // Kill all singleton services + MA5::LogService::Kill(); + MA5::ExceptionService::Kill(); + MA5::TimeService::Kill(); + MA5::PDGService::Kill(); + MA5::PhysicsService::kill(); + + // ----------------------------------------------------------------------- + // Bye bye message + // ----------------------------------------------------------------------- + INFO << " * Goodbye." << endmsg; + return true; } - -void SampleAnalyzer::FillSummary(SampleFormat& summary, - const std::vector& samples) +void SampleAnalyzer::FillSummary(SampleFormat &summary, + const std::vector &samples) { - // Create a SampleFormat container for summary info - summary.setName("FINAL"); - summary.InitializeMC(); - summary.InitializeRec(); - - // Loop over samples - for (MAuint32 i=0;ixsection_ += samples[i].mc()->xsection() * - samples[i].nevents_; - summary.mc()->xsection_error_ += samples[i].mc()->xsection_error() * - samples[i].mc()->xsection_error() * - samples[i].nevents_ * - samples[i].nevents_; - - // Sum of weights - summary.mc()->sumweight_positive_ += samples[i].mc()->sumweight_positive_; - summary.mc()->sumweight_negative_ += samples[i].mc()->sumweight_negative_; - } - - // Finalizing xsection - if (summary.nevents_!=0) - { - summary.mc()->xsection_ /= summary.nevents_; - summary.mc()->xsection_error_ = sqrt(summary.mc()->xsection_error_) / - summary.nevents_; - } - else - { - summary.mc()->xsection_ = 0; - summary.mc()->xsection_error_ = 0; - } - + // Create a SampleFormat container for summary info + summary.setName("FINAL"); + summary.InitializeMC(); + summary.InitializeRec(); + + // Loop over samples + for (MAuint32 i = 0; i < samples.size(); i++) + { + // Total number of events + summary.nevents_ += samples[i].nevents_; + + // Requiring MC info + if (samples[i].mc() == 0) + continue; + + // Mean cross-section + summary.mc()->xsection_ += samples[i].mc()->xsection() * + samples[i].nevents_; + summary.mc()->xsection_error_ += samples[i].mc()->xsection_error() * + samples[i].mc()->xsection_error() * + samples[i].nevents_ * + samples[i].nevents_; + + // Sum of weights + summary.mc()->sumweight_positive_ += samples[i].mc()->sumweight_positive_; + summary.mc()->sumweight_negative_ += samples[i].mc()->sumweight_negative_; + } + + // Finalizing xsection + if (summary.nevents_ != 0) + { + summary.mc()->xsection_ /= summary.nevents_; + summary.mc()->xsection_error_ = sqrt(summary.mc()->xsection_error_) / + summary.nevents_; + } + else + { + summary.mc()->xsection_ = 0; + summary.mc()->xsection_error_ = 0; + } } - - /// Updating the progress bar void SampleAnalyzer::UpdateProgressBar() { - progressBar_->Update(myReader_->GetPosition()); + progressBar_->Update(myReader_->GetPosition()); } - - void SampleAnalyzer::HeadSR(std::ostream &outwriter) { - outwriter << "#"; - for(MAuint32 i=0; iManager()->HeadSR(outwriter, analyzers_[i]->name()); - } + for (MAuint32 i = 0; i < analyzers_.size(); i++) + { + MAbool is_first = (i == 0); + analyzers_[i]->Manager()->HeadSR(outwriter, analyzers_[i]->name(), is_first); + } } - void SampleAnalyzer::DumpSR(std::ostream &outwriter) { - for(MAuint32 i=0; iManager()->DumpSR(outwriter); - outwriter << std::endl; + for (MAuint32 i = 0; i < analyzers_.size(); i++) + { + MAbool is_first = (i == 0); + analyzers_[i]->Manager()->DumpSR(outwriter, is_first); + } + outwriter << std::endl; } void SampleAnalyzer::AddDefaultHadronic() { - // definition of the multiparticle "hadronic" - PHYSICS->mcConfig().AddHadronicId(-20543); - PHYSICS->mcConfig().AddHadronicId(-20533); - PHYSICS->mcConfig().AddHadronicId(-20523); - PHYSICS->mcConfig().AddHadronicId(-20513); - PHYSICS->mcConfig().AddHadronicId(-20433); - PHYSICS->mcConfig().AddHadronicId(-20423); - PHYSICS->mcConfig().AddHadronicId(-20413); - PHYSICS->mcConfig().AddHadronicId(-20323); - PHYSICS->mcConfig().AddHadronicId(-20313); - PHYSICS->mcConfig().AddHadronicId(-20213); - PHYSICS->mcConfig().AddHadronicId(-10543); - PHYSICS->mcConfig().AddHadronicId(-10541); - PHYSICS->mcConfig().AddHadronicId(-10533); - PHYSICS->mcConfig().AddHadronicId(-10531); - PHYSICS->mcConfig().AddHadronicId(-10523); - PHYSICS->mcConfig().AddHadronicId(-10521); - PHYSICS->mcConfig().AddHadronicId(-10513); - PHYSICS->mcConfig().AddHadronicId(-10511); - PHYSICS->mcConfig().AddHadronicId(-10433); - PHYSICS->mcConfig().AddHadronicId(-10431); - PHYSICS->mcConfig().AddHadronicId(-10423); - PHYSICS->mcConfig().AddHadronicId(-10421); - PHYSICS->mcConfig().AddHadronicId(-10413); - PHYSICS->mcConfig().AddHadronicId(-10411); - PHYSICS->mcConfig().AddHadronicId(-10323); - PHYSICS->mcConfig().AddHadronicId(-10321); - PHYSICS->mcConfig().AddHadronicId(-10313); - PHYSICS->mcConfig().AddHadronicId(-10311); - PHYSICS->mcConfig().AddHadronicId(-10213); - PHYSICS->mcConfig().AddHadronicId(-10211); - PHYSICS->mcConfig().AddHadronicId(-5554); - PHYSICS->mcConfig().AddHadronicId(-5544); - PHYSICS->mcConfig().AddHadronicId(-5542); - PHYSICS->mcConfig().AddHadronicId(-5534); - PHYSICS->mcConfig().AddHadronicId(-5532); - PHYSICS->mcConfig().AddHadronicId(-5524); - PHYSICS->mcConfig().AddHadronicId(-5522); - PHYSICS->mcConfig().AddHadronicId(-5514); - PHYSICS->mcConfig().AddHadronicId(-5512); - PHYSICS->mcConfig().AddHadronicId(-5503); - PHYSICS->mcConfig().AddHadronicId(-5444); - PHYSICS->mcConfig().AddHadronicId(-5442); - PHYSICS->mcConfig().AddHadronicId(-5434); - PHYSICS->mcConfig().AddHadronicId(-5432); - PHYSICS->mcConfig().AddHadronicId(-5424); - PHYSICS->mcConfig().AddHadronicId(-5422); - PHYSICS->mcConfig().AddHadronicId(-5414); - PHYSICS->mcConfig().AddHadronicId(-5412); - PHYSICS->mcConfig().AddHadronicId(-5403); - PHYSICS->mcConfig().AddHadronicId(-5401); - PHYSICS->mcConfig().AddHadronicId(-5342); - PHYSICS->mcConfig().AddHadronicId(-5334); - PHYSICS->mcConfig().AddHadronicId(-5332); - PHYSICS->mcConfig().AddHadronicId(-5324); - PHYSICS->mcConfig().AddHadronicId(-5322); - PHYSICS->mcConfig().AddHadronicId(-5314); - PHYSICS->mcConfig().AddHadronicId(-5312); - PHYSICS->mcConfig().AddHadronicId(-5303); - PHYSICS->mcConfig().AddHadronicId(-5301); - PHYSICS->mcConfig().AddHadronicId(-5242); - PHYSICS->mcConfig().AddHadronicId(-5232); - PHYSICS->mcConfig().AddHadronicId(-5224); - PHYSICS->mcConfig().AddHadronicId(-5222); - PHYSICS->mcConfig().AddHadronicId(-5214); - PHYSICS->mcConfig().AddHadronicId(-5212); - PHYSICS->mcConfig().AddHadronicId(-5203); - PHYSICS->mcConfig().AddHadronicId(-5201); - PHYSICS->mcConfig().AddHadronicId(-5142); - PHYSICS->mcConfig().AddHadronicId(-5132); - PHYSICS->mcConfig().AddHadronicId(-5122); - PHYSICS->mcConfig().AddHadronicId(-5114); - PHYSICS->mcConfig().AddHadronicId(-5112); - PHYSICS->mcConfig().AddHadronicId(-5103); - PHYSICS->mcConfig().AddHadronicId(-5101); - PHYSICS->mcConfig().AddHadronicId(-4444); - PHYSICS->mcConfig().AddHadronicId(-4434); - PHYSICS->mcConfig().AddHadronicId(-4432); - PHYSICS->mcConfig().AddHadronicId(-4424); - PHYSICS->mcConfig().AddHadronicId(-4422); - PHYSICS->mcConfig().AddHadronicId(-4414); - PHYSICS->mcConfig().AddHadronicId(-4412); - PHYSICS->mcConfig().AddHadronicId(-4403); - PHYSICS->mcConfig().AddHadronicId(-4334); - PHYSICS->mcConfig().AddHadronicId(-4332); - PHYSICS->mcConfig().AddHadronicId(-4324); - PHYSICS->mcConfig().AddHadronicId(-4322); - PHYSICS->mcConfig().AddHadronicId(-4314); - PHYSICS->mcConfig().AddHadronicId(-4312); - PHYSICS->mcConfig().AddHadronicId(-4303); - PHYSICS->mcConfig().AddHadronicId(-4301); - PHYSICS->mcConfig().AddHadronicId(-4232); - PHYSICS->mcConfig().AddHadronicId(-4224); - PHYSICS->mcConfig().AddHadronicId(-4222); - PHYSICS->mcConfig().AddHadronicId(-4214); - PHYSICS->mcConfig().AddHadronicId(-4212); - PHYSICS->mcConfig().AddHadronicId(-4203); - PHYSICS->mcConfig().AddHadronicId(-4201); - PHYSICS->mcConfig().AddHadronicId(-4132); - PHYSICS->mcConfig().AddHadronicId(-4122); - PHYSICS->mcConfig().AddHadronicId(-4114); - PHYSICS->mcConfig().AddHadronicId(-4112); - PHYSICS->mcConfig().AddHadronicId(-4103); - PHYSICS->mcConfig().AddHadronicId(-4101); - PHYSICS->mcConfig().AddHadronicId(-3334); - PHYSICS->mcConfig().AddHadronicId(-3324); - PHYSICS->mcConfig().AddHadronicId(-3322); - PHYSICS->mcConfig().AddHadronicId(-3314); - PHYSICS->mcConfig().AddHadronicId(-3312); - PHYSICS->mcConfig().AddHadronicId(-3303); - PHYSICS->mcConfig().AddHadronicId(-3224); - PHYSICS->mcConfig().AddHadronicId(-3222); - PHYSICS->mcConfig().AddHadronicId(-3214); - PHYSICS->mcConfig().AddHadronicId(-3212); - PHYSICS->mcConfig().AddHadronicId(-3203); - PHYSICS->mcConfig().AddHadronicId(-3201); - PHYSICS->mcConfig().AddHadronicId(-3122); - PHYSICS->mcConfig().AddHadronicId(-3114); - PHYSICS->mcConfig().AddHadronicId(-3112); - PHYSICS->mcConfig().AddHadronicId(-3103); - PHYSICS->mcConfig().AddHadronicId(-3101); - PHYSICS->mcConfig().AddHadronicId(-2224); - PHYSICS->mcConfig().AddHadronicId(-2214); - PHYSICS->mcConfig().AddHadronicId(-2212); - PHYSICS->mcConfig().AddHadronicId(-2203); - PHYSICS->mcConfig().AddHadronicId(-2114); - PHYSICS->mcConfig().AddHadronicId(-2112); - PHYSICS->mcConfig().AddHadronicId(-2103); - PHYSICS->mcConfig().AddHadronicId(-2101); - PHYSICS->mcConfig().AddHadronicId(-1114); - PHYSICS->mcConfig().AddHadronicId(-1103); - PHYSICS->mcConfig().AddHadronicId(-545); - PHYSICS->mcConfig().AddHadronicId(-543); - PHYSICS->mcConfig().AddHadronicId(-541); - PHYSICS->mcConfig().AddHadronicId(-535); - PHYSICS->mcConfig().AddHadronicId(-533); - PHYSICS->mcConfig().AddHadronicId(-531); - PHYSICS->mcConfig().AddHadronicId(-525); - PHYSICS->mcConfig().AddHadronicId(-523); - PHYSICS->mcConfig().AddHadronicId(-521); - PHYSICS->mcConfig().AddHadronicId(-515); - PHYSICS->mcConfig().AddHadronicId(-513); - PHYSICS->mcConfig().AddHadronicId(-511); - PHYSICS->mcConfig().AddHadronicId(-435); - PHYSICS->mcConfig().AddHadronicId(-433); - PHYSICS->mcConfig().AddHadronicId(-431); - PHYSICS->mcConfig().AddHadronicId(-425); - PHYSICS->mcConfig().AddHadronicId(-423); - PHYSICS->mcConfig().AddHadronicId(-421); - PHYSICS->mcConfig().AddHadronicId(-415); - PHYSICS->mcConfig().AddHadronicId(-413); - PHYSICS->mcConfig().AddHadronicId(-411); - PHYSICS->mcConfig().AddHadronicId(-325); - PHYSICS->mcConfig().AddHadronicId(-323); - PHYSICS->mcConfig().AddHadronicId(-321); - PHYSICS->mcConfig().AddHadronicId(-315); - PHYSICS->mcConfig().AddHadronicId(-313); - PHYSICS->mcConfig().AddHadronicId(-311); - PHYSICS->mcConfig().AddHadronicId(-215); - PHYSICS->mcConfig().AddHadronicId(-213); - PHYSICS->mcConfig().AddHadronicId(-211); - PHYSICS->mcConfig().AddHadronicId(111); - PHYSICS->mcConfig().AddHadronicId(113); - PHYSICS->mcConfig().AddHadronicId(115); - PHYSICS->mcConfig().AddHadronicId(130); - PHYSICS->mcConfig().AddHadronicId(211); - PHYSICS->mcConfig().AddHadronicId(213); - PHYSICS->mcConfig().AddHadronicId(215); - PHYSICS->mcConfig().AddHadronicId(221); - PHYSICS->mcConfig().AddHadronicId(223); - PHYSICS->mcConfig().AddHadronicId(225); - PHYSICS->mcConfig().AddHadronicId(310); - PHYSICS->mcConfig().AddHadronicId(311); - PHYSICS->mcConfig().AddHadronicId(313); - PHYSICS->mcConfig().AddHadronicId(315); - PHYSICS->mcConfig().AddHadronicId(321); - PHYSICS->mcConfig().AddHadronicId(323); - PHYSICS->mcConfig().AddHadronicId(325); - PHYSICS->mcConfig().AddHadronicId(331); - PHYSICS->mcConfig().AddHadronicId(333); - PHYSICS->mcConfig().AddHadronicId(335); - PHYSICS->mcConfig().AddHadronicId(411); - PHYSICS->mcConfig().AddHadronicId(413); - PHYSICS->mcConfig().AddHadronicId(415); - PHYSICS->mcConfig().AddHadronicId(421); - PHYSICS->mcConfig().AddHadronicId(423); - PHYSICS->mcConfig().AddHadronicId(425); - PHYSICS->mcConfig().AddHadronicId(431); - PHYSICS->mcConfig().AddHadronicId(433); - PHYSICS->mcConfig().AddHadronicId(435); - PHYSICS->mcConfig().AddHadronicId(441); - PHYSICS->mcConfig().AddHadronicId(443); - PHYSICS->mcConfig().AddHadronicId(445); - PHYSICS->mcConfig().AddHadronicId(511); - PHYSICS->mcConfig().AddHadronicId(513); - PHYSICS->mcConfig().AddHadronicId(515); - PHYSICS->mcConfig().AddHadronicId(521); - PHYSICS->mcConfig().AddHadronicId(523); - PHYSICS->mcConfig().AddHadronicId(525); - PHYSICS->mcConfig().AddHadronicId(531); - PHYSICS->mcConfig().AddHadronicId(533); - PHYSICS->mcConfig().AddHadronicId(535); - PHYSICS->mcConfig().AddHadronicId(541); - PHYSICS->mcConfig().AddHadronicId(543); - PHYSICS->mcConfig().AddHadronicId(545); - PHYSICS->mcConfig().AddHadronicId(551); - PHYSICS->mcConfig().AddHadronicId(553); - PHYSICS->mcConfig().AddHadronicId(555); - PHYSICS->mcConfig().AddHadronicId(1103); - PHYSICS->mcConfig().AddHadronicId(1114); - PHYSICS->mcConfig().AddHadronicId(2101); - PHYSICS->mcConfig().AddHadronicId(2103); - PHYSICS->mcConfig().AddHadronicId(2112); - PHYSICS->mcConfig().AddHadronicId(2114); - PHYSICS->mcConfig().AddHadronicId(2203); - PHYSICS->mcConfig().AddHadronicId(2212); - PHYSICS->mcConfig().AddHadronicId(2214); - PHYSICS->mcConfig().AddHadronicId(2224); - PHYSICS->mcConfig().AddHadronicId(3101); - PHYSICS->mcConfig().AddHadronicId(3103); - PHYSICS->mcConfig().AddHadronicId(3112); - PHYSICS->mcConfig().AddHadronicId(3114); - PHYSICS->mcConfig().AddHadronicId(3122); - PHYSICS->mcConfig().AddHadronicId(3201); - PHYSICS->mcConfig().AddHadronicId(3203); - PHYSICS->mcConfig().AddHadronicId(3212); - PHYSICS->mcConfig().AddHadronicId(3214); - PHYSICS->mcConfig().AddHadronicId(3222); - PHYSICS->mcConfig().AddHadronicId(3224); - PHYSICS->mcConfig().AddHadronicId(3303); - PHYSICS->mcConfig().AddHadronicId(3312); - PHYSICS->mcConfig().AddHadronicId(3314); - PHYSICS->mcConfig().AddHadronicId(3322); - PHYSICS->mcConfig().AddHadronicId(3324); - PHYSICS->mcConfig().AddHadronicId(3334); - PHYSICS->mcConfig().AddHadronicId(4101); - PHYSICS->mcConfig().AddHadronicId(4103); - PHYSICS->mcConfig().AddHadronicId(4112); - PHYSICS->mcConfig().AddHadronicId(4114); - PHYSICS->mcConfig().AddHadronicId(4122); - PHYSICS->mcConfig().AddHadronicId(4132); - PHYSICS->mcConfig().AddHadronicId(4201); - PHYSICS->mcConfig().AddHadronicId(4203); - PHYSICS->mcConfig().AddHadronicId(4212); - PHYSICS->mcConfig().AddHadronicId(4214); - PHYSICS->mcConfig().AddHadronicId(4222); - PHYSICS->mcConfig().AddHadronicId(4224); - PHYSICS->mcConfig().AddHadronicId(4232); - PHYSICS->mcConfig().AddHadronicId(4301); - PHYSICS->mcConfig().AddHadronicId(4303); - PHYSICS->mcConfig().AddHadronicId(4312); - PHYSICS->mcConfig().AddHadronicId(4314); - PHYSICS->mcConfig().AddHadronicId(4322); - PHYSICS->mcConfig().AddHadronicId(4324); - PHYSICS->mcConfig().AddHadronicId(4332); - PHYSICS->mcConfig().AddHadronicId(4334); - PHYSICS->mcConfig().AddHadronicId(4403); - PHYSICS->mcConfig().AddHadronicId(4412); - PHYSICS->mcConfig().AddHadronicId(4414); - PHYSICS->mcConfig().AddHadronicId(4422); - PHYSICS->mcConfig().AddHadronicId(4424); - PHYSICS->mcConfig().AddHadronicId(4432); - PHYSICS->mcConfig().AddHadronicId(4434); - PHYSICS->mcConfig().AddHadronicId(4444); - PHYSICS->mcConfig().AddHadronicId(5101); - PHYSICS->mcConfig().AddHadronicId(5103); - PHYSICS->mcConfig().AddHadronicId(5112); - PHYSICS->mcConfig().AddHadronicId(5114); - PHYSICS->mcConfig().AddHadronicId(5122); - PHYSICS->mcConfig().AddHadronicId(5132); - PHYSICS->mcConfig().AddHadronicId(5142); - PHYSICS->mcConfig().AddHadronicId(5201); - PHYSICS->mcConfig().AddHadronicId(5203); - PHYSICS->mcConfig().AddHadronicId(5212); - PHYSICS->mcConfig().AddHadronicId(5214); - PHYSICS->mcConfig().AddHadronicId(5222); - PHYSICS->mcConfig().AddHadronicId(5224); - PHYSICS->mcConfig().AddHadronicId(5232); - PHYSICS->mcConfig().AddHadronicId(5242); - PHYSICS->mcConfig().AddHadronicId(5301); - PHYSICS->mcConfig().AddHadronicId(5303); - PHYSICS->mcConfig().AddHadronicId(5312); - PHYSICS->mcConfig().AddHadronicId(5314); - PHYSICS->mcConfig().AddHadronicId(5322); - PHYSICS->mcConfig().AddHadronicId(5324); - PHYSICS->mcConfig().AddHadronicId(5332); - PHYSICS->mcConfig().AddHadronicId(5334); - PHYSICS->mcConfig().AddHadronicId(5342); - PHYSICS->mcConfig().AddHadronicId(5401); - PHYSICS->mcConfig().AddHadronicId(5403); - PHYSICS->mcConfig().AddHadronicId(5412); - PHYSICS->mcConfig().AddHadronicId(5414); - PHYSICS->mcConfig().AddHadronicId(5422); - PHYSICS->mcConfig().AddHadronicId(5424); - PHYSICS->mcConfig().AddHadronicId(5432); - PHYSICS->mcConfig().AddHadronicId(5434); - PHYSICS->mcConfig().AddHadronicId(5442); - PHYSICS->mcConfig().AddHadronicId(5444); - PHYSICS->mcConfig().AddHadronicId(5503); - PHYSICS->mcConfig().AddHadronicId(5512); - PHYSICS->mcConfig().AddHadronicId(5514); - PHYSICS->mcConfig().AddHadronicId(5522); - PHYSICS->mcConfig().AddHadronicId(5524); - PHYSICS->mcConfig().AddHadronicId(5532); - PHYSICS->mcConfig().AddHadronicId(5534); - PHYSICS->mcConfig().AddHadronicId(5542); - PHYSICS->mcConfig().AddHadronicId(5544); - PHYSICS->mcConfig().AddHadronicId(5554); - PHYSICS->mcConfig().AddHadronicId(10111); - PHYSICS->mcConfig().AddHadronicId(10113); - PHYSICS->mcConfig().AddHadronicId(10211); - PHYSICS->mcConfig().AddHadronicId(10213); - PHYSICS->mcConfig().AddHadronicId(10221); - PHYSICS->mcConfig().AddHadronicId(10223); - PHYSICS->mcConfig().AddHadronicId(10311); - PHYSICS->mcConfig().AddHadronicId(10313); - PHYSICS->mcConfig().AddHadronicId(10321); - PHYSICS->mcConfig().AddHadronicId(10323); - PHYSICS->mcConfig().AddHadronicId(10331); - PHYSICS->mcConfig().AddHadronicId(10333); - PHYSICS->mcConfig().AddHadronicId(10411); - PHYSICS->mcConfig().AddHadronicId(10413); - PHYSICS->mcConfig().AddHadronicId(10421); - PHYSICS->mcConfig().AddHadronicId(10423); - PHYSICS->mcConfig().AddHadronicId(10431); - PHYSICS->mcConfig().AddHadronicId(10433); - PHYSICS->mcConfig().AddHadronicId(10441); - PHYSICS->mcConfig().AddHadronicId(10443); - PHYSICS->mcConfig().AddHadronicId(10511); - PHYSICS->mcConfig().AddHadronicId(10513); - PHYSICS->mcConfig().AddHadronicId(10521); - PHYSICS->mcConfig().AddHadronicId(10523); - PHYSICS->mcConfig().AddHadronicId(10531); - PHYSICS->mcConfig().AddHadronicId(10533); - PHYSICS->mcConfig().AddHadronicId(10541); - PHYSICS->mcConfig().AddHadronicId(10543); - PHYSICS->mcConfig().AddHadronicId(10551); - PHYSICS->mcConfig().AddHadronicId(10553); - PHYSICS->mcConfig().AddHadronicId(20113); - PHYSICS->mcConfig().AddHadronicId(20213); - PHYSICS->mcConfig().AddHadronicId(20223); - PHYSICS->mcConfig().AddHadronicId(20313); - PHYSICS->mcConfig().AddHadronicId(20323); - PHYSICS->mcConfig().AddHadronicId(20333); - PHYSICS->mcConfig().AddHadronicId(20413); - PHYSICS->mcConfig().AddHadronicId(20423); - PHYSICS->mcConfig().AddHadronicId(20433); - PHYSICS->mcConfig().AddHadronicId(20443); - PHYSICS->mcConfig().AddHadronicId(20513); - PHYSICS->mcConfig().AddHadronicId(20523); - PHYSICS->mcConfig().AddHadronicId(20533); - PHYSICS->mcConfig().AddHadronicId(20543); - PHYSICS->mcConfig().AddHadronicId(20553); - PHYSICS->mcConfig().AddHadronicId(100443); - PHYSICS->mcConfig().AddHadronicId(100553); - PHYSICS->mcConfig().AddHadronicId(9900440); - PHYSICS->mcConfig().AddHadronicId(9900441); - PHYSICS->mcConfig().AddHadronicId(9900443); - PHYSICS->mcConfig().AddHadronicId(9900551); - PHYSICS->mcConfig().AddHadronicId(9900553); - PHYSICS->mcConfig().AddHadronicId(9910441); - PHYSICS->mcConfig().AddHadronicId(9910551); - + // definition of the multiparticle "hadronic" + PHYSICS->mcConfig().AddHadronicId(-20543); + PHYSICS->mcConfig().AddHadronicId(-20533); + PHYSICS->mcConfig().AddHadronicId(-20523); + PHYSICS->mcConfig().AddHadronicId(-20513); + PHYSICS->mcConfig().AddHadronicId(-20433); + PHYSICS->mcConfig().AddHadronicId(-20423); + PHYSICS->mcConfig().AddHadronicId(-20413); + PHYSICS->mcConfig().AddHadronicId(-20323); + PHYSICS->mcConfig().AddHadronicId(-20313); + PHYSICS->mcConfig().AddHadronicId(-20213); + PHYSICS->mcConfig().AddHadronicId(-10543); + PHYSICS->mcConfig().AddHadronicId(-10541); + PHYSICS->mcConfig().AddHadronicId(-10533); + PHYSICS->mcConfig().AddHadronicId(-10531); + PHYSICS->mcConfig().AddHadronicId(-10523); + PHYSICS->mcConfig().AddHadronicId(-10521); + PHYSICS->mcConfig().AddHadronicId(-10513); + PHYSICS->mcConfig().AddHadronicId(-10511); + PHYSICS->mcConfig().AddHadronicId(-10433); + PHYSICS->mcConfig().AddHadronicId(-10431); + PHYSICS->mcConfig().AddHadronicId(-10423); + PHYSICS->mcConfig().AddHadronicId(-10421); + PHYSICS->mcConfig().AddHadronicId(-10413); + PHYSICS->mcConfig().AddHadronicId(-10411); + PHYSICS->mcConfig().AddHadronicId(-10323); + PHYSICS->mcConfig().AddHadronicId(-10321); + PHYSICS->mcConfig().AddHadronicId(-10313); + PHYSICS->mcConfig().AddHadronicId(-10311); + PHYSICS->mcConfig().AddHadronicId(-10213); + PHYSICS->mcConfig().AddHadronicId(-10211); + PHYSICS->mcConfig().AddHadronicId(-5554); + PHYSICS->mcConfig().AddHadronicId(-5544); + PHYSICS->mcConfig().AddHadronicId(-5542); + PHYSICS->mcConfig().AddHadronicId(-5534); + PHYSICS->mcConfig().AddHadronicId(-5532); + PHYSICS->mcConfig().AddHadronicId(-5524); + PHYSICS->mcConfig().AddHadronicId(-5522); + PHYSICS->mcConfig().AddHadronicId(-5514); + PHYSICS->mcConfig().AddHadronicId(-5512); + PHYSICS->mcConfig().AddHadronicId(-5503); + PHYSICS->mcConfig().AddHadronicId(-5444); + PHYSICS->mcConfig().AddHadronicId(-5442); + PHYSICS->mcConfig().AddHadronicId(-5434); + PHYSICS->mcConfig().AddHadronicId(-5432); + PHYSICS->mcConfig().AddHadronicId(-5424); + PHYSICS->mcConfig().AddHadronicId(-5422); + PHYSICS->mcConfig().AddHadronicId(-5414); + PHYSICS->mcConfig().AddHadronicId(-5412); + PHYSICS->mcConfig().AddHadronicId(-5403); + PHYSICS->mcConfig().AddHadronicId(-5401); + PHYSICS->mcConfig().AddHadronicId(-5342); + PHYSICS->mcConfig().AddHadronicId(-5334); + PHYSICS->mcConfig().AddHadronicId(-5332); + PHYSICS->mcConfig().AddHadronicId(-5324); + PHYSICS->mcConfig().AddHadronicId(-5322); + PHYSICS->mcConfig().AddHadronicId(-5314); + PHYSICS->mcConfig().AddHadronicId(-5312); + PHYSICS->mcConfig().AddHadronicId(-5303); + PHYSICS->mcConfig().AddHadronicId(-5301); + PHYSICS->mcConfig().AddHadronicId(-5242); + PHYSICS->mcConfig().AddHadronicId(-5232); + PHYSICS->mcConfig().AddHadronicId(-5224); + PHYSICS->mcConfig().AddHadronicId(-5222); + PHYSICS->mcConfig().AddHadronicId(-5214); + PHYSICS->mcConfig().AddHadronicId(-5212); + PHYSICS->mcConfig().AddHadronicId(-5203); + PHYSICS->mcConfig().AddHadronicId(-5201); + PHYSICS->mcConfig().AddHadronicId(-5142); + PHYSICS->mcConfig().AddHadronicId(-5132); + PHYSICS->mcConfig().AddHadronicId(-5122); + PHYSICS->mcConfig().AddHadronicId(-5114); + PHYSICS->mcConfig().AddHadronicId(-5112); + PHYSICS->mcConfig().AddHadronicId(-5103); + PHYSICS->mcConfig().AddHadronicId(-5101); + PHYSICS->mcConfig().AddHadronicId(-4444); + PHYSICS->mcConfig().AddHadronicId(-4434); + PHYSICS->mcConfig().AddHadronicId(-4432); + PHYSICS->mcConfig().AddHadronicId(-4424); + PHYSICS->mcConfig().AddHadronicId(-4422); + PHYSICS->mcConfig().AddHadronicId(-4414); + PHYSICS->mcConfig().AddHadronicId(-4412); + PHYSICS->mcConfig().AddHadronicId(-4403); + PHYSICS->mcConfig().AddHadronicId(-4334); + PHYSICS->mcConfig().AddHadronicId(-4332); + PHYSICS->mcConfig().AddHadronicId(-4324); + PHYSICS->mcConfig().AddHadronicId(-4322); + PHYSICS->mcConfig().AddHadronicId(-4314); + PHYSICS->mcConfig().AddHadronicId(-4312); + PHYSICS->mcConfig().AddHadronicId(-4303); + PHYSICS->mcConfig().AddHadronicId(-4301); + PHYSICS->mcConfig().AddHadronicId(-4232); + PHYSICS->mcConfig().AddHadronicId(-4224); + PHYSICS->mcConfig().AddHadronicId(-4222); + PHYSICS->mcConfig().AddHadronicId(-4214); + PHYSICS->mcConfig().AddHadronicId(-4212); + PHYSICS->mcConfig().AddHadronicId(-4203); + PHYSICS->mcConfig().AddHadronicId(-4201); + PHYSICS->mcConfig().AddHadronicId(-4132); + PHYSICS->mcConfig().AddHadronicId(-4122); + PHYSICS->mcConfig().AddHadronicId(-4114); + PHYSICS->mcConfig().AddHadronicId(-4112); + PHYSICS->mcConfig().AddHadronicId(-4103); + PHYSICS->mcConfig().AddHadronicId(-4101); + PHYSICS->mcConfig().AddHadronicId(-3334); + PHYSICS->mcConfig().AddHadronicId(-3324); + PHYSICS->mcConfig().AddHadronicId(-3322); + PHYSICS->mcConfig().AddHadronicId(-3314); + PHYSICS->mcConfig().AddHadronicId(-3312); + PHYSICS->mcConfig().AddHadronicId(-3303); + PHYSICS->mcConfig().AddHadronicId(-3224); + PHYSICS->mcConfig().AddHadronicId(-3222); + PHYSICS->mcConfig().AddHadronicId(-3214); + PHYSICS->mcConfig().AddHadronicId(-3212); + PHYSICS->mcConfig().AddHadronicId(-3203); + PHYSICS->mcConfig().AddHadronicId(-3201); + PHYSICS->mcConfig().AddHadronicId(-3122); + PHYSICS->mcConfig().AddHadronicId(-3114); + PHYSICS->mcConfig().AddHadronicId(-3112); + PHYSICS->mcConfig().AddHadronicId(-3103); + PHYSICS->mcConfig().AddHadronicId(-3101); + PHYSICS->mcConfig().AddHadronicId(-2224); + PHYSICS->mcConfig().AddHadronicId(-2214); + PHYSICS->mcConfig().AddHadronicId(-2212); + PHYSICS->mcConfig().AddHadronicId(-2203); + PHYSICS->mcConfig().AddHadronicId(-2114); + PHYSICS->mcConfig().AddHadronicId(-2112); + PHYSICS->mcConfig().AddHadronicId(-2103); + PHYSICS->mcConfig().AddHadronicId(-2101); + PHYSICS->mcConfig().AddHadronicId(-1114); + PHYSICS->mcConfig().AddHadronicId(-1103); + PHYSICS->mcConfig().AddHadronicId(-545); + PHYSICS->mcConfig().AddHadronicId(-543); + PHYSICS->mcConfig().AddHadronicId(-541); + PHYSICS->mcConfig().AddHadronicId(-535); + PHYSICS->mcConfig().AddHadronicId(-533); + PHYSICS->mcConfig().AddHadronicId(-531); + PHYSICS->mcConfig().AddHadronicId(-525); + PHYSICS->mcConfig().AddHadronicId(-523); + PHYSICS->mcConfig().AddHadronicId(-521); + PHYSICS->mcConfig().AddHadronicId(-515); + PHYSICS->mcConfig().AddHadronicId(-513); + PHYSICS->mcConfig().AddHadronicId(-511); + PHYSICS->mcConfig().AddHadronicId(-435); + PHYSICS->mcConfig().AddHadronicId(-433); + PHYSICS->mcConfig().AddHadronicId(-431); + PHYSICS->mcConfig().AddHadronicId(-425); + PHYSICS->mcConfig().AddHadronicId(-423); + PHYSICS->mcConfig().AddHadronicId(-421); + PHYSICS->mcConfig().AddHadronicId(-415); + PHYSICS->mcConfig().AddHadronicId(-413); + PHYSICS->mcConfig().AddHadronicId(-411); + PHYSICS->mcConfig().AddHadronicId(-325); + PHYSICS->mcConfig().AddHadronicId(-323); + PHYSICS->mcConfig().AddHadronicId(-321); + PHYSICS->mcConfig().AddHadronicId(-315); + PHYSICS->mcConfig().AddHadronicId(-313); + PHYSICS->mcConfig().AddHadronicId(-311); + PHYSICS->mcConfig().AddHadronicId(-215); + PHYSICS->mcConfig().AddHadronicId(-213); + PHYSICS->mcConfig().AddHadronicId(-211); + PHYSICS->mcConfig().AddHadronicId(111); + PHYSICS->mcConfig().AddHadronicId(113); + PHYSICS->mcConfig().AddHadronicId(115); + PHYSICS->mcConfig().AddHadronicId(130); + PHYSICS->mcConfig().AddHadronicId(211); + PHYSICS->mcConfig().AddHadronicId(213); + PHYSICS->mcConfig().AddHadronicId(215); + PHYSICS->mcConfig().AddHadronicId(221); + PHYSICS->mcConfig().AddHadronicId(223); + PHYSICS->mcConfig().AddHadronicId(225); + PHYSICS->mcConfig().AddHadronicId(310); + PHYSICS->mcConfig().AddHadronicId(311); + PHYSICS->mcConfig().AddHadronicId(313); + PHYSICS->mcConfig().AddHadronicId(315); + PHYSICS->mcConfig().AddHadronicId(321); + PHYSICS->mcConfig().AddHadronicId(323); + PHYSICS->mcConfig().AddHadronicId(325); + PHYSICS->mcConfig().AddHadronicId(331); + PHYSICS->mcConfig().AddHadronicId(333); + PHYSICS->mcConfig().AddHadronicId(335); + PHYSICS->mcConfig().AddHadronicId(411); + PHYSICS->mcConfig().AddHadronicId(413); + PHYSICS->mcConfig().AddHadronicId(415); + PHYSICS->mcConfig().AddHadronicId(421); + PHYSICS->mcConfig().AddHadronicId(423); + PHYSICS->mcConfig().AddHadronicId(425); + PHYSICS->mcConfig().AddHadronicId(431); + PHYSICS->mcConfig().AddHadronicId(433); + PHYSICS->mcConfig().AddHadronicId(435); + PHYSICS->mcConfig().AddHadronicId(441); + PHYSICS->mcConfig().AddHadronicId(443); + PHYSICS->mcConfig().AddHadronicId(445); + PHYSICS->mcConfig().AddHadronicId(511); + PHYSICS->mcConfig().AddHadronicId(513); + PHYSICS->mcConfig().AddHadronicId(515); + PHYSICS->mcConfig().AddHadronicId(521); + PHYSICS->mcConfig().AddHadronicId(523); + PHYSICS->mcConfig().AddHadronicId(525); + PHYSICS->mcConfig().AddHadronicId(531); + PHYSICS->mcConfig().AddHadronicId(533); + PHYSICS->mcConfig().AddHadronicId(535); + PHYSICS->mcConfig().AddHadronicId(541); + PHYSICS->mcConfig().AddHadronicId(543); + PHYSICS->mcConfig().AddHadronicId(545); + PHYSICS->mcConfig().AddHadronicId(551); + PHYSICS->mcConfig().AddHadronicId(553); + PHYSICS->mcConfig().AddHadronicId(555); + PHYSICS->mcConfig().AddHadronicId(1103); + PHYSICS->mcConfig().AddHadronicId(1114); + PHYSICS->mcConfig().AddHadronicId(2101); + PHYSICS->mcConfig().AddHadronicId(2103); + PHYSICS->mcConfig().AddHadronicId(2112); + PHYSICS->mcConfig().AddHadronicId(2114); + PHYSICS->mcConfig().AddHadronicId(2203); + PHYSICS->mcConfig().AddHadronicId(2212); + PHYSICS->mcConfig().AddHadronicId(2214); + PHYSICS->mcConfig().AddHadronicId(2224); + PHYSICS->mcConfig().AddHadronicId(3101); + PHYSICS->mcConfig().AddHadronicId(3103); + PHYSICS->mcConfig().AddHadronicId(3112); + PHYSICS->mcConfig().AddHadronicId(3114); + PHYSICS->mcConfig().AddHadronicId(3122); + PHYSICS->mcConfig().AddHadronicId(3201); + PHYSICS->mcConfig().AddHadronicId(3203); + PHYSICS->mcConfig().AddHadronicId(3212); + PHYSICS->mcConfig().AddHadronicId(3214); + PHYSICS->mcConfig().AddHadronicId(3222); + PHYSICS->mcConfig().AddHadronicId(3224); + PHYSICS->mcConfig().AddHadronicId(3303); + PHYSICS->mcConfig().AddHadronicId(3312); + PHYSICS->mcConfig().AddHadronicId(3314); + PHYSICS->mcConfig().AddHadronicId(3322); + PHYSICS->mcConfig().AddHadronicId(3324); + PHYSICS->mcConfig().AddHadronicId(3334); + PHYSICS->mcConfig().AddHadronicId(4101); + PHYSICS->mcConfig().AddHadronicId(4103); + PHYSICS->mcConfig().AddHadronicId(4112); + PHYSICS->mcConfig().AddHadronicId(4114); + PHYSICS->mcConfig().AddHadronicId(4122); + PHYSICS->mcConfig().AddHadronicId(4132); + PHYSICS->mcConfig().AddHadronicId(4201); + PHYSICS->mcConfig().AddHadronicId(4203); + PHYSICS->mcConfig().AddHadronicId(4212); + PHYSICS->mcConfig().AddHadronicId(4214); + PHYSICS->mcConfig().AddHadronicId(4222); + PHYSICS->mcConfig().AddHadronicId(4224); + PHYSICS->mcConfig().AddHadronicId(4232); + PHYSICS->mcConfig().AddHadronicId(4301); + PHYSICS->mcConfig().AddHadronicId(4303); + PHYSICS->mcConfig().AddHadronicId(4312); + PHYSICS->mcConfig().AddHadronicId(4314); + PHYSICS->mcConfig().AddHadronicId(4322); + PHYSICS->mcConfig().AddHadronicId(4324); + PHYSICS->mcConfig().AddHadronicId(4332); + PHYSICS->mcConfig().AddHadronicId(4334); + PHYSICS->mcConfig().AddHadronicId(4403); + PHYSICS->mcConfig().AddHadronicId(4412); + PHYSICS->mcConfig().AddHadronicId(4414); + PHYSICS->mcConfig().AddHadronicId(4422); + PHYSICS->mcConfig().AddHadronicId(4424); + PHYSICS->mcConfig().AddHadronicId(4432); + PHYSICS->mcConfig().AddHadronicId(4434); + PHYSICS->mcConfig().AddHadronicId(4444); + PHYSICS->mcConfig().AddHadronicId(5101); + PHYSICS->mcConfig().AddHadronicId(5103); + PHYSICS->mcConfig().AddHadronicId(5112); + PHYSICS->mcConfig().AddHadronicId(5114); + PHYSICS->mcConfig().AddHadronicId(5122); + PHYSICS->mcConfig().AddHadronicId(5132); + PHYSICS->mcConfig().AddHadronicId(5142); + PHYSICS->mcConfig().AddHadronicId(5201); + PHYSICS->mcConfig().AddHadronicId(5203); + PHYSICS->mcConfig().AddHadronicId(5212); + PHYSICS->mcConfig().AddHadronicId(5214); + PHYSICS->mcConfig().AddHadronicId(5222); + PHYSICS->mcConfig().AddHadronicId(5224); + PHYSICS->mcConfig().AddHadronicId(5232); + PHYSICS->mcConfig().AddHadronicId(5242); + PHYSICS->mcConfig().AddHadronicId(5301); + PHYSICS->mcConfig().AddHadronicId(5303); + PHYSICS->mcConfig().AddHadronicId(5312); + PHYSICS->mcConfig().AddHadronicId(5314); + PHYSICS->mcConfig().AddHadronicId(5322); + PHYSICS->mcConfig().AddHadronicId(5324); + PHYSICS->mcConfig().AddHadronicId(5332); + PHYSICS->mcConfig().AddHadronicId(5334); + PHYSICS->mcConfig().AddHadronicId(5342); + PHYSICS->mcConfig().AddHadronicId(5401); + PHYSICS->mcConfig().AddHadronicId(5403); + PHYSICS->mcConfig().AddHadronicId(5412); + PHYSICS->mcConfig().AddHadronicId(5414); + PHYSICS->mcConfig().AddHadronicId(5422); + PHYSICS->mcConfig().AddHadronicId(5424); + PHYSICS->mcConfig().AddHadronicId(5432); + PHYSICS->mcConfig().AddHadronicId(5434); + PHYSICS->mcConfig().AddHadronicId(5442); + PHYSICS->mcConfig().AddHadronicId(5444); + PHYSICS->mcConfig().AddHadronicId(5503); + PHYSICS->mcConfig().AddHadronicId(5512); + PHYSICS->mcConfig().AddHadronicId(5514); + PHYSICS->mcConfig().AddHadronicId(5522); + PHYSICS->mcConfig().AddHadronicId(5524); + PHYSICS->mcConfig().AddHadronicId(5532); + PHYSICS->mcConfig().AddHadronicId(5534); + PHYSICS->mcConfig().AddHadronicId(5542); + PHYSICS->mcConfig().AddHadronicId(5544); + PHYSICS->mcConfig().AddHadronicId(5554); + PHYSICS->mcConfig().AddHadronicId(10111); + PHYSICS->mcConfig().AddHadronicId(10113); + PHYSICS->mcConfig().AddHadronicId(10211); + PHYSICS->mcConfig().AddHadronicId(10213); + PHYSICS->mcConfig().AddHadronicId(10221); + PHYSICS->mcConfig().AddHadronicId(10223); + PHYSICS->mcConfig().AddHadronicId(10311); + PHYSICS->mcConfig().AddHadronicId(10313); + PHYSICS->mcConfig().AddHadronicId(10321); + PHYSICS->mcConfig().AddHadronicId(10323); + PHYSICS->mcConfig().AddHadronicId(10331); + PHYSICS->mcConfig().AddHadronicId(10333); + PHYSICS->mcConfig().AddHadronicId(10411); + PHYSICS->mcConfig().AddHadronicId(10413); + PHYSICS->mcConfig().AddHadronicId(10421); + PHYSICS->mcConfig().AddHadronicId(10423); + PHYSICS->mcConfig().AddHadronicId(10431); + PHYSICS->mcConfig().AddHadronicId(10433); + PHYSICS->mcConfig().AddHadronicId(10441); + PHYSICS->mcConfig().AddHadronicId(10443); + PHYSICS->mcConfig().AddHadronicId(10511); + PHYSICS->mcConfig().AddHadronicId(10513); + PHYSICS->mcConfig().AddHadronicId(10521); + PHYSICS->mcConfig().AddHadronicId(10523); + PHYSICS->mcConfig().AddHadronicId(10531); + PHYSICS->mcConfig().AddHadronicId(10533); + PHYSICS->mcConfig().AddHadronicId(10541); + PHYSICS->mcConfig().AddHadronicId(10543); + PHYSICS->mcConfig().AddHadronicId(10551); + PHYSICS->mcConfig().AddHadronicId(10553); + PHYSICS->mcConfig().AddHadronicId(20113); + PHYSICS->mcConfig().AddHadronicId(20213); + PHYSICS->mcConfig().AddHadronicId(20223); + PHYSICS->mcConfig().AddHadronicId(20313); + PHYSICS->mcConfig().AddHadronicId(20323); + PHYSICS->mcConfig().AddHadronicId(20333); + PHYSICS->mcConfig().AddHadronicId(20413); + PHYSICS->mcConfig().AddHadronicId(20423); + PHYSICS->mcConfig().AddHadronicId(20433); + PHYSICS->mcConfig().AddHadronicId(20443); + PHYSICS->mcConfig().AddHadronicId(20513); + PHYSICS->mcConfig().AddHadronicId(20523); + PHYSICS->mcConfig().AddHadronicId(20533); + PHYSICS->mcConfig().AddHadronicId(20543); + PHYSICS->mcConfig().AddHadronicId(20553); + PHYSICS->mcConfig().AddHadronicId(100443); + PHYSICS->mcConfig().AddHadronicId(100553); + PHYSICS->mcConfig().AddHadronicId(9900440); + PHYSICS->mcConfig().AddHadronicId(9900441); + PHYSICS->mcConfig().AddHadronicId(9900443); + PHYSICS->mcConfig().AddHadronicId(9900551); + PHYSICS->mcConfig().AddHadronicId(9900553); + PHYSICS->mcConfig().AddHadronicId(9910441); + PHYSICS->mcConfig().AddHadronicId(9910551); } void SampleAnalyzer::AddDefaultInvisible() { - // definition of the multiparticle "invisible" - PHYSICS->mcConfig().AddInvisibleId(-16); - PHYSICS->mcConfig().AddInvisibleId(-14); - PHYSICS->mcConfig().AddInvisibleId(-12); - PHYSICS->mcConfig().AddInvisibleId(12); - PHYSICS->mcConfig().AddInvisibleId(14); - PHYSICS->mcConfig().AddInvisibleId(16); - PHYSICS->mcConfig().AddInvisibleId(1000022); - PHYSICS->mcConfig().AddInvisibleId(1000039); + // definition of the multiparticle "invisible" + PHYSICS->mcConfig().AddInvisibleId(-16); + PHYSICS->mcConfig().AddInvisibleId(-14); + PHYSICS->mcConfig().AddInvisibleId(-12); + PHYSICS->mcConfig().AddInvisibleId(12); + PHYSICS->mcConfig().AddInvisibleId(14); + PHYSICS->mcConfig().AddInvisibleId(16); + PHYSICS->mcConfig().AddInvisibleId(1000022); + PHYSICS->mcConfig().AddInvisibleId(1000039); } \ No newline at end of file diff --git a/tools/SampleAnalyzer/Process/Core/xdr_istream.cpp b/tools/SampleAnalyzer/Process/Core/xdr_istream.cpp index 45e3d6bc..c1a734a0 100644 --- a/tools/SampleAnalyzer/Process/Core/xdr_istream.cpp +++ b/tools/SampleAnalyzer/Process/Core/xdr_istream.cpp @@ -50,8 +50,8 @@ xdr_istream& xdr_istream::operator>>(std::string &s) MAchar* dummy = new MAchar[pad]; sb_->sgetn(dummy,pad); - delete line; - delete dummy; + delete[] line; + delete[] dummy; return *this; } diff --git a/tools/SampleAnalyzer/Process/JetClustering/JetClusterer.cpp b/tools/SampleAnalyzer/Process/JetClustering/JetClusterer.cpp index 5858ccf4..1b72b9e5 100644 --- a/tools/SampleAnalyzer/Process/JetClustering/JetClusterer.cpp +++ b/tools/SampleAnalyzer/Process/JetClustering/JetClusterer.cpp @@ -2,505 +2,1008 @@ // // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // SampleAnalyzer headers #include "SampleAnalyzer/Process/JetClustering/JetClusterer.h" #include "SampleAnalyzer/Commons/Service/LoopService.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" #include "SampleAnalyzer/Commons/Service/ConvertService.h" #include "SampleAnalyzer/Commons/Service/PDGService.h" -#include "SampleAnalyzer/Process/JetClustering/NullSmearer.h" - - -using namespace MA5; - -// ----------------------------------------------------------------------------- -// Initialize -// ----------------------------------------------------------------------------- -MAbool JetClusterer::Initialize(const std::map& options) +#include "SampleAnalyzer/Commons/Base/ClusterAlgoBase.h" +#include "SampleAnalyzer/Commons/Service/Physics.h" + +#ifdef MA5_FASTJET_MODE +#include "SampleAnalyzer/Interfaces/substructure/VariableR.h" +#include "SampleAnalyzer/Interfaces/fastjet/ClusterAlgoStandard.h" +#include "SampleAnalyzer/Interfaces/fastjet/ClusterAlgoSISCone.h" +#include "SampleAnalyzer/Interfaces/fastjet/ClusterAlgoCDFMidpoint.h" +#include "SampleAnalyzer/Interfaces/fastjet/ClusterAlgoCDFJetClu.h" +#include "SampleAnalyzer/Interfaces/fastjet/ClusterAlgoGridJet.h" +#endif + +namespace MA5 { - // algo defined ? - if (algo_==0) return false; - - // configure tagger - myBtagger_ = new bTagger(); - myCtagger_ = new cTagger(); - myTautagger_ = new TauTagger(); - mySmearer_ = new NullSmearer(); - mySmearer_->Initialize(true); - - // Loop over options - for (std::map::const_iterator - it=options.begin();it!=options.end();it++) - { - std::string key = ClusterAlgoBase::Lower(it->first); - MAbool result=false; - - // exclusive_id - if (key=="exclusive_id") - { - MAint32 tmp=0; - std::stringstream str; - str << it->second; - str >> tmp; - try - { - if (tmp==1) ExclusiveId_=true; - else if (tmp==0) ExclusiveId_=false; - else throw EXCEPTION_WARNING("'exclusive_id' must be equal to 0 or 1. Using default value 'exclusive_id' = "+CONVERT->ToString(ExclusiveId_),"",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - result=true; - } - // b-tagging - else if (key.find("bjet_id.")==0) + /// Set isolation cones for tracks, e, mu, photon based on tower objects + template + void SetConeRadius( + std::vector cone_radius, std::vector &objects, MCParticleFormat part, MAbool addself = false) { - result=myBtagger_->SetParameter(key.substr(8),it->second,"bjet_id."); + for (MAuint32 iR = 0; iR < cone_radius.size(); iR++) + { + for (MAuint32 i = 0; i < objects.size(); i++) + { + IsolationConeType *current_isocone = objects[i].GetIsolCone(cone_radius[iR]); + if (objects[i].dr(part.momentum()) < cone_radius[iR]) + { + current_isocone->addsumPT(part.pt()); + current_isocone->addSumET(part.et()); + if (addself) + { + current_isocone->setSelfPT(objects[i].pt()); + current_isocone->setSelfET(objects[i].et()); + } + } + } + } } - // c-tagging - // else if (key.find("cjet_id.")==0) - // { - // result=myCtagger_->SetParameter(key.substr(8),it->second,"cjet_id."); - // } - - // tau-tagging - else if (key.find("tau_id.")==0) + /// Constructor + JetClusterer::JetClusterer(ClusterAlgoBase *algo) { - result=myTautagger_->SetParameter(key.substr(7),it->second,"tau_id."); + // Initializing tagger + algo_ = algo; +#ifdef MA5_FASTJET_MODE + cluster_collection_.clear(); + substructure_collection_.clear(); +#endif + mySmearer_ = 0; + myTagger_ = 0; + myTaggerOptions_ = 0; + ExclusiveId_ = false; + JetID_ = "Ma5Jet"; + isocone_track_radius_.clear(); + isocone_electron_radius_.clear(); + isocone_muon_radius_.clear(); + isocone_photon_radius_.clear(); } - // clustering algo - else if (key.find("cluster.")==0) + /// Destructor + JetClusterer::~JetClusterer() { - result=algo_->SetParameter(key.substr(8),it->second); + if (algo_ != 0) + delete algo_; + if (mySmearer_ != 0) + delete mySmearer_; + if (myTagger_ != 0) + delete myTagger_; + if (myTaggerOptions_ != 0) + delete myTaggerOptions_; +#ifdef MA5_FASTJET_MODE + for (auto &col : cluster_collection_) + if (col.second != 0) + delete col.second; + for (auto &col : substructure_collection_) + if (col.second != 0) + delete col.second; +#endif } - // Isolation cone radius for tracker - else if (key.find("isolation")==0) + /// Accessor to the jet clusterer name + std::string JetClusterer::GetName() { - result=algo_->SetParameter(key,it->second); + if (algo_ == 0) + return "NotDefined"; + else + return algo_->GetName(); } - // Other - try - { - if (!result) throw EXCEPTION_WARNING("Parameter = "+key+" unknown. It will be skipped.","",0); - } - catch(const std::exception& e) - { - MANAGE_EXCEPTION(e); - } + /// Accessor to the tagger parameters + void JetClusterer::TaggerParameters() { myTagger_->PrintParam(); } - } + /// Print parameters + void JetClusterer::PrintParam() { algo_->PrintParam(); } - // configure algo - algo_->Initialize(); + /// Accessor to the jet clusterer parameters + std::string JetClusterer::GetParameters() { return algo_->GetParameters(); } + // ----------------------------------------------------------------------------- + // Initialize + // ----------------------------------------------------------------------------- + MAbool JetClusterer::Initialize(const std::map &options) + { + // algo defined ? + if (algo_ == 0) + return false; + + // configure tagger + mySmearer_ = new SmearerBase(); + myTagger_ = new SFSTaggerBase(); + myTaggerOptions_ = new SFSTaggerBaseOptions(); + mySmearer_->Initialize(true); + myTagger_->Initialize(); + + /// Loop ower options + for (const auto &opt : options) + { + std::string key = ClusterAlgoBase::Lower(opt.first); + MAbool result = false; - return true; -} + /// Initialize exclusive algorithm for jet clustering + if (key == "exclusive_id") + { + MAint32 tmp = 0; + std::stringstream str; + str << opt.second; + str >> tmp; + try + { + if (tmp == 1) + ExclusiveId_ = true; + else if (tmp == 0) + ExclusiveId_ = false; + else + throw EXCEPTION_WARNING( + "'exclusive_id' must be equal to 0 or 1. Using default value 'exclusive_id' = " + CONVERT->ToString(ExclusiveId_), "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + result = true; + } + /// B tagging options + else if (key.find("bjet_id.") == 0 || key.find("cjet_id.") == 0 || key.find("tau_id.") == 0) + { + /// Turn the input value to float + MAfloat32 tmp = 0; + std::stringstream str; + str << opt.second; + str >> tmp; + + /// Is bjet run via exclusive algorithm + if (key == "bjet_id.exclusive") + { + try + { + if (tmp == 1.) + myTaggerOptions_->btag_exclusive = true; + else if (tmp == 0.) + myTaggerOptions_->btag_exclusive = false; + else + throw EXCEPTION_WARNING( + "'bjet_id.exclusive' must be equal to 0 or 1. Using default value 'bjet_id.exclusive' = " + CONVERT->ToString(myTaggerOptions_->btag_exclusive), "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + /// What is the bjet matching DR + else if (key == "bjet_id.matching_dr") + myTaggerOptions_->btag_matching_deltaR = tmp; + /// Is cjet run via exclusive algorithm + else if (key == "cjet_id.exclusive") + { + try + { + if (tmp == 1.) + myTaggerOptions_->ctag_exclusive = true; + else if (tmp == 0.) + myTaggerOptions_->ctag_exclusive = false; + else + throw EXCEPTION_WARNING( + "'cjet_id.exclusive' must be equal to 0 or 1. Using default value 'cjet_id.exclusive' = " + CONVERT->ToString(myTaggerOptions_->ctag_exclusive), "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + /// What is the cjet matching DR + else if (key == "cjet_id.matching_dr") + myTaggerOptions_->ctag_matching_deltaR = tmp; + + /// Is CJet tagging enabled + else if (key == "cjet_id.enable_ctagging") + { + try + { + if (tmp == 1.) + myTaggerOptions_->enable_ctagging = true; + else if (tmp == 0.) + myTaggerOptions_->enable_ctagging = false; + else + throw EXCEPTION_WARNING( + "'cjet_id.enable_ctagging' must be equal to 0 or 1. Using default " + "value 'cjet_id.enable_ctagging' = " + + CONVERT->ToString(myTaggerOptions_->enable_ctagging), + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + /// Is taujet run via exclusive algorithm + else if (key == "tau_id.exclusive") + { + try + { + if (tmp == 1.) + myTaggerOptions_->tautag_exclusive = true; + else if (tmp == 0.) + myTaggerOptions_->tautag_exclusive = false; + else + throw EXCEPTION_WARNING( + "'cjet_id.exclusive' must be equal to 0 or 1. Using default value 'cjet_id.exclusive' = " + CONVERT->ToString(myTaggerOptions_->ctag_exclusive), "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + else if (key == "tau_id.matching_dr") + myTaggerOptions_->tautag_matching_deltaR = tmp; + else if (key == "tau_id.reconstruction_method") + { + try + { + if (tmp == 1.) + myTaggerOptions_->tautag_jetbased = true; + else if (tmp == 0.) + myTaggerOptions_->tautag_jetbased = false; + else + throw EXCEPTION_WARNING( + "Hadronic tau tagging has only two options 0 corresponds to hadron-based tagging algorithm " + "and 1 corresponds to jet-based tagging algorithm. Default, hadron-based, " + "algorithm will be used", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + myTaggerOptions_->tautag_jetbased = false; + } + } + else + { + try + { + throw EXCEPTION_WARNING("Parameter = " + key + " unknown. It will be skipped.", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + result = true; + } + /// clustering algo + else if (key.find("cluster.") == 0) + result = algo_->SetParameter(key.substr(8), opt.second); + /// Primary Jet ID + else if (key == "jetid") + { + JetID_ = opt.second; + result = true; + } + /// Isolation cone radius for tracker + else if (key.find("isolation") == 0) + { + std::stringstream str(opt.second); + for (MAfloat64 tmp; str >> tmp;) + { + if (tmp > 0. && key.substr(10) == "track.radius") + isocone_track_radius_.push_back(tmp); + if (tmp > 0. && key.substr(10) == "electron.radius") + isocone_electron_radius_.push_back(tmp); + if (tmp > 0. && key.substr(10) == "muon.radius") + isocone_muon_radius_.push_back(tmp); + if (tmp > 0. && key.substr(10) == "photon.radius") + isocone_photon_radius_.push_back(tmp); + if (str.peek() == ',' || str.peek() == ' ') + str.ignore(); + } + result = true; + } + /// Other + try + { + if (!result) + throw EXCEPTION_WARNING("Parameter = " + key + " unknown. It will be skipped.", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + /// configure algo + algo_->Initialize(); + /// Configure Tagger + myTagger_->SetOptions(*myTaggerOptions_); -// ----------------------------------------------------------------------------- -// Finalize -// ----------------------------------------------------------------------------- -void JetClusterer::Finalize() -{ - if (algo_!=0) delete algo_; - if (myBtagger_!=0) delete myBtagger_; - if (myCtagger_!=0) delete myCtagger_; - if (myTautagger_!=0) delete myTautagger_; - if (mySmearer_!=0) delete mySmearer_; -} - - -// ----------------------------------------------------------------------------- -// GetFinalState -// ----------------------------------------------------------------------------- -void JetClusterer::GetFinalState(const MCParticleFormat* part, std::set& finalstates) -{ - for (MAuint32 i=0; idaughters().size(); i++) - { - if (PHYSICS->Id->IsFinalState(part->daughters()[i])) finalstates.insert(part->daughters()[i]); - else return GetFinalState(part->daughters()[i],finalstates); - } -} - - -// ----------------------------------------------------------------------------- -// IsLast -// ----------------------------------------------------------------------------- -MAbool JetClusterer::IsLast(const MCParticleFormat* part, EventFormat& myEvent) -{ - for (MAuint32 i=0; idaughters().size(); i++) - { - if (part->daughters()[i]->pdgid()==part->pdgid()) return false; - } - return true; -} - - -// ----------------------------------------------------------------------------- -// Sorting the reco objects (necessary after smearing) -// ----------------------------------------------------------------------------- -MAbool sort_by_leptonPT(RecLeptonFormat const & a, RecLeptonFormat const & b) { return a.pt() < b.pt(); }; -MAbool sort_by_photonPT(RecPhotonFormat const & a, RecPhotonFormat const & b) { return a.pt() < b.pt(); }; -MAbool sort_by_tauPT(RecTauFormat const & a, RecTauFormat const & b) { return a.pt() < b.pt(); }; - -// ----------------------------------------------------------------------------- -// Execute -// ----------------------------------------------------------------------------- -MAbool JetClusterer::Execute(SampleFormat& mySample, EventFormat& myEvent) -{ - // Safety - if (mySample.mc()==0 || myEvent.mc()==0) return false; - if (mySample.rec()==0) mySample.InitializeRec(); - if (myEvent.rec() ==0) myEvent.InitializeRec(); + return true; + } - /// Set length unit - mySmearer_->SetLengthUnit(mySample.mc()->LengthUnit()); + // ----------------------------------------------------------------------------- + // Finalize + // ----------------------------------------------------------------------------- + void JetClusterer::Finalize() + { + if (algo_ != 0) + delete algo_; + if (mySmearer_ != 0) + delete mySmearer_; + if (myTaggerOptions_ != 0) + delete myTaggerOptions_; + if (myTagger_ != 0) + delete myTagger_; + } - // Reseting the reconstructed event - myEvent.rec()->Reset(); + // ----------------------------------------------------------------------------- + // GetFinalState + // ----------------------------------------------------------------------------- + void JetClusterer::GetFinalState(const MCParticleFormat *part, std::set &finalstates) + { + for (MAuint32 i = 0; i < part->daughters().size(); i++) + { + if (PHYSICS->Id->IsFinalState(part->daughters()[i])) + finalstates.insert(part->daughters()[i]); + else + return GetFinalState(part->daughters()[i], finalstates); + } + } - // Veto - std::vector vetos(myEvent.mc()->particles().size(),false); - std::set vetos2; + // ----------------------------------------------------------------------------- + // IsLast + // ----------------------------------------------------------------------------- + MAbool JetClusterer::IsLast(const MCParticleFormat *part, EventFormat &myEvent) + { + for (MAuint32 i = 0; i < part->daughters().size(); i++) + { + if (part->daughters()[i]->pdgid() == part->pdgid()) + return false; + } + return true; + } - // Filling the dataformat with electron/muon - for (MAuint32 i=0;iparticles().size();i++) - { - const MCParticleFormat& part = myEvent.mc()->particles()[i]; - MAuint32 absid = std::abs(part.pdgid()); + // ----------------------------------------------------------------------------- + // Execute + // ----------------------------------------------------------------------------- + MAbool JetClusterer::Execute(SampleFormat &mySample, EventFormat &myEvent) + { + // Safety + if (mySample.mc() == 0 || myEvent.mc() == 0) + return false; + if (mySample.rec() == 0) + mySample.InitializeRec(); + if (myEvent.rec() == 0) + myEvent.InitializeRec(); + + /// Set length unit + mySmearer_->SetLengthUnit(mySample.mc()->LengthUnit()); + + // Reseting the reconstructed event + myEvent.rec()->Reset(); + + // Veto + std::vector vetos(myEvent.mc()->particles().size(), false); + std::set vetos2; + + // shortcut for TET & THT + MAfloat64 &TET = myEvent.rec()->TET(); + // MAfloat64 & THT = myEvent.rec()->THT(); + RecParticleFormat *MET = &(myEvent.rec()->MET()); + RecParticleFormat *MHT = &(myEvent.rec()->MHT()); + + // Filling the dataformat with electron/muon + for (MAuint32 i = 0; i < myEvent.mc()->particles().size(); i++) + { + const MCParticleFormat &part = myEvent.mc()->particles()[i]; + MAuint32 absid = std::abs(part.pdgid()); - // Rejecting particle with a null pt (initial state ?) - if (part.pt()<1e-10) continue; + // Rejecting particle with a null pt (initial state ?) + if (part.pt() < 1e-10) + continue; - // Run particle propagator - if (mySmearer_->isPropagatorOn() && part.mothers().size()>0) - mySmearer_->ParticlePropagator(const_cast(&part)); + // Run particle propagator + if (mySmearer_->isPropagatorOn() && part.mothers().size() > 0) + mySmearer_->ParticlePropagator(const_cast(&part)); - // Set up tracks as charged FS particles OR charged interstate particles with nonzero ctau - if (PDG->IsCharged(part.pdgid()) && part.mothers().size()>0) - { - // Minimum tracking requirement is around 0.5 mm see ref. 1007.1988 - if (part.ctau() > 0. || PHYSICS->Id->IsFinalState(part)) + /// @attention delphes based analyses already has tracks + /// Set up tracks as charged FS particles OR charged interstate particles with nonzero ctau + if (PDG->IsCharged(part.pdgid()) && part.mothers().size() > 0 && algo_ != 0) + { + // Minimum tracking requirement is around 0.5 mm see ref. 1007.1988 + if (part.ctau() > 0. || PHYSICS->Id->IsFinalState(part)) + { + // Reminder: -1 is reserved for the tracks + MCParticleFormat smeared_track = mySmearer_->Execute(&part, -1); + if (smeared_track.pt() > 1e-5) + { + RecTrackFormat *track = myEvent.rec()->GetNewTrack(); + MALorentzVector trk_mom; + trk_mom.SetPtEtaPhiM(smeared_track.pt(), + smeared_track.eta(), + smeared_track.phi(), 0.0); + track->setMomentum(trk_mom); + track->setD0(smeared_track.d0()); + track->setDZ(smeared_track.dz()); + track->setD0Approx(smeared_track.d0_approx()); + track->setDZApprox(smeared_track.dz_approx()); + MAdouble64 ctau = PHYSICS->Id->IsFinalState(part) ? 0.0 : part.mothers()[0]->ctau(); + MALorentzVector new_vertex(part.mothers()[0]->decay_vertex().X(), + part.mothers()[0]->decay_vertex().Y(), + part.mothers()[0]->decay_vertex().Z(), ctau); + track->setProductionVertex(new_vertex); + track->setClosestApproach(smeared_track.closest_approach()); + track->setMc(&(part)); + track->SetCharge(PDG->GetCharge(part.pdgid(), false) / 3.); + } + } + } + + // Treating intermediate particles + if (PHYSICS->Id->IsInterState(part)) + { + // rejecting not interesting particles + if (absid != 5 && absid != 4 && absid != 15) + continue; + + // keeping the last particle with the same id in the decay chain + if (!IsLast(&part, myEvent)) + continue; + + // looking for b quarks + if (absid == 5) + { + MAbool found = false; + for (MAuint32 j = 0; j < myEvent.rec()->MCBquarks_.size(); j++) + { + if (myEvent.rec()->MCBquarks_[j] == &(part)) + { + found = true; + break; + } + } + if (!found) + myEvent.rec()->MCBquarks_.push_back(&(part)); + } + + /// looking for c quarks + else if (absid == 4) + { + MAbool found = false; + for (MAuint32 j = 0; j < myEvent.rec()->MCCquarks_.size(); j++) + { + if (myEvent.rec()->MCCquarks_[j] == &(part)) + { + found = true; + break; + } + } + if (!found) + myEvent.rec()->MCCquarks_.push_back(&(part)); + } + + /// looking for taus + else if (absid == 15) + { + // rejecting particle if coming from hadronization + if (LOOP->ComingFromHadronDecay(&part, mySample, myEvent.mc()->particles().size())) + continue; + + // Looking taus daughters id + MAbool leptonic = true; + MAbool muonic = false; + MAbool electronic = false; + for (MAuint32 j = 0; j < part.daughters().size(); j++) + { + MAuint32 pdgid = std::abs(part.daughters()[j]->pdgid()); + if (pdgid == 13) + muonic = true; + else if (pdgid == 11) + electronic = true; + else if (pdgid != 22 /*photons*/ && + !(pdgid >= 11 && pdgid <= 16) /*neutrinos*/) + leptonic = false; + } + if (!leptonic) + { + muonic = false; + electronic = false; + } + + // Saving taus decaying into muons (only one copy) + if (muonic) + { + MAbool found = false; + for (MAuint32 j = 0; j < myEvent.rec()->MCMuonicTaus_.size(); j++) + { + if (myEvent.rec()->MCMuonicTaus_[j] == &(part)) + { + found = true; + break; + } + } + if (!found) + myEvent.rec()->MCMuonicTaus_.push_back(&(part)); + } + else if (electronic) // Saving taus decaying into electrons (only one copy) + { + MAbool found = false; + for (MAuint32 j = 0; j < myEvent.rec()->MCElectronicTaus_.size(); j++) + { + if (myEvent.rec()->MCElectronicTaus_[j] == &(part)) + { + found = true; + break; + } + } + if (!found) + myEvent.rec()->MCElectronicTaus_.push_back(&(part)); + } + else // Saving taus decaying into hadrons (only copy) + { + MAbool found = false; + for (MAuint32 j = 0; j < myEvent.rec()->MCHadronicTaus_.size(); j++) + { + if (myEvent.rec()->MCHadronicTaus_[j] == &(part)) + { + found = true; + break; + } + } + if (!found) + { + // Saving the hadrons in MC container + myEvent.rec()->MCHadronicTaus_.push_back(&(part)); + + /// If tau tagging is jet based do not proceed + if (myTaggerOptions_->tautag_jetbased) + continue; + + // Smearing the hadronic taus + MCParticleFormat smeared = mySmearer_->Execute( + &part, static_cast(absid)); + // If smeared pt is zero, no need to count the particle but it still needs + // to be vetoed for jet clustering. + if (smeared.pt() > 1e-10) + { + // Creating reco hadronic taus + RecTauFormat *myTau = myEvent.rec()->GetNewTau(); + if (part.pdgid() > 0) + myTau->setCharge(-1); + else + myTau->setCharge(+1); + myTau->setMomentum(smeared.momentum()); + myTau->setD0(smeared.d0()); + myTau->setDZ(smeared.dz()); + myTau->setD0Approx(smeared.d0_approx()); + myTau->setDZApprox(smeared.dz_approx()); + myTau->setProductionVertex( + MALorentzVector(part.mothers()[0]->decay_vertex().X(), + part.mothers()[0]->decay_vertex().Y(), + part.mothers()[0]->decay_vertex().Z(), + 0.0)); + myTau->setClosestApproach(smeared.closest_approach()); + myTau->setMc(&part); + myTau->setDecayMode(PHYSICS->GetTauDecayMode(myTau->mc())); + if (myTau->DecayMode() <= 0) + myTau->setNtracks(0); // ERROR case + else if (myTau->DecayMode() == 7 || + myTau->DecayMode() == 9) + myTau->setNtracks(3); // 3-Prong + else + myTau->setNtracks(1); // 1-Prong + + /// Set MET and TET + if (ExclusiveId_) + { + (*MET) -= myTau->momentum(); + TET += myTau->pt(); + } + + } // (smeared.pt() < 1e-10) + + // Searching final state + GetFinalState(&part, vetos2); + } + } + } // if (absid==15) + } // if (PHYSICS->Id->IsInterState(part)) + + // Keeping only final states + else if (PHYSICS->Id->IsFinalState(part)) + { + // rejecting particle if coming from hadronization + if (!(ExclusiveId_ && LOOP->ComingFromHadronDecay(&part, mySample))) + { + // Muons + if (absid == 13) + { + vetos[i] = true; + + // Smearing its momentum + MCParticleFormat smeared = mySmearer_->Execute(&part, static_cast(absid)); + if (smeared.pt() > 1e-10) + { + RecLeptonFormat *current_muon = myEvent.rec()->GetNewMuon(); + current_muon->setMomentum(smeared.momentum()); + current_muon->setD0(smeared.d0()); + current_muon->setDZ(smeared.dz()); + current_muon->setD0Approx(smeared.d0_approx()); + current_muon->setDZApprox(smeared.dz_approx()); + current_muon->setProductionVertex(MALorentzVector(part.mothers()[0]->decay_vertex().X(), + part.mothers()[0]->decay_vertex().Y(), + part.mothers()[0]->decay_vertex().Z(), 0.0)); + current_muon->setClosestApproach(smeared.closest_approach()); + current_muon->setMc(&(part)); + if (part.pdgid() == 13) + current_muon->SetCharge(-1); + else + current_muon->SetCharge(+1); + + /// Set MET and TET + (*MET) -= current_muon->momentum(); + TET += current_muon->pt(); + } + } // (absid == 13) + // Electrons + else if (absid == 11) + { + vetos[i] = true; + + // Smearing the electron momentum + MCParticleFormat smeared = mySmearer_->Execute(&part, static_cast(absid)); + if (smeared.pt() > 1e-10) + { + RecLeptonFormat *elec = myEvent.rec()->GetNewElectron(); + elec->setMomentum(smeared.momentum()); + elec->setD0(smeared.d0()); + elec->setDZ(smeared.dz()); + elec->setD0Approx(smeared.d0_approx()); + elec->setDZApprox(smeared.dz_approx()); + elec->setProductionVertex(MALorentzVector(part.mothers()[0]->decay_vertex().X(), + part.mothers()[0]->decay_vertex().Y(), + part.mothers()[0]->decay_vertex().Z(), 0.0)); + elec->setClosestApproach(smeared.closest_approach()); + elec->setMc(&(part)); + if (part.pdgid() == 11) + elec->SetCharge(-1); + else + elec->SetCharge(+1); + + /// Set MET and TET + if (ExclusiveId_) + { + (*MET) -= elec->momentum(); + TET += elec->pt(); + } + } + } // if (absid==11) + // Photons + else if (absid == 22) + { + if (!LOOP->IrrelevantPhoton(&part, mySample)) + { + vetos[i] = true; + + // Smearing the photon momentum + MCParticleFormat smeared = mySmearer_->Execute(&part, static_cast(absid)); + if (smeared.pt() > 1e-10) + { + RecPhotonFormat *current_photon = myEvent.rec()->GetNewPhoton(); + current_photon->setMomentum(smeared.momentum()); + current_photon->setD0(smeared.d0()); + current_photon->setDZ(smeared.dz()); + current_photon->setD0Approx(smeared.d0_approx()); + current_photon->setDZApprox(smeared.dz_approx()); + current_photon->setProductionVertex(MALorentzVector(part.mothers()[0]->decay_vertex().X(), + part.mothers()[0]->decay_vertex().Y(), + part.mothers()[0]->decay_vertex().Z(), + 0.0)); + current_photon->setClosestApproach(smeared.closest_approach()); + current_photon->setMc(&(part)); + + /// Set MET and TET + if (ExclusiveId_) + { + (*MET) -= current_photon->momentum(); + TET += current_photon->pt(); + } + } // (smeared.pt() <= 1e-10) + } // (!LOOP->IrrelevantPhoton(&part,mySample)) + } // (absid==22 && !reject_hadronic) + } + + // Collect Hadrons for jet clustering... + + // Putting the good inputs into the containter + // Good inputs = - final state + // - visible + // - if exclusiveID=1: particles not vetoed + // - if exclusiveID=0: all particles except muons + if (PHYSICS->Id->IsInvisible(part) || algo_ == 0) + continue; + + // ExclusiveId mode + if (ExclusiveId_) + { + if (vetos[i]) + continue; + if (vetos2.find(&part) != vetos2.end()) + continue; + } + // NonExclusive Id mode + else if (std::abs(part.pdgid()) == 13) + continue; + + // Smearer module returns a smeared MCParticleFormat object + // Default: NullSmearer, that does nothing + // Reminder: 0 is reserved for the jet constituents + MCParticleFormat smeared = mySmearer_->Execute(&part, 0); + if (smeared.pt() <= 1e-10) + continue; + + // Filling good particle for clustering + myEvent.rec()->AddHadron(smeared, i); + + } // if (PHYSICS->Id->IsFinalState(part)) + } // for (MAuint32 i=0;iparticles().size();i++) + + // Set Primary Jet ID + myEvent.rec()->SetPrimaryJetID(JetID_); + // Launching the clustering + // -> Filling the collection: myEvent->rec()->jets() + algo_->Execute(mySample, myEvent, mySmearer_); + +#ifdef MA5_FASTJET_MODE + // Cluster additional jets separately. In order to save time Execute function + // saves hadron inputs into memory and that configuration is used for the rest + // of the jets. + for (auto &collection_item : cluster_collection_) + collection_item.second->Cluster(myEvent, collection_item.first); + for (auto &substructure : substructure_collection_) + substructure.second->Execute(myEvent, substructure.first); +#endif + + MET->momentum().SetPz(0.); + MET->momentum().SetE(MET->momentum().Pt()); + MHT->momentum().SetPz(0.); + MHT->momentum().SetE(MHT->momentum().Pt()); + + /// Execute tagger + myTagger_->Execute(myEvent); + + // Sorting the objects + std::sort(myEvent.rec()->electrons_.begin(), myEvent.rec()->electrons_.end(), + [](RecLeptonFormat const &lep1, RecLeptonFormat const &lep2) + { return lep1.pt() > lep2.pt(); }); + std::sort(myEvent.rec()->muons_.begin(), myEvent.rec()->muons_.end(), + [](RecLeptonFormat const &lep1, RecLeptonFormat const &lep2) + { return lep1.pt() > lep2.pt(); }); + std::sort(myEvent.rec()->taus_.begin(), myEvent.rec()->taus_.end(), + [](RecTauFormat const &ta1, RecTauFormat const &ta2) + { return ta1.pt() > ta2.pt(); }); + std::sort(myEvent.rec()->photons_.begin(), myEvent.rec()->photons_.end(), + [](RecPhotonFormat const &ph1, RecPhotonFormat const &ph2) + { return ph1.pt() > ph2.pt(); }); + std::sort(myEvent.rec()->jets().begin(), myEvent.rec()->jets().end(), + [](RecJetFormat &j1, RecJetFormat &j2) + { return j1.pt() > j2.pt(); }); + +#ifdef MA5_FASTJET_MODE + // Setup isolation cones + if (isocone_track_radius_.size() > 0 || isocone_electron_radius_.size() > 0 || + isocone_muon_radius_.size() > 0 || isocone_photon_radius_.size() > 0) { - // Reminder: -1 is reserved for the tracks - MCParticleFormat smeared_track = mySmearer_->Execute(&part, -1); - if (smeared_track.pt() > 1e-5) + for (auto &part : myEvent.rec()->cluster_inputs()) { - RecTrackFormat * track = myEvent.rec()->GetNewTrack(); - MALorentzVector trk_mom; - trk_mom.SetPtEtaPhiM(smeared_track.pt(), - smeared_track.eta(), - smeared_track.phi(),0.0); - track->setMomentum(trk_mom); - track->setD0(smeared_track.d0()); - track->setDZ(smeared_track.dz()); - track->setD0Approx(smeared_track.d0_approx()); - track->setDZApprox(smeared_track.dz_approx()); - MAdouble64 ctau = PHYSICS->Id->IsFinalState(part) ? 0.0 : part.mothers()[0]->ctau(); - MALorentzVector new_vertex(part.mothers()[0]->decay_vertex().X(), - part.mothers()[0]->decay_vertex().Y(), - part.mothers()[0]->decay_vertex().Z(), ctau); - track->setProductionVertex(new_vertex); - track->setClosestApproach(smeared_track.closest_approach()); - track->setMc(&(part)); - track->SetCharge(PDG->GetCharge(part.pdgid(), false) / 3.); + MCParticleFormat current_jet; + current_jet.momentum().SetPxPyPzE(part.px(), part.py(), part.pz(), part.e()); + // Set track isolation + // Isolation cone is applied to each particle that deposits energy in HCAL; + // all hadronic activity assumed to reach to HCAL + SetConeRadius(isocone_track_radius_, myEvent.rec()->tracks(), current_jet, false); + // Set Electron isolation + SetConeRadius(isocone_electron_radius_, myEvent.rec()->electrons(), current_jet, !ExclusiveId_); + // Set Muon isolation + SetConeRadius(isocone_muon_radius_, myEvent.rec()->muons(), current_jet, false); + // Set Photon isolation + SetConeRadius(isocone_photon_radius_, myEvent.rec()->photons(), current_jet, !ExclusiveId_); } } +#endif + + return true; } - // Treating intermediate particles - if (PHYSICS->Id->IsInterState(part)) + // Load additional Jets + MAbool JetClusterer::LoadJetConfiguration(std::map options) { - // rejecting not interesting particles - if (absid!=5 && absid!=4 && absid!=15) continue; - - // keeping the last particle with the same id in the decay chain - if (!IsLast(&part, myEvent)) continue; - - // looking for b quarks - if (absid==5) - { - MAbool found=false; - for (MAuint32 j=0;jMCBquarks_.size();j++) +#ifdef MA5_FASTJET_MODE + std::string new_jetid; + std::string algorithm; + if (options.find("algorithm") == options.end()) { - if (myEvent.rec()->MCBquarks_[j]==&(part)) - {found=true; break;} + ERROR << "Jet configuration needs to have `algorithm` option. Jet configuration will be ignored." << endmsg; + return true; } - if (!found) myEvent.rec()->MCBquarks_.push_back(&(part)); - } - - // looking for c quarks - else if (absid==4) - { - MAbool found=false; - for (MAuint32 j=0;jMCCquarks_.size();j++) + else + algorithm = options["algorithm"]; + if (options.find("JetID") == options.end()) { - if (myEvent.rec()->MCCquarks_[j]==&(part)) - {found=true; break;} + ERROR << "Jet configuration needs to have `JetID` option. Jet configuration will be ignored." << endmsg; + return true; } - if (!found) myEvent.rec()->MCCquarks_.push_back(&(part)); - } - - // looking for taus - else if (absid==15) - { - // rejecting particle if coming from hadronization - if (LOOP->ComingFromHadronDecay(&part,mySample,myEvent.mc()->particles().size())) continue; - - // Looking taus daughters id - MAbool leptonic = true; - MAbool muonic = false; - MAbool electronic = false; - for (MAuint32 j=0;jpdgid()); - if (pdgid==13) muonic=true; - else if (pdgid==11) electronic=true; - else if (pdgid!=22 /*photons*/ && - !(pdgid>=11 && pdgid<=16) /*neutrinos*/) - leptonic=false; + ERROR << "Jet ID " + options["JetID"] + + " already exists. Jet configuration will be ignored." + << endmsg; + return true; } - if (!leptonic) {muonic=false; electronic=false;} - // Saving taus decaying into muons (only one copy) - if (muonic) + if (algorithm != "VariableR") { - MAbool found=false; - for (MAuint32 j=0;jMCMuonicTaus_.size();j++) - { - if (myEvent.rec()->MCMuonicTaus_[j]==&(part)) - {found=true; break;} - } - if (!found) myEvent.rec()->MCMuonicTaus_.push_back(&(part)); - } + std::map clustering_params; - // Saving taus decaying into electrons (only one copy) - else if (electronic) - { - MAbool found=false; - for (MAuint32 j=0;jMCElectronicTaus_.size();j++) - { - if (myEvent.rec()->MCElectronicTaus_[j]==&(part)) - {found=true; break;} - } - if (!found) myEvent.rec()->MCElectronicTaus_.push_back(&(part)); - } + // decide if its good to keep this jet + ClusterAlgoBase *new_algo; + // Loop over options + for (const auto &it : options) + { + std::string key = ClusterAlgoBase::Lower(it.first); + if (key == "jetid") + { + // Check if JetID is used before + new_jetid = it.second; + continue; + } + + // Find the clustering algorithm + if (key == "algorithm") + { + if (it.second == "antikt") + new_algo = new ClusterAlgoStandard("antikt"); + else if (it.second == "cambridge") + new_algo = new ClusterAlgoStandard("cambridge"); + else if (it.second == "genkt") + new_algo = new ClusterAlgoStandard("genkt"); + else if (it.second == "kt") + new_algo = new ClusterAlgoStandard("kt"); + else if (it.second == "siscone") + new_algo = new ClusterAlgoSISCone(); + else if (it.second == "cdfmidpoint") + new_algo = new ClusterAlgoCDFMidpoint(); + else if (it.second == "cdfjetclu") + new_algo = new ClusterAlgoCDFJetClu(); + else if (it.second == "gridjet") + new_algo = new ClusterAlgoGridJet(); + else + { + ERROR << "Unknown algorithm : " << it.second << ". It will be ignored." << endmsg; + return true; + } + continue; + } + // clustering algo -> keep the previous syntax + else if (key.find("cluster.") == 0) + { + clustering_params.insert(std::pair(key.substr(8), it.second)); + continue; + } + + // Other + try + { + throw EXCEPTION_WARNING("Parameter = " + key + " unknown. It will be skipped.", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return false; + } + } - // Saving taus decaying into hadrons (only copy) - else + cluster_collection_.insert(std::pair(new_jetid, new_algo)); + for (const auto &it : clustering_params) + cluster_collection_[new_jetid]->SetParameter(it.first, it.second); + std::string algoname = cluster_collection_[new_jetid]->GetName(); + std::string params = cluster_collection_[new_jetid]->GetParameters(); + INFO << " - Adding Jet ID : " << new_jetid << endmsg; + INFO << " with algo : " << algoname << ", " << params << endmsg; + cluster_collection_[new_jetid]->Initialize(); + } + else if (algorithm == "VariableR") { - MAbool found=false; - for (MAuint32 j=0;jMCHadronicTaus_.size();j++) - { - if (myEvent.rec()->MCHadronicTaus_[j]==&(part)) - {found=true; break;} - } - if (!found) - { - // Saving the hadrons in MC container - myEvent.rec()->MCHadronicTaus_.push_back(&(part)); - - // Applying efficiency - if (!myTautagger_->IsIdentified()) continue; - - // Smearing the hadronic taus - MCParticleFormat smeared = mySmearer_->Execute(&part, static_cast(absid)); - // If smeared pt is zero, no need to count the particle but it still needs - // to be vetoed for jet clustering. - if (smeared.pt() > 1e-10) + for (std::string key : {"rho", "minR", "maxR", "PTmin", "clustertype", "strategy", "exclusive"}) { - // Creating reco hadronic taus - RecTauFormat* myTau = myEvent.rec()->GetNewTau(); - if (part.pdgid()>0) myTau->setCharge(-1); - else myTau->setCharge(+1); - myTau->setMomentum(smeared.momentum()); - myTau->setD0(smeared.d0()); - myTau->setDZ(smeared.dz()); - myTau->setD0Approx(smeared.d0_approx()); - myTau->setDZApprox(smeared.dz_approx()); - myTau->setProductionVertex(MALorentzVector(part.mothers()[0]->decay_vertex().X(), - part.mothers()[0]->decay_vertex().Y(), - part.mothers()[0]->decay_vertex().Z(),0.0)); - myTau->setClosestApproach(smeared.closest_approach()); - myTau->setMc(&part); - myTau->setDecayMode(PHYSICS->GetTauDecayMode(myTau->mc())); - if (myTau->DecayMode()<=0) myTau->setNtracks(0); // ERROR case - else if (myTau->DecayMode()==7 || - myTau->DecayMode()==9) myTau->setNtracks(3); // 3-Prong - else myTau->setNtracks(1); // 1-Prong + if (options.find("cluster." + key) == options.end()) + { + ERROR << "Option 'cluster." + key + "' is missing. VariableR clustering will be ignored." << endmsg; + return true; + } } - - // Searching final state - GetFinalState(&part,vetos2); - } + MAfloat32 rho = std::stof(options["cluster.rho"]); + MAfloat32 minR = std::stof(options["cluster.minR"]); + MAfloat32 maxR = std::stof(options["cluster.maxR"]); + MAfloat32 ptmin = std::stof(options["cluster.PTmin"]); + MAbool isExclusive = (options["cluster.exclusive"] == "1"); + + Substructure::VariableR::ClusterType ctype = Substructure::VariableR::AKTLIKE; + if (options["cluster.clustertype"] == "CALIKE") + ctype = Substructure::VariableR::CALIKE; + else if (options["cluster.clustertype"] == "KTLIKE") + ctype = Substructure::VariableR::KTLIKE; + else if (options["cluster.clustertype"] == "AKTLIKE") + ctype = Substructure::VariableR::AKTLIKE; + + Substructure::VariableR::Strategy strategy = Substructure::VariableR::Best; + if (options["cluster.strategy"] == "Best") + strategy = Substructure::VariableR::Best; + else if (options["cluster.strategy"] == "N2Tiled") + strategy = Substructure::VariableR::N2Tiled; + else if (options["cluster.strategy"] == "N2Plain") + strategy = Substructure::VariableR::N2Plain; + else if (options["cluster.strategy"] == "NNH") + strategy = Substructure::VariableR::NNH; + else if (options["cluster.strategy"] == "Native") + strategy = Substructure::VariableR::Native; + + Substructure::VariableR *variableR; + variableR = new Substructure::VariableR(rho, minR, maxR, ctype, strategy, ptmin, isExclusive); + + substructure_collection_.insert( + std::pair(options["JetID"], variableR)); + + std::string exclusive = isExclusive ? "True" : "False"; + INFO << " - Adding Jet ID : " << options["JetID"] << endmsg; + INFO << " with algo : VariableR" + << ", " + << "rho = " << options["cluster.rho"] << ", " + << "minR = " << options["cluster.minR"] << ", " + << "maxR = " << options["cluster.maxR"] << ", " + << "ptmin = " << options["cluster.PTmin"] << ", \n" + << " " + << "isExclusive = " << exclusive << ", " + << "clustertype = " << options["cluster.clustertype"] << ", " + << "strategy = " << options["cluster.strategy"] + << endmsg; + } + else + { + ERROR << "Unknown algorithm: " << algorithm << endmsg; + return false; } - } - } - // Keeping only final states - else if (PHYSICS->Id->IsFinalState(part)) - { - // keeping only electron, muon and photon - if (absid!=22 && absid!=11 && absid!=13) continue; - - // rejecting particle if coming from hadronization - if (ExclusiveId_ && LOOP->ComingFromHadronDecay(&part,mySample,myEvent.mc()->particles().size())) continue; - - // Muons - if (absid==13) - { - vetos[i]=true; - - // Smearing its momentum - MCParticleFormat smeared = mySmearer_->Execute(&part, static_cast(absid)); - if (smeared.pt() <= 1e-10) continue; - - RecLeptonFormat * muon = myEvent.rec()->GetNewMuon(); - muon->setMomentum(smeared.momentum()); - muon->setD0(smeared.d0()); - muon->setDZ(smeared.dz()); - muon->setD0Approx(smeared.d0_approx()); - muon->setDZApprox(smeared.dz_approx()); - muon->setProductionVertex(MALorentzVector(part.mothers()[0]->decay_vertex().X(), - part.mothers()[0]->decay_vertex().Y(), - part.mothers()[0]->decay_vertex().Z(),0.0)); - muon->setClosestApproach(smeared.closest_approach()); - muon->setMc(&(part)); - if (part.pdgid()==13) muon->SetCharge(-1); - else muon->SetCharge(+1); - } - - // Electrons - else if (absid==11) - { - vetos[i]=true; - - // Smearing the electron momentum - MCParticleFormat smeared = mySmearer_->Execute(&part, static_cast(absid)); - if (smeared.pt() <= 1e-10) continue; - - RecLeptonFormat * elec = myEvent.rec()->GetNewElectron(); - elec->setMomentum(smeared.momentum()); - elec->setD0(smeared.d0()); - elec->setDZ(smeared.dz()); - elec->setD0Approx(smeared.d0_approx()); - elec->setDZApprox(smeared.dz_approx()); - elec->setProductionVertex(MALorentzVector(part.mothers()[0]->decay_vertex().X(), - part.mothers()[0]->decay_vertex().Y(), - part.mothers()[0]->decay_vertex().Z(),0.0)); - elec->setClosestApproach(smeared.closest_approach()); - elec->setMc(&(part)); - if (part.pdgid()==11) elec->SetCharge(-1); - else elec->SetCharge(+1); - } - - // Photons - else if (absid==22) - { - if (LOOP->IrrelevantPhoton(&part,mySample)) continue; - vetos[i]=true; - - // Smearing the photon momentum - MCParticleFormat smeared = mySmearer_->Execute(&part, static_cast(absid)); - if (smeared.pt() <= 1e-10) continue; - - RecPhotonFormat * photon = myEvent.rec()->GetNewPhoton(); - photon->setMomentum(smeared.momentum()); - photon->setD0(smeared.d0()); - photon->setDZ(smeared.dz()); - photon->setD0Approx(smeared.d0_approx()); - photon->setDZApprox(smeared.dz_approx()); - photon->setProductionVertex(MALorentzVector(part.mothers()[0]->decay_vertex().X(), - part.mothers()[0]->decay_vertex().Y(), - part.mothers()[0]->decay_vertex().Z(),0.0)); - photon->setClosestApproach(smeared.closest_approach()); - photon->setMc(&(part)); - } + return true; +#else + ERROR << "FastJet has not been enabled. Can not add jets to the analysis." << endmsg; + return true; +#endif } - } - - // Sorting the objecfts after smearing - if (mySmearer_->isElectronSmearerOn()) - std::sort(myEvent.rec()->electrons_.begin(), myEvent.rec()->electrons_.end(), sort_by_leptonPT); - if (mySmearer_->isMuonSmearerOn()) - std::sort(myEvent.rec()->muons_.begin(), myEvent.rec()->muons_.end(), sort_by_leptonPT); - if (mySmearer_->isTauSmearerOn()) - std::sort(myEvent.rec()->taus_.begin(), myEvent.rec()->taus_.end(), sort_by_tauPT); - if (mySmearer_->isPhotonSmearerOn()) - std::sort(myEvent.rec()->photons_.begin(), myEvent.rec()->photons_.end(), sort_by_photonPT); - - // Launching the clustering - // -> Filling the collection: myEvent->rec()->jets() - algo_->Execute(mySample,myEvent,ExclusiveId_,vetos,vetos2,mySmearer_); - - // shortcut for TET & THT - MAfloat64 & TET = myEvent.rec()->TET(); - // MAfloat64 & THT = myEvent.rec()->THT(); - RecParticleFormat* MET = &(myEvent.rec()->MET()); - RecParticleFormat* MHT = &(myEvent.rec()->MHT()); - - // End - if (ExclusiveId_) - { - for (MAuint32 i=0;ielectrons().size();i++) - { - (*MET) -= myEvent.rec()->electrons()[i].momentum(); - TET += myEvent.rec()->electrons()[i].pt(); - } - for (MAuint32 i=0;iphotons().size();i++) - { - (*MET) -= myEvent.rec()->photons()[i].momentum(); - TET += myEvent.rec()->photons()[i].pt(); - } - for (MAuint32 i=0;itaus().size();i++) - { - (*MET) -= myEvent.rec()->taus()[i].momentum(); - TET += myEvent.rec()->taus()[i].pt(); - } - } - - for (MAuint32 i=0;imuons().size();i++) - { - (*MET) -= myEvent.rec()->muons()[i].momentum(); - TET += myEvent.rec()->muons()[i].pt(); - } - - MET->momentum().SetPz(0.); - MET->momentum().SetE(MET->momentum().Pt()); - MHT->momentum().SetPz(0.); - MHT->momentum().SetE(MHT->momentum().Pt()); - - myBtagger_->Execute(mySample,myEvent); - myTautagger_->Execute(mySample,myEvent); - - return true; -} +} // namespace diff --git a/tools/SampleAnalyzer/Process/JetClustering/JetClusterer.h b/tools/SampleAnalyzer/Process/JetClustering/JetClusterer.h index 357c4aa4..0847cd5b 100644 --- a/tools/SampleAnalyzer/Process/JetClustering/JetClusterer.h +++ b/tools/SampleAnalyzer/Process/JetClustering/JetClusterer.h @@ -2,144 +2,146 @@ // // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef JET_CLUSTERER_H #define JET_CLUSTERER_H - // SampleAnalyser headers #include "SampleAnalyzer/Commons/DataFormat/EventFormat.h" #include "SampleAnalyzer/Commons/DataFormat/SampleFormat.h" -#include "SampleAnalyzer/Commons/Service/Physics.h" -#include "SampleAnalyzer/Commons/Base/ClusterAlgoBase.h" -#include "SampleAnalyzer/Process/JetClustering/bTagger.h" -#include "SampleAnalyzer/Process/JetClustering/cTagger.h" -#include "SampleAnalyzer/Process/JetClustering/TauTagger.h" -#include "SampleAnalyzer/Process/JetClustering/NullSmearer.h" #include "SampleAnalyzer/Commons/Base/SmearerBase.h" +#include "SampleAnalyzer/Commons/Base/SFSTaggerBase.h" + +#ifdef MA5_FASTJET_MODE +#include "SampleAnalyzer/Interfaces/substructure/ClusterBase.h" +#endif // STL headers -#include -#include #include - namespace MA5 { - class JetClusterer - { - //-------------------------------------------------------------------------- - // data members - //-------------------------------------------------------------------------- - protected : - - ClusterAlgoBase* algo_; - bTagger* myBtagger_; - cTagger* myCtagger_; - TauTagger* myTautagger_; - SmearerBase* mySmearer_; - - /// Exclusive id for tau-elec-photon-jet - MAbool ExclusiveId_; - - MAuint32 muon; - MAuint32 electron; - MAuint32 tauH; - MAuint32 tauM; - MAuint32 tauE; - MAuint32 photon; - - //-------------------------------------------------------------------------- - // method members - //-------------------------------------------------------------------------- - public : - - /// Constructor without argument - JetClusterer (ClusterAlgoBase* algo) - { - // Initializing tagger - algo_ = algo; - myBtagger_ = 0; - myCtagger_ = 0; - myTautagger_ = 0; - mySmearer_ = 0; - ExclusiveId_ = false; - muon=0; - electron=0; - tauH=0; - tauM=0; - tauE=0; - photon=0; - } - - /// Destructor - ~JetClusterer() - { } - - /// Initialization - MAbool Initialize(const std::map& options); - - /// Jet clustering - MAbool Execute(SampleFormat& mySample, EventFormat& myEvent); - - /// Finalization - void Finalize(); - - /// Generic loader for the smearer module - void LoadSmearer(SmearerBase* smearer) + class ClusterAlgoBase; + + class JetClusterer { - mySmearer_ = smearer; - mySmearer_->Initialize(); - } - - /// Accessor to the jet clusterer name - std::string GetName() - { - if (algo_==0) return "NotDefined"; - else return algo_->GetName(); - } - - /// Accessor to the b tagger parameters - std::string bParameters() - { return myBtagger_->GetParameters(); } - - /// Accessor to the tau tagger parameters - std::string tauParameters() - { return myTautagger_->GetParameters(); } - - /// Print parameters - void PrintParam() - { algo_->PrintParam(); } - - /// Accessor to the jet clusterer parameters - std::string GetParameters() - { return algo_->GetParameters(); } - - private: - MAbool IsLast(const MCParticleFormat* part, EventFormat& myEvent); - void GetFinalState(const MCParticleFormat* part, std::set& finalstates); - - }; + //-------------------------------------------------------------------------- + // data members + //-------------------------------------------------------------------------- + protected: + ClusterAlgoBase *algo_; + /// SFS smearer + SmearerBase *mySmearer_; + /// b/c/tau tagger + SFSTaggerBase *myTagger_; + + /// pointer to tagger options + SFSTaggerBaseOptions *myTaggerOptions_; + + /// @brief Exclusive id for tau-elec-photon-jet + /// @code ExclusiveId_ = true; @endcode + /// Exclusive algorithm: FS Leptons (photons) originated from hadronic decays + /// will not be included in Lepton (photon) collection. + /// @code ExclusiveId_ = false; @endcode + /// Includive algorithm: All FS leptons (photons) will be included in + /// their corresponding containers. + MAbool ExclusiveId_; + + /// Primary Jet ID + std::string JetID_; + +#ifdef MA5_FASTJET_MODE + /// Jet collection configurations + std::map cluster_collection_; + + // Jet collection configuration with VariableR + std::map substructure_collection_; +#endif + + // Track Isolation radius + std::vector isocone_track_radius_; + + // Electron Isolation radius + std::vector isocone_electron_radius_; + + // Muon Isolation radius + std::vector isocone_muon_radius_; + + // Photon Isolation radius + std::vector isocone_photon_radius_; + + //-------------------------------------------------------------------------- + // method members + //-------------------------------------------------------------------------- + public: + /// Constructor + JetClusterer(ClusterAlgoBase *algo); + + /// Destructor + ~JetClusterer(); + + /// Initialization + MAbool Initialize(const std::map &options); + + /// Jet clustering + MAbool Execute(SampleFormat &mySample, EventFormat &myEvent); + + /// Finalization + void Finalize(); + + /// Generic loader for the smearer module + void LoadSmearer(SmearerBase *smearer) + { + mySmearer_ = smearer; + mySmearer_->Initialize(); + } + + /// Generic Loader for tagger module + void LoadTagger(SFSTaggerBase *tagger) + { + myTagger_ = tagger; + myTagger_->Initialize(); + myTagger_->SetOptions(*myTaggerOptions_); + } + + // Load additional Jets + MAbool LoadJetConfiguration(std::map options); + + /// Accessor to the jet clusterer name + std::string GetName(); + + /// Accessor to the tagger parameters + void TaggerParameters(); + + /// Print parameters + void PrintParam(); + + /// Accessor to the jet clusterer parameters + std::string GetParameters(); + + private: + MAbool IsLast(const MCParticleFormat *part, EventFormat &myEvent); + void GetFinalState(const MCParticleFormat *part, std::set &finalstates); + }; } diff --git a/tools/SampleAnalyzer/Process/JetClustering/TauTagger.cpp b/tools/SampleAnalyzer/Process/JetClustering/TauTagger.cpp deleted file mode 100644 index 99759bda..00000000 --- a/tools/SampleAnalyzer/Process/JetClustering/TauTagger.cpp +++ /dev/null @@ -1,315 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks -// The MadAnalysis development team, email: -// -// This file is part of MadAnalysis 5. -// Official website: -// -// MadAnalysis 5 is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// MadAnalysis 5 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with MadAnalysis 5. If not, see -// -//////////////////////////////////////////////////////////////////////////////// - - -// STL headers -#include - -// SampleAnalyzer headers -#include "SampleAnalyzer/Process/JetClustering/TauTagger.h" -#include "SampleAnalyzer/Commons/Service/RandomService.h" -#include "SampleAnalyzer/Commons/Service/ExceptionService.h" - - -using namespace MA5; - - -void TauTagger::Method1 (SampleFormat& mySample, EventFormat& myEvent) -{ - // Performing mis-id - if (doMisefficiency_) - { - std::vector toRemove; - for (MAuint32 i=0;ijets().size();i++) - { - // keeping only light jets - if (myEvent.rec()->jets()[i].true_ctag_ || - myEvent.rec()->jets()[i].true_btag_) continue; - - // simulating mis-id - if (RANDOM->flat() < misid_ljet_) - { - RecTauFormat* myTau = myEvent.rec()->GetNewTau(); - Jet2Tau(&myEvent.rec()->jets()[i], myTau, myEvent); - toRemove.push_back(i); - } - } - for (MAint32 i=toRemove.size()-1; i>=0;i--) - { - myEvent.rec()->jets().erase(myEvent.rec()->jets().begin() - + toRemove[i]); - } - } - -} - -void TauTagger::Method2 (SampleFormat& mySample, EventFormat& myEvent) -{ - std::vector Candidates; - - for (MAuint32 i=0;ijets().size();i++) - { - if (myEvent.rec()->jets()[i].ntracks()!=1 && myEvent.rec()->jets()[i].ntracks()!=3) continue; - - MAbool tag = false; - // Loop on the jets constituents - for (MAuint32 j=0;jjets()[i].Constituents_.size();j++) - { - // Searching for a tau in the history - MAint32 N = myEvent.rec()->jets()[i].Constituents_[j]; - MCParticleFormat* particle = & myEvent.mc()->particles()[N]; - while (!tag) - { - if (particle==0) - { - ERROR << "No particle" << endmsg; - break; - } - if (particle->statuscode()==3) break; - - if (std::abs(particle->pdgid())==15) - { - tag = true; - myEvent.rec()->jets()[i].mc_ = particle; - break; - } - - if (particle->mothers().size()>1 && particle->mothers()[1]!=particle->mothers()[0]) break; - - particle = particle->mothers()[0]; - } - - if (tag) break; - } - - if (tag) Candidates.push_back(& myEvent.rec()->jets()[i]); - } - - if (Exclusive_) - { - MAuint32 i = 0; - MAuint32 n = Candidates.size(); - - while (imc()->dr(Candidates[i]); - - while (jmc()==Candidates[j]->mc()) - { - MAfloat32 DeltaR2 = Candidates[j]->mc()->dr(Candidates[j]); - - if (DeltaR20;i--) - { - RecTauFormat* myTau = myEvent.rec()->GetNewTau(); - Jet2Tau(Candidates[i-1], myTau, myEvent); - // BENJ PB COMPIL: myEvent.rec()->jets().erase((std::vector::iterator) Candidates[i-1]); - - // Remove the tau-identified jet from the list - MAuint32 pos=myEvent.rec()->jets().size(); - for (MAuint32 ind=0;indjets().size();ind++) - { - if (&(myEvent.rec()->jets()[ind])==Candidates[i-1]) {pos=ind;break;} - } - if (pos!=myEvent.rec()->jets().size()) // must never happen - myEvent.rec()->jets().erase(myEvent.rec()->jets().begin()+pos); - } - Candidates.clear(); -} - -void TauTagger::Method3 (SampleFormat& mySample, EventFormat& myEvent) -{ - std::vector Candidates; - - // Jets preselection using method 2 - for (MAuint32 i=0;ijets().size();i++) - { - if (myEvent.rec()->jets()[i].ntracks()!=1 && myEvent.rec()->jets()[i].ntracks()!=3) continue; - - MAbool tag = false; - for (MAuint32 j=0;jjets()[i].Constituents_.size();j++) - { - MAint32 N = myEvent.rec()->jets()[i].Constituents_[j]; - MCParticleFormat* particle = & myEvent.mc()->particles()[N]; - while (!tag) - { - if (particle==0) - { - ERROR << "No particle" << endmsg; - break; - } - - if (particle->statuscode()==3) break; - - if (std::abs(particle->pdgid())==15) - { - tag = true; - myEvent.rec()->jets()[i].mc_ = particle; - break; - } - - if (particle->mothers().size()>1 && particle->mothers()[1]!=particle->mothers()[0]) break; - - particle = particle->mothers()[0]; - } - - if (tag) break; - } - - if (tag) Candidates.push_back(& myEvent.rec()->jets()[i]); - } - - std::vector Taus; - - // tau-tagging using method 1 - for (MAuint32 i=0;iparticles().size();i++) - { - if (std::abs(myEvent.mc()->particles()[i].pdgid())!=15) continue; - - if (!IsLast(&myEvent.mc()->particles()[i], myEvent)) continue; - - MAfloat64 DeltaRmax = DeltaRmax_; - MAbool tag = false; - - for (MAuint32 j=Candidates.size();j>0;j--) - { - MAfloat32 DeltaR = myEvent.mc()->particles()[i].dr(Candidates[j-1]); - - if (DeltaR <= DeltaRmax) - { - if (Exclusive_) - { - if (tag) Taus.pop_back(); - tag = true; - DeltaRmax = DeltaR; - } - Taus.push_back(Candidates[j-1]); - Candidates.erase(Candidates.begin()+j-1); - } - } - } - - sort(Taus.begin(),Taus.end()); - - for (MAuint32 j=Taus.size();j>0;j--) - { - RecTauFormat* myTau = myEvent.rec()->GetNewTau(); - Jet2Tau(Taus[j-1], myTau, myEvent); - // PB Benj compil: myEvent.rec()->jets().erase((std::vector::iterator) Taus[j-1]); - - // Remove the tau-identified jet from the list - MAuint32 pos=myEvent.rec()->jets().size(); - for (MAuint32 ind=0;indjets().size();ind++) - { - if (&(myEvent.rec()->jets()[ind])==Taus[j-1]) {pos=ind;break;} - } - if (pos!=myEvent.rec()->jets().size()) // must never happen - myEvent.rec()->jets().erase(myEvent.rec()->jets().begin()+pos); - - - } - - Taus.clear(); - Candidates.clear(); -} - - -void TauTagger::Jet2Tau (RecJetFormat* myJet, RecTauFormat* myTau, EventFormat& myEvent) -{ - myTau->setMomentum(myJet->momentum()); - myTau->ntracks_ = myJet->ntracks(); - myTau->mc_ = myJet->mc_; - myTau->DecayMode_ = PHYSICS->GetTauDecayMode(myTau->mc_); - - MAint32 charge = 0; - - for (MAuint32 i=0;iConstituents_.size();i++) - { - charge += PDG->GetCharge(myEvent.mc()->particles()[myJet->Constituents_[i]].pdgid()); - } - - if (charge>0) myTau->charge_ = true; - else if (charge<=0) myTau->charge_ = false; -} - - -MAbool TauTagger::SetParameter(const std::string& key, - const std::string& value, - std::string header) -{ - // miss-id efficiency - if (key=="misid_ljet") - { - MAfloat32 tmp=0; - std::stringstream str; - str << value; - str >> tmp; - if (tmp<0) - { - WARNING << "'misid_ljet' efficiency must be a positive value. " - << "Using the default value = " - << misid_ljet_ << endmsg; - } - else if (tmp>1) - { - WARNING << "'misid_ljet' efficiency cannot be greater than 1. " - << "Using the default value = " - << misid_ljet_ << endmsg; - } - else misid_ljet_=tmp; - if (misid_ljet_==0.0) doMisefficiency_=false; else doMisefficiency_=true; - } - - // Other - else return TaggerBase::SetParameter(key,value,header); - - return true; - -} - - -std::string TauTagger::GetParameters() -{ - std::stringstream str; - str << "IDeff=" << Efficiency_; - str << " ; MisID(q)=" << misid_ljet_; - return str.str(); -} diff --git a/tools/SampleAnalyzer/Process/JetClustering/TauTagger.h b/tools/SampleAnalyzer/Process/JetClustering/TauTagger.h deleted file mode 100644 index 027570ea..00000000 --- a/tools/SampleAnalyzer/Process/JetClustering/TauTagger.h +++ /dev/null @@ -1,96 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks -// The MadAnalysis development team, email: -// -// This file is part of MadAnalysis 5. -// Official website: -// -// MadAnalysis 5 is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// MadAnalysis 5 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with MadAnalysis 5. If not, see -// -//////////////////////////////////////////////////////////////////////////////// - - -#ifndef TAUTAGGER_H -#define TAUTAGGER_H - - -// SampleAnalyser headers -#include "SampleAnalyzer/Commons/Base/TaggerBase.h" - - -namespace MA5 -{ - -class TauTagger: public TaggerBase -{ -//--------------------------------------------------------------------------------- -// data members -//--------------------------------------------------------------------------------- - protected : - - /// Mis-identification efficiency - MAfloat32 misid_ljet_; - - /// Apply misefficiency - MAbool doMisefficiency_; - // TH1F* htest; - -//--------------------------------------------------------------------------------- -// method members -//--------------------------------------------------------------------------------- - public : - - /// Constructor without argument - TauTagger () - { - misid_ljet_=0.0; - doMisefficiency_=false; - // htest = new TH1F("eric","eric",10,0,10); - } - - /// Destructor - virtual ~TauTagger () - { /*htest->SaveAs("Alloul.root");*/ } - - /// Matching using dr - virtual void Method1 (SampleFormat& mySample, EventFormat& myEvent); - - /// Matching using the history - virtual void Method2 (SampleFormat& mySample, EventFormat& myEvent); - - /// Matching using a jet preselection with the history before calculating dr - virtual void Method3 (SampleFormat& mySample, EventFormat& myEvent); - - /// Matching general method - virtual void Execute(SampleFormat& mySample, EventFormat& myEvent) - { - if (Method_==1) Method1(mySample,myEvent); - else if (Method_==2) Method2(mySample,myEvent); - else if (Method_==3) Method3(mySample,myEvent); - } - - /// Fill the Tau format with the information from the jet format - void Jet2Tau (RecJetFormat* myJet, RecTauFormat* myTau, EventFormat& myEvent); - - /// Set a parameter - virtual MAbool SetParameter(const std::string& key, const std::string& value,std::string header); - - virtual std::string GetParameters(); - -}; - -} - -#endif diff --git a/tools/SampleAnalyzer/Process/JetClustering/bTagger.cpp b/tools/SampleAnalyzer/Process/JetClustering/bTagger.cpp deleted file mode 100644 index 8d7cb1bb..00000000 --- a/tools/SampleAnalyzer/Process/JetClustering/bTagger.cpp +++ /dev/null @@ -1,367 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks -// The MadAnalysis development team, email: -// -// This file is part of MadAnalysis 5. -// Official website: -// -// MadAnalysis 5 is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// MadAnalysis 5 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with MadAnalysis 5. If not, see -// -//////////////////////////////////////////////////////////////////////////////// - - -// SampleAnalyzer headesr -#include "SampleAnalyzer/Commons/Service/RandomService.h" -#include "SampleAnalyzer/Process/JetClustering/bTagger.h" -#include - - -using namespace MA5; - - -void bTagger::Method1 (SampleFormat& mySample, EventFormat& myEvent) -{ - std::vector Candidates; - - // Matching b-quarks to jets - for (MAuint32 i=0;iMCBquarks_.size();i++) - { - RecJetFormat* tag = 0; - MAfloat64 DeltaRmax = DeltaRmax_; - - // loop on the jets - for (MAuint32 j=0;jjets().size();j++) - { - if (myEvent.rec()->jets()[j].pt()<1e-10) continue; - MAfloat32 DeltaR = myEvent.rec()->MCBquarks_[i]->dr(myEvent.rec()->jets()[j]); - - if (DeltaR <= DeltaRmax) - { - if (Exclusive_) - { - tag = &(myEvent.rec()->jets()[j]); - DeltaRmax = DeltaR; - } - else Candidates.push_back(& myEvent.rec()->jets()[j]); - } - } - if (Exclusive_ && tag!=0) Candidates.push_back(tag); - } - - // Tagging the b-jet - for (MAuint32 i=0;itrue_btag_ = true; - } - Candidates.clear(); - - // Matching c-quarks to jets - for (MAuint32 i=0;iMCCquarks_.size();i++) - { - RecJetFormat* tag = 0; - MAfloat64 DeltaRmax = DeltaRmax_; - - // loop on the jets - for (MAuint32 j=0;jjets().size();j++) - { - if (myEvent.rec()->jets()[j].pt()<1e-10) continue; - - MAfloat32 DeltaR = - myEvent.rec()->MCCquarks_[i]->dr(myEvent.rec()->jets()[j]); - - if (DeltaR <= DeltaRmax) - { - if (Exclusive_) - { - tag = &(myEvent.rec()->jets()[j]); - DeltaRmax = DeltaR; - } - else Candidates.push_back(& myEvent.rec()->jets()[j]); - } - } - if (Exclusive_ && tag!=0) Candidates.push_back(tag); - } - - // Tagging the c-jet - for (MAuint32 i=0;itrue_btag_) continue; - Candidates[i]->true_ctag_ = true; - } - - // Identification and misidentification - for (MAuint32 i=0;ijets().size();i++) - { - RecJetFormat* jet = &(myEvent.rec()->jets()[i]); - - // 100% identification - if (jet->true_btag_) jet->btag_=true; - if (!doEfficiency_ && !doMisefficiency_) continue; - - // identification efficiency - if (doEfficiency_ && jet->true_btag_) - { - if (RANDOM->flat() >= Efficiency_) jet->btag_=false; - } - - // mis-identification (c-quark) - if (doMisefficiency_ && !jet->true_btag_ && jet->true_ctag_) - { - if (RANDOM->flat() < misid_cjet_) jet->btag_=true; - } - - // mis-identification (light quarks) - else if (doMisefficiency_ && !jet->true_btag_ && !jet->true_ctag_) - { - if (RANDOM->flat() < misid_ljet_) jet->btag_=true; - } - } - -} - -void bTagger::Method2 (SampleFormat& mySample, EventFormat& myEvent) -{ - std::vector Candidates; - - for (MAuint32 i=0;ijets().size();i++) - { - MAbool b = false; - - for (MAuint32 j=0;jjets()[i].Constituents_.size();j++) - { - MAint32 N = myEvent.rec()->jets()[i].Constituents_[j]; - MCParticleFormat* particle = & myEvent.mc()->particles()[N]; - while (!b) - { - if (particle==0) - { - INFO << "No particle" << endmsg; - break; - } - - if (particle->statuscode()==3) break; - - if (PHYSICS->Id->IsBHadron(particle->pdgid()) && IsLastBHadron(particle, myEvent)) - { - b = true; - myEvent.rec()->jets()[i].mc_ = particle; - break; - } - - if (particle->mothers().size()>1 && particle->mothers()[1]!=particle->mothers()[0]) break; - - particle = particle->mothers()[0]; - } - - if (b) break; - } - - if (b) Candidates.push_back(& myEvent.rec()->jets()[i]); - } - - if (Exclusive_) - { - MAuint32 i = 0; - MAuint32 n = Candidates.size(); - - while (imc()->dr(Candidates[i]); - - while (jmc()==Candidates[j]->mc()) - { - MAfloat32 DeltaR2 = Candidates[j]->mc()->dr(Candidates[j]); - - if (DeltaR2btag_ = true; - } -} - -void bTagger::Method3 (SampleFormat& mySample, EventFormat& myEvent) -{ - std::vector Candidates; - - // jet preselection using method 2 - for (MAuint32 i=0;ijets().size();i++) - { - MAbool b = false; - - for (MAuint32 j=0;jjets()[i].Constituents_.size();j++) - { - MAint32 N = myEvent.rec()->jets()[i].Constituents_[j]; - MCParticleFormat* particle = & myEvent.mc()->particles()[N]; - while (!b) - { - if (particle==0) - { - INFO << "No particle" << endmsg; - break; - } - - if (particle->statuscode()==3) break; - - if (PHYSICS->Id->IsBHadron(particle->pdgid()) && IsLastBHadron(particle, myEvent)) - { - b = true; - myEvent.rec()->jets()[i].mc_ = particle; - break; - } - - if (particle->mothers().size()>1 && particle->mothers()[1]!=particle->mothers()[0]) break; - - particle = particle->mothers()[0]; - } - - if (b) break; - } - - if (b) Candidates.push_back(& myEvent.rec()->jets()[i]); - } - - // b-tagging using method 1 - for (MAuint32 i=0;iparticles().size();i++) - { - if (std::abs(myEvent.mc()->particles()[i].pdgid())!=5) continue; - - if (!IsLast(&myEvent.mc()->particles()[i], myEvent)) continue; - - MAuint32 k = 0; - - for (MAuint32 j=Candidates.size();j>0;j--) - { - MAfloat32 DeltaR = myEvent.mc()->particles()[i].dr(Candidates[j-1]); - - if (DeltaR <= DeltaRmax_) - { - k++; - std::swap (Candidates[j-1], Candidates[Candidates.size()-k]); - } - } - - if (Exclusive_) - { - while (k>1) - { - if (Candidates[Candidates.size()-1]->e() > Candidates[Candidates.size()-2]->e()) std::swap(Candidates[Candidates.size()-1], Candidates[Candidates.size()-2]); - Candidates.pop_back(); - k--; - } - } - - for (MAuint32 j=0;jbtag_=true; - Candidates.pop_back(); - } - } - - Candidates.clear(); -} - -MAbool bTagger::IsLastBHadron(MCParticleFormat* part, EventFormat& myEvent) -{ - for (MAuint32 i=0; iparticles().size(); i++) - { - if (myEvent.mc()->particles()[i].mothers()[0]== part) - { - if (PHYSICS->Id->IsBHadron(myEvent.mc()->particles()[i].pdgid())) return false; - } - } - return true; -} - - -MAbool bTagger::SetParameter(const std::string& key, - const std::string& value, - std::string header) -{ - // miss-id efficiency - if (key=="misid_ljet") - { - MAfloat32 tmp=0; - std::stringstream str; - str << value; - str >> tmp; - if (tmp<0) - { - WARNING << "'misid_ljet' efficiency must be a positive value. " - << "Using the default value = " - << misid_ljet_ << endmsg; - } - else if (tmp>1) - { - WARNING << "'misid_ljet' efficiency cannot be greater than 1. " - << "Using the default value = " - << misid_ljet_ << endmsg; - } - else misid_ljet_=tmp; - if (misid_ljet_!=0.0) doMisefficiency_=true; - } - - // miss-id efficiency - else if (key=="misid_cjet") - { - MAfloat32 tmp=0; - std::stringstream str; - str << value; - str >> tmp; - if (tmp<0) - { - WARNING << "'misid_cjet' efficiency must be a positive value. " - << "Using the default value = " - << misid_cjet_ << endmsg; - } - else if (tmp>1) - { - WARNING << "'misid_cjet' efficiency cannot be greater than 1. " - << "Using the default value = " - << misid_cjet_ << endmsg; - } - else misid_cjet_=tmp; - if (misid_cjet_!=0.0) doMisefficiency_=true; - } - - // Other - else return TaggerBase::SetParameter(key,value,header); - return true; -} - -std::string bTagger::GetParameters() -{ - std::stringstream str; - str << "dR=" << DeltaRmax_ << " ; "; - if (Exclusive_) str << "Exclusive ; "; else str << "Inclusive ; "; - str << "IDeff=" << Efficiency_; - str << " ; MisID(c)=" << misid_cjet_; - str << " ; MisID(q)=" << misid_ljet_; - return str.str(); -} diff --git a/tools/SampleAnalyzer/Process/JetClustering/bTagger.h b/tools/SampleAnalyzer/Process/JetClustering/bTagger.h deleted file mode 100644 index 1bde801a..00000000 --- a/tools/SampleAnalyzer/Process/JetClustering/bTagger.h +++ /dev/null @@ -1,99 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks -// The MadAnalysis development team, email: -// -// This file is part of MadAnalysis 5. -// Official website: -// -// MadAnalysis 5 is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// MadAnalysis 5 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with MadAnalysis 5. If not, see -// -//////////////////////////////////////////////////////////////////////////////// - - -#ifndef BTAGGER_H -#define BTAGGER_H - - -// SampleAnalyzer headers -#include "SampleAnalyzer/Commons/Base/TaggerBase.h" - - -namespace MA5 -{ - -class bTagger:public TaggerBase -{ -//--------------------------------------------------------------------------------- -// data members -//--------------------------------------------------------------------------------- - - protected : - - /// Mis-identification efficiency - MAfloat32 misid_ljet_; - - /// Mis-identification efficiency - MAfloat32 misid_cjet_; - - /// Apply misefficiency - MAbool doMisefficiency_; - - -//--------------------------------------------------------------------------------- -// method members -//--------------------------------------------------------------------------------- - public : - - /// Constructor without argument - bTagger() - { - misid_cjet_=0.0; - misid_ljet_=0.0; - doMisefficiency_=false; - } - - /// Destructor - virtual ~bTagger() {} - - /// Matching using dr - virtual void Method1 (SampleFormat& mySample, EventFormat& myEvent); - - /// Matching using the history - virtual void Method2 (SampleFormat& mySample, EventFormat& myEvent); - - /// Matching using a jet preselection with the history before calculating dr - virtual void Method3 (SampleFormat& mySample, EventFormat& myEvent); - - /// Matching general method - virtual void Execute(SampleFormat& mySample, EventFormat& myEvent) - { - if (Method_==1) Method1(mySample,myEvent); - else if (Method_==2) Method2(mySample,myEvent); - else if (Method_==3) Method3(mySample,myEvent); - } - - /// Is this B hadron the last in the decay chain ? - MAbool IsLastBHadron(MCParticleFormat* part, EventFormat& myEvent); - - /// Set a parameter - virtual MAbool SetParameter(const std::string& key, const std::string& value,std::string header); - - virtual std::string GetParameters(); - -}; - -} - -#endif diff --git a/tools/SampleAnalyzer/Process/JetClustering/cTagger.cpp b/tools/SampleAnalyzer/Process/JetClustering/cTagger.cpp deleted file mode 100644 index dca54a05..00000000 --- a/tools/SampleAnalyzer/Process/JetClustering/cTagger.cpp +++ /dev/null @@ -1,260 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks -// The MadAnalysis development team, email: -// -// This file is part of MadAnalysis 5. -// Official website: -// -// MadAnalysis 5 is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// MadAnalysis 5 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with MadAnalysis 5. If not, see -// -//////////////////////////////////////////////////////////////////////////////// - - -// SampleAnalyzer headers -#include "SampleAnalyzer/Process/JetClustering/cTagger.h" - -// STL headers -#include - - -using namespace MA5; - -// Matching using dr -void cTagger::Method1 (SampleFormat& mySample, EventFormat& myEvent) -{ - std::vector Candidates; - - // loop on the particles searching for last c - for (MAuint32 i=0;iparticles().size();i++) - { - if (PHYSICS->Id->IsInitialState(myEvent.mc()->particles()[i])) continue; - if (std::abs(myEvent.mc()->particles()[i].pdgid())!=4) continue; - if (!IsLast(&myEvent.mc()->particles()[i], myEvent)) continue; - - MAbool tag = false; - MAfloat64 DeltaRmax = DeltaRmax_; - - // loop on the jets - for (MAuint32 j=0;jjets().size();j++) - { - if (myEvent.rec()->jets()[j].btag()) continue; - - // Calculating DeltaR - MAfloat32 DeltaR = myEvent.mc()->particles()[i].dr(myEvent.rec()->jets()[j]); - - // Adding the jet to the candidates if DeltaR <= DeltaRmax - if (DeltaR <= DeltaRmax) - { - if (Exclusive_) - { - if (tag) Candidates.pop_back(); - tag = true; - DeltaRmax = DeltaR; - } - Candidates.push_back(& myEvent.rec()->jets()[j]); - } - } - - // Tagging the candidates - for (MAuint32 i=0;itrue_ctag_ = true; - } - - Candidates.clear(); - } -} - -// Matching using history -void cTagger::Method2 (SampleFormat& mySample, EventFormat& myEvent) -{ - std::vector Candidates; - - for (MAuint32 i=0;ijets().size();i++) - { - if (myEvent.rec()->jets()[i].btag()) continue; - - MAbool c = false; - - for (MAuint32 j=0;jjets()[i].Constituents_.size();j++) - { - MAint32 N = myEvent.rec()->jets()[i].Constituents_[j]; - MCParticleFormat* particle = & myEvent.mc()->particles()[N]; - while (!c) - { - if (particle==0) - { - INFO << "No particle" << endmsg; - break; - } - - if (particle->statuscode()==3) break; - - if (PHYSICS->Id->IsCHadron(particle->pdgid()) && IsLastCHadron(particle, myEvent)) - { - c = true; - myEvent.rec()->jets()[i].mc_ = particle; - break; - } - - if (particle->mothers()[1]!=0 && particle->mothers()[1]!=particle->mothers()[0]) break; - - particle = particle->mothers()[0]; - } - - if (c) break; - } - - if (c) Candidates.push_back(& myEvent.rec()->jets()[i]); - } - - if (Exclusive_) - { - MAuint32 i = 0; - MAuint32 n = Candidates.size(); - - while (imc()->dr(Candidates[i]); - - while (jmc()==Candidates[j]->mc()) - { - MAfloat32 DeltaR2 = Candidates[j]->mc()->dr(Candidates[j]); - - if (DeltaR2true_ctag_ = true; - } - - Candidates.clear(); -} - -void cTagger::Method3 (SampleFormat& mySample, EventFormat& myEvent) -{ - std::vector Candidates; - - // jet preselection using method 2 - for (MAuint32 i=0;ijets().size();i++) - { - if (myEvent.rec()->jets()[i].btag()) continue; - - MAbool c = false; - - for (MAuint32 j=0;jjets()[i].Constituents_.size();j++) - { - MAint32 N = myEvent.rec()->jets()[i].Constituents_[j]; - MCParticleFormat* particle = & myEvent.mc()->particles()[N]; - while (!c) - { - if (particle==0) - { - INFO << "No particle" << endmsg; - break; - } - - if (particle->statuscode()==3) break; - - if (PHYSICS->Id->IsCHadron(particle->pdgid()) && IsLastCHadron(particle, myEvent)) - { - c = true; - myEvent.rec()->jets()[i].mc_ = particle; - break; - } - - if (particle->mothers()[1]!=0 && particle->mothers()[1]!=particle->mothers()[0]) break; - - particle = particle->mothers()[0]; - } - - if (c) break; - } - - if (c) Candidates.push_back(& myEvent.rec()->jets()[i]); - } - - // c-tagging using method 1 - for (MAuint32 i=0;iparticles().size();i++) - { - if (std::abs(myEvent.mc()->particles()[i].pdgid())!=4) continue; - - if (!IsLast(&myEvent.mc()->particles()[i], myEvent)) continue; - - MAuint32 k = 0; - - for (MAuint32 j=Candidates.size();j>0;j--) - { - MAfloat32 DeltaR = myEvent.mc()->particles()[i].dr(Candidates[j-1]); - - if (DeltaR <= DeltaRmax_) - { - k++; - std::swap (Candidates[j-1], Candidates[Candidates.size()-k]); - } - } - - if (Exclusive_) - { - while (k>1) - { - if (Candidates[Candidates.size()-1]->e() > Candidates[Candidates.size()-2]->e()) std::swap(Candidates[Candidates.size()-1], Candidates[Candidates.size()-2]); - Candidates.pop_back(); - k--; - } - } - - for (MAuint32 j=0;jtrue_ctag_=true; - Candidates.pop_back(); - } - } - - Candidates.clear(); -} - -MAbool cTagger::IsLastCHadron(MCParticleFormat* part, EventFormat& myEvent) -{ - for (MAuint32 i=0; iparticles().size(); i++) - { - if (myEvent.mc()->particles()[i].mothers()[0]== part) - { - if (PHYSICS->Id->IsCHadron(myEvent.mc()->particles()[i].pdgid())) return false; - } - } - return true; -} - -std::string cTagger::GetParameters() -{ - std::stringstream str; - // str << "R=" << R_ << " ; p=" << p_ << " ; PTmin=" << Ptmin_; - return str.str(); -} diff --git a/tools/SampleAnalyzer/Process/JetClustering/cTagger.h b/tools/SampleAnalyzer/Process/JetClustering/cTagger.h deleted file mode 100644 index 1bbf42d3..00000000 --- a/tools/SampleAnalyzer/Process/JetClustering/cTagger.h +++ /dev/null @@ -1,79 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks -// The MadAnalysis development team, email: -// -// This file is part of MadAnalysis 5. -// Official website: -// -// MadAnalysis 5 is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// MadAnalysis 5 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with MadAnalysis 5. If not, see -// -//////////////////////////////////////////////////////////////////////////////// - - -#ifndef CTAGGER_H -#define CTAGGER_H - - -// SampleAnalyzer headers -#include "SampleAnalyzer/Commons/Base/TaggerBase.h" - - -namespace MA5 -{ - -class cTagger:public TaggerBase -{ -//--------------------------------------------------------------------------------- -// data members -//--------------------------------------------------------------------------------- - -//--------------------------------------------------------------------------------- -// method members -//--------------------------------------------------------------------------------- - public : - - /// Constructor without argument - cTagger() {} - - /// Destructor - virtual ~cTagger () {} - - /// Matching using dr - virtual void Method1 (SampleFormat& mySample, EventFormat& myEvent); - - /// Matching using the history - virtual void Method2 (SampleFormat& mySample, EventFormat& myEvent); - - /// Matching using a jet preselection with the history before calculating dr - virtual void Method3 (SampleFormat& mySample, EventFormat& myEvent); - - /// Matching general method - virtual void Execute(SampleFormat& mySample, EventFormat& myEvent) - { - if (Method_==1) Method1(mySample,myEvent); - else if (Method_==2) Method2(mySample,myEvent); - else if (Method_==3) Method3(mySample,myEvent); - } - - /// Is this C hadron the last in the decay chain ? - MAbool IsLastCHadron(MCParticleFormat* part, EventFormat& myEvent); - - virtual std::string GetParameters(); - -}; - -} - -#endif diff --git a/tools/SampleAnalyzer/Process/Reader/LHCOReader.cpp b/tools/SampleAnalyzer/Process/Reader/LHCOReader.cpp index aacd9603..8cc9cecd 100644 --- a/tools/SampleAnalyzer/Process/Reader/LHCOReader.cpp +++ b/tools/SampleAnalyzer/Process/Reader/LHCOReader.cpp @@ -127,12 +127,12 @@ StatusCode::Type LHCOReader::ReadEvent(EventFormat& myEvent, SampleFormat& mySam MAbool LHCOReader::FinalizeEvent(SampleFormat& mySample, EventFormat& myEvent) { // MHT & THT - for (MAuint32 i=0; ijets_.size();i++) + for (MAuint32 i=0; ijets().size();i++) { - myEvent.rec()->MHT_ -= myEvent.rec()->jets_[i].momentum(); - myEvent.rec()->THT_ += myEvent.rec()->jets_[i].pt(); - myEvent.rec()->TET_ += myEvent.rec()->jets_[i].pt(); - myEvent.rec()->Meff_+= myEvent.rec()->jets_[i].pt(); + myEvent.rec()->MHT_ -= myEvent.rec()->jets()[i].momentum(); + myEvent.rec()->THT_ += myEvent.rec()->jets()[i].pt(); + myEvent.rec()->TET_ += myEvent.rec()->jets()[i].pt(); + myEvent.rec()->Meff_+= myEvent.rec()->jets()[i].pt(); } myEvent.rec()->Meff_ += myEvent.rec()->MET_.pt(); @@ -363,8 +363,8 @@ void LHCOReader::FillEventParticleLine(const std::string& line, EventFormat& myE // 8th column : btag str >> tmp; - if ( tmp == 1. || tmp ==2.) jet->btag_=true; - else jet->btag_ =false; + if ( tmp == 1. || tmp ==2.) jet->loose_btag_=true; + else jet->loose_btag_ =false; str >> jet->HEoverEE_; } diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp index a3b6ea94..df47c49f 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.cpp @@ -1,27 +1,26 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - // STL headers #include @@ -29,151 +28,185 @@ #include "SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - using namespace MA5; /// Apply a cut MAbool RegionSelectionManager::ApplyCut(MAbool condition, std::string const &cut) { - /// Skip the cut if all regions are already failing the previous cut - if (NumberOfSurvivingRegions_==0) { return false; } - - /// Get the cut under consideration - MultiRegionCounter *mycut=0; - for(MAuint32 i=0; iGetName())==0) - { - mycut=cutmanager_.GetCuts()[i]; - break; - } - } - // Trying to apply a non-existing cut - try - { - if(mycut==0) throw EXCEPTION_WARNING("Trying to apply the non-declared cut \""+ cut + "\"","",0); - } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - return true; - } - - // Looping over all regions the cut needs to be applied - std::vector RegionsForThisCut = mycut->Regions(); - for (MAuint32 i=0; iIsSurviving() ) { continue; } - - /// Check the current cut: - if(condition) { ThisRegion->IncrementCutFlow(ThisRegion->GetWeight()); } - else - { - ThisRegion->SetSurvivingTest(false); - NumberOfSurvivingRegions_--; - if (NumberOfSurvivingRegions_==0) {return false;} - } - } - - /// If we're here, we've looped through all RegionsForThisCut and - /// NumberOfSurvivingRegions is still greater than zero, so return true. - return true; + /// Skip the cut if all regions are already failing the previous cut + if (NumberOfSurvivingRegions_ == 0) + { + return false; + } + + /// Get the cut under consideration + MultiRegionCounter *mycut = 0; + for (MAuint32 i = 0; i < cutmanager_.GetNcuts(); i++) + { + if (cut.compare(cutmanager_.GetCuts()[i]->GetName()) == 0) + { + mycut = cutmanager_.GetCuts()[i]; + break; + } + } + // Trying to apply a non-existing cut + try + { + if (mycut == 0) + throw EXCEPTION_WARNING("Trying to apply the non-declared cut \"" + cut + "\"", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return true; + } + + // Looping over all regions the cut needs to be applied + std::vector RegionsForThisCut = mycut->Regions(); + for (MAuint32 i = 0; i < RegionsForThisCut.size(); i++) + { + RegionSelection *ThisRegion = RegionsForThisCut[i]; + + /// Skip the current region if it has failed a previous cut + if (!ThisRegion->IsSurviving()) + { + continue; + } + + /// Check the current cut: + if (condition) + { + ThisRegion->IncrementCutFlow(ThisRegion->GetWeight()); + } + else + { + ThisRegion->SetSurvivingTest(false); + NumberOfSurvivingRegions_--; + if (NumberOfSurvivingRegions_ == 0) + { + return false; + } + } + } + + /// If we're here, we've looped through all RegionsForThisCut and + /// NumberOfSurvivingRegions is still greater than zero, so return true. + return true; } /// Filling an histo with a value val -void RegionSelectionManager::FillHisto(std::string const&histname, MAfloat64 val) +void RegionSelectionManager::FillHisto(std::string const &histname, MAfloat64 val) { - // Current histo - Histo *myhisto=0; - HistoFrequency *myhistof=0; - HistoLogX *myhistoX=0; - // Looping over all histos - for(MAuint32 i=0; iGetName())==0) - { - // HistoFrequency - if(dynamic_cast(plotmanager_.GetHistos()[i])!=0) - { - myhistof = dynamic_cast(plotmanager_.GetHistos()[i]); - if(myhistof->AllSurviving()==0) return; - try - { - if(myhistof->AllSurviving()==-1) throw - EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far","",0); - } - catch (const std::exception& e) { MANAGE_EXCEPTION(e); } - // Filling the histo - if (myhistof->FreshEvent()) myhistof->IncrementNEvents(weight_); - myhistof->Fill(val,weight_); - } - // LogX histo - else if(dynamic_cast(plotmanager_.GetHistos()[i])!=0) - { - myhistoX = dynamic_cast(plotmanager_.GetHistos()[i]); - if(myhistoX->AllSurviving()==0) return; - try - { - if(myhistoX->AllSurviving()==-1) throw - EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far","",0); - } - catch (const std::exception& e) { MANAGE_EXCEPTION(e); } - // Filling the histo - if (myhistoX->FreshEvent()) myhistoX->IncrementNEvents(weight_); - myhistoX->Fill(val,weight_); - } - // Normal histo - else if(dynamic_cast(plotmanager_.GetHistos()[i])!=0) - { - myhisto = dynamic_cast(plotmanager_.GetHistos()[i]); - if(myhisto->AllSurviving()==0) return; - try - { - if(myhisto->AllSurviving()==-1) throw - EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far","",0); - } - catch (const std::exception& e) { MANAGE_EXCEPTION(e); } - // Filling the histo - if (myhisto->FreshEvent()) myhisto->IncrementNEvents(weight_); - myhisto->Fill(val,weight_); - } - break; - } - } - // Trying to fill a non-existing histo - try - { - if( (myhisto==0) && (myhistof==0) && (myhistoX==0) ) throw - EXCEPTION_WARNING("Trying to fill non-declared histogram \""+ histname + "\"","",0); - } - catch (const std::exception& e) { MANAGE_EXCEPTION(e); return; } + // Current histo + Histo *myhisto = 0; + HistoFrequency *myhistof = 0; + HistoLogX *myhistoX = 0; + // Looping over all histos + for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) + { + if (histname.compare(plotmanager_.GetHistos()[i]->GetName()) == 0) + { + // HistoFrequency + if (dynamic_cast(plotmanager_.GetHistos()[i]) != 0) + { + myhistof = dynamic_cast(plotmanager_.GetHistos()[i]); + if (myhistof->AllSurviving() == 0) + return; + try + { + if (myhistof->AllSurviving() == -1) + throw EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + // Filling the histo + if (myhistof->FreshEvent()) + myhistof->IncrementNEvents(weight_); + myhistof->Fill(val, weight_); + } + // LogX histo + else if (dynamic_cast(plotmanager_.GetHistos()[i]) != 0) + { + myhistoX = dynamic_cast(plotmanager_.GetHistos()[i]); + if (myhistoX->AllSurviving() == 0) + return; + try + { + if (myhistoX->AllSurviving() == -1) + throw EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + // Filling the histo + if (myhistoX->FreshEvent()) + myhistoX->IncrementNEvents(weight_); + myhistoX->Fill(val, weight_); + } + // Normal histo + else if (dynamic_cast(plotmanager_.GetHistos()[i]) != 0) + { + myhisto = dynamic_cast(plotmanager_.GetHistos()[i]); + if (myhisto->AllSurviving() == 0) + return; + try + { + if (myhisto->AllSurviving() == -1) + throw EXCEPTION_WARNING("Filling an histogram with not all SRs surviving the cuts applied so far", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + // Filling the histo + if (myhisto->FreshEvent()) + myhisto->IncrementNEvents(weight_); + myhisto->Fill(val, weight_); + } + break; + } + } + // Trying to fill a non-existing histo + try + { + if ((myhisto == 0) && (myhistof == 0) && (myhistoX == 0)) + throw EXCEPTION_WARNING("Trying to fill non-declared histogram \"" + histname + "\"", "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + return; + } } - - -void RegionSelectionManager::WriteHistoDefinition(SAFWriter& output) +void RegionSelectionManager::WriteHistoDefinition(SAFWriter &output) { - *output.GetStream() << "" << std::endl; - for(MAuint32 i=0; iWriteDefinition(output); - *output.GetStream() << "" << std::endl << std::endl; + *output.GetStream() << "" << std::endl; + for (MAuint32 i = 0; i < regions_.size(); i++) + regions_[i]->WriteDefinition(output); + *output.GetStream() << "" << std::endl + << std::endl; } - - -void RegionSelectionManager::HeadSR(std::ostream &outwriter, const std::string &ananame) +void RegionSelectionManager::HeadSR(std::ostream &outwriter, const std::string &ananame, MAbool &is_first) { - for (MAuint32 i=0;iGetName(); -} + // Set first SR out of the for loop to avoid many if executions + // use :: instead of - since - is generally used in SR names + if (regions_.size() > 0 && is_first) + outwriter << ananame << "::" << regions_[0]->GetName(); + for (MAuint32 i = is_first ? 1 : 0; i < regions_.size(); i++) + outwriter << "," << ananame << "::" << regions_[i]->GetName(); +} -void RegionSelectionManager::DumpSR(std::ostream &outwriter) +void RegionSelectionManager::DumpSR(std::ostream &outwriter, MAbool &is_first) { - for (MAuint32 i=0;iIsSurviving(); -} + // Set first SR out of the for loop to avoid many if executions + if (regions_.size() > 0 && is_first) outwriter << regions_[0]->IsSurviving(); + for (MAuint32 i = is_first ? 1 : 0; i < regions_.size(); i++) + outwriter << "," << regions_[i]->IsSurviving(); +} diff --git a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h index b7926218..5b6ec7ac 100644 --- a/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h +++ b/tools/SampleAnalyzer/Process/RegionSelection/RegionSelectionManager.h @@ -1,31 +1,29 @@ //////////////////////////////////////////////////////////////////////////////// -// +// // Copyright (C) 2012-2023 Jack Araz, Eric Conte & Benjamin Fuks // The MadAnalysis development team, email: -// +// // This file is part of MadAnalysis 5. // Official website: -// +// // MadAnalysis 5 is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. -// +// // MadAnalysis 5 is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with MadAnalysis 5. If not, see -// +// //////////////////////////////////////////////////////////////////////////////// - #ifndef __REGIONSELECTIONMANAGER_H #define __REGIONSELECTIONMANAGER_H - // STL headers #include #include @@ -39,450 +37,472 @@ #include "SampleAnalyzer/Process/Writer/SAFWriter.h" #include "SampleAnalyzer/Commons/Service/ExceptionService.h" - namespace MA5 { -class RegionSelectionManager -{ - // ------------------------------------------------------------- - // data members - // ------------------------------------------------------------- - private: - - /// Collection of Region selections - std::vector regions_; - - /// Collection of plots that will be generated during the analysis - PlotManager plotmanager_; - - /// Collection of cuts that will be applied to the analysis - MultiRegionCounterManager cutmanager_; - - /// Index related to the number of surviving regions in an analysis - MAuint32 NumberOfSurvivingRegions_; - - /// Weight associated with the processed event - MAfloat64 weight_; - - // ------------------------------------------------------------- - // method members - // ------------------------------------------------------------- - public: - /// constructor - RegionSelectionManager() {}; - - /// Destructor - ~RegionSelectionManager() { - for(auto ®ion_pointer : regions_){ - delete region_pointer; - } - }; - - /// Reset - void Reset() - { - for (MAuint32 i=0;i Regions() - { return regions_; } - - MultiRegionCounterManager* GetCutManager() - { return &cutmanager_; } - - PlotManager* GetPlotManager() - { return &plotmanager_; } - - MAfloat64 GetCurrentEventWeight() - { return weight_; } - - /// Set method - void SetCurrentEventWeight(MAfloat64 weight) + class RegionSelectionManager { - weight_=weight; - for(MAuint16 i=0; i regions_; + + /// Collection of plots that will be generated during the analysis + PlotManager plotmanager_; + + /// Collection of cuts that will be applied to the analysis + MultiRegionCounterManager cutmanager_; + + /// Index related to the number of surviving regions in an analysis + MAuint32 NumberOfSurvivingRegions_; + + /// Weight associated with the processed event + MAfloat64 weight_; + + // ------------------------------------------------------------- + // method members + // ------------------------------------------------------------- + public: + /// constructor + RegionSelectionManager(){}; + + /// Destructor + ~RegionSelectionManager() { - regions_[i]->SetWeight(weight); - } - } + for (auto ®ion_pointer : regions_) + { + delete region_pointer; + } + }; - /// Set method - void SetRegionWeight(std::string name, MAfloat64 weight) + /// Reset + void Reset() { - for(MAuint16 i=0; iGetName() == name) {regions_[i]->SetWeight(weight); break;} + if (regions_[i] != 0) + delete regions_[i]; } + regions_.clear(); + cutmanager_.Finalize(); + plotmanager_.Finalize(); } - /// Adding a RegionSelection to the manager - void AddRegionSelection(const std::string& name) - { - std::string myname=name; - if(myname.compare("")==0) + /// Finalizing + void Finalize() { Reset(); } + + /// Get methods + std::vector Regions() { - std::stringstream numstream; - numstream << regions_.size(); - myname = "RegionSelection" + numstream.str(); + return regions_; } - RegionSelection* myregion = new RegionSelection(name); - regions_.push_back(myregion); - } - /// Getting ready for a new event - void InitializeForNewEvent(MAfloat64 EventWeight) - { - weight_ = EventWeight; - NumberOfSurvivingRegions_ = regions_.size(); - for (MAuint32 i=0; iInitializeForNewEvent(EventWeight); - for (MAuint32 i=0; i < plotmanager_.GetNplots(); i++) - plotmanager_.GetHistos()[i]->SetFreshEvent(true); - } - - /// This method associates all regions with a cut - void AddCut(const std::string&name) - { - // The name of the cut - std::string myname=name; - if(myname.compare("")==0) + MultiRegionCounterManager *GetCutManager() { - std::stringstream numstream; - numstream << cutmanager_.GetCuts().size(); - myname = "Cut" + numstream.str(); + return &cutmanager_; } - // Adding the cut to all the regions - cutmanager_.AddCut(myname,regions_); - } - - - /// This method associates one single region with a cut - void AddCut(const std::string&name, const std::string &RSname) - { - std::string RSnameA[] = {RSname}; - AddCut(name, RSnameA); - } + PlotManager *GetPlotManager() + { + return &plotmanager_; + } + MAfloat64 GetCurrentEventWeight() + { + return weight_; + } - /// this method associates an arbitrary number of RS with a cut - template void AddCut(const std::string&name, std::string const(&RSnames)[NRS]) - { - // The name of the cut - std::string myname=name; - if(myname.compare("")==0) + /// Set method + void SetCurrentEventWeight(MAfloat64 weight) { - std::stringstream numstream; - numstream << cutmanager_.GetCuts().size(); - myname = "Cut" + numstream.str(); + weight_ = weight; + for (MAuint16 i = 0; i < regions_.size(); i++) + { + regions_[i]->SetWeight(weight); + } } - // Creating the vector of SR of interests - std::vector myregions; - for(MAuint32 i=0; iGetName().compare(RSnames[i])==0) + if (regions_[i]->GetName() == name) { - myregions.push_back(regions_[j]); + regions_[i]->SetWeight(weight); break; } } - - try + } + + /// Adding a RegionSelection to the manager + void AddRegionSelection(const std::string &name) + { + std::string myname = name; + if (myname.compare("") == 0) { - if (myregions.size()==i) throw EXCEPTION_WARNING("Assigning the cut \"" + name + - "\" to the non-existing signal region \"" + RSnames[i] + - "\"","",0); + std::stringstream numstream; + numstream << regions_.size(); + myname = "RegionSelection" + numstream.str(); } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - } + RegionSelection *myregion = new RegionSelection(name); + regions_.push_back(myregion); } - // Creating the cut - cutmanager_.AddCut(myname,myregions); - } + /// Getting ready for a new event + void InitializeForNewEvent(MAfloat64 EventWeight) + { + weight_ = EventWeight; + NumberOfSurvivingRegions_ = regions_.size(); + for (MAuint32 i = 0; i < regions_.size(); i++) + regions_[i]->InitializeForNewEvent(EventWeight); + for (MAuint32 i = 0; i < plotmanager_.GetNplots(); i++) + plotmanager_.GetHistos()[i]->SetFreshEvent(true); + } + /// This method associates all regions with a cut + void AddCut(const std::string &name) + { + // The name of the cut + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << cutmanager_.GetCuts().size(); + myname = "Cut" + numstream.str(); + } + // Adding the cut to all the regions + cutmanager_.AddCut(myname, regions_); + } - void AddCut(const std::string&name, std::vector SRnames) - { - // The name of the cut - std::string myname=name; - if(myname.compare("")==0) + /// This method associates one single region with a cut + void AddCut(const std::string &name, const std::string &RSname) { - std::stringstream numstream; - numstream << cutmanager_.GetCuts().size(); - myname = "Cut" + numstream.str(); + std::string RSnameA[] = {RSname}; + AddCut(name, RSnameA); } - // Creating the vector of SR of interests - std::vector myregions; - for(MAuint32 i=0; i + void AddCut(const std::string &name, std::string const (&RSnames)[NRS]) { - for(MAuint32 j=0; jGetName().compare(SRnames[i])==0) - { - myregions.push_back(regions_[j]); - break; - } + std::stringstream numstream; + numstream << cutmanager_.GetCuts().size(); + myname = "Cut" + numstream.str(); } - try + // Creating the vector of SR of interests + std::vector myregions; + for (MAuint32 i = 0; i < NRS; i++) { - if (myregions.size()==i) throw EXCEPTION_WARNING("Assigning the cut \"" + name + - "\" to the non-existing signal region \"" + SRnames[i] + - "\"","",0); + for (MAuint32 j = 0; j < regions_.size(); j++) + { + if (regions_[j]->GetName().compare(RSnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } + + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the cut \"" + name + + "\" to the non-existing signal region \"" + RSnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } } - catch (const std::exception& e) + + // Creating the cut + cutmanager_.AddCut(myname, myregions); + } + + void AddCut(const std::string &name, std::vector SRnames) + { + // The name of the cut + std::string myname = name; + if (myname.compare("") == 0) { - MANAGE_EXCEPTION(e); + std::stringstream numstream; + numstream << cutmanager_.GetCuts().size(); + myname = "Cut" + numstream.str(); } - } - // Creating the cut - cutmanager_.AddCut(myname,myregions); + // Creating the vector of SR of interests + std::vector myregions; + for (MAuint32 i = 0; i < SRnames.size(); i++) + { + for (MAuint32 j = 0; j < regions_.size(); j++) + { + if (regions_[j]->GetName().compare(SRnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } - } + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the cut \"" + name + + "\" to the non-existing signal region \"" + SRnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } + } + // Creating the cut + cutmanager_.AddCut(myname, myregions); + } - /// Apply a cut - MAbool ApplyCut(MAbool, std::string const&); + /// Apply a cut + MAbool ApplyCut(MAbool, std::string const &); - /// This method associates all signal regions with an histo - void AddHistoFrequency(const std::string&name) - { - // The name of the histo - std::string myname=name; - if(myname.compare("")==0) + /// This method associates all signal regions with an histo + void AddHistoFrequency(const std::string &name) { - std::stringstream numstream; - numstream << plotmanager_.GetHistos().size(); - myname = "Histo" + numstream.str(); + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << plotmanager_.GetHistos().size(); + myname = "Histo" + numstream.str(); + } + // Adding the histo and linking all regions to the histo + plotmanager_.Add_HistoFrequency(myname, regions_); } - // Adding the histo and linking all regions to the histo - plotmanager_.Add_HistoFrequency(myname,regions_); - } - /// This method associates all signal regions with an histo - void AddHisto(const std::string&name,MAuint32 nb,MAfloat64 xmin,MAfloat64 xmax) - { - // The name of the histo - std::string myname=name; - if(myname.compare("")==0) + /// This method associates all signal regions with an histo + void AddHisto(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax) { - std::stringstream numstream; - numstream << plotmanager_.GetHistos().size(); - myname = "Histo" + numstream.str(); + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << plotmanager_.GetHistos().size(); + myname = "Histo" + numstream.str(); + } + // Adding the histo and linking all regions to the histo + plotmanager_.Add_Histo(myname, nb, xmin, xmax, regions_); } - // Adding the histo and linking all regions to the histo - plotmanager_.Add_Histo(myname,nb,xmin,xmax,regions_); - } - /// This method associates all signal regions with an histo - void AddHistoLogX(const std::string&name,MAuint32 nb,MAfloat64 xmin,MAfloat64 xmax) - { - // The name of the histo - std::string myname=name; - if(myname.compare("")==0) + /// This method associates all signal regions with an histo + void AddHistoLogX(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax) { - std::stringstream numstream; - numstream << plotmanager_.GetHistos().size(); - myname = "Histo" + numstream.str(); + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) + { + std::stringstream numstream; + numstream << plotmanager_.GetHistos().size(); + myname = "Histo" + numstream.str(); + } + // Adding the histo and linking all regions to the histo + plotmanager_.Add_HistoLogX(myname, nb, xmin, xmax, regions_); } - // Adding the histo and linking all regions to the histo - plotmanager_.Add_HistoLogX(myname,nb,xmin,xmax,regions_); - } - /// This method associates one single signal region with an histo - void AddHisto(const std::string&name,MAuint32 nb,MAfloat64 xmin,MAfloat64 xmax, - const std::string &RSname) - { - std::string RSnameA[] = {RSname}; - AddHisto(name, nb, xmin, xmax, RSnameA); - } - - /// This method associates one single signal region with an histo - void AddHistoLogX(const std::string&name,MAuint32 nb,MAfloat64 xmin,MAfloat64 xmax, - const std::string &RSname) - { - std::string RSnameA[] = {RSname}; - AddHistoLogX(name, nb, xmin, xmax, RSnameA); - } - /// This method associates one single signal region with an histo - void AddHistoFrequency(const std::string&name, const std::string &RSname) - { - std::string RSnameA[] = {RSname}; - AddHistoFrequency(name, RSnameA); - } + /// This method associates one single signal region with an histo + void AddHisto(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax, + const std::string &RSname) + { + std::string RSnameA[] = {RSname}; + AddHisto(name, nb, xmin, xmax, RSnameA); + } - /// this method associates an arbitrary number of RS with an histo - template void AddHisto(const std::string&name, MAuint32 nb, - MAfloat64 xmin,MAfloat64 xmax, std::string const(&RSnames)[NRS]) - { - // The name of the histo - std::string myname=name; - if(myname.compare("")==0) + /// This method associates one single signal region with an histo + void AddHistoLogX(const std::string &name, MAuint32 nb, MAfloat64 xmin, MAfloat64 xmax, + const std::string &RSname) { - std::stringstream numstream; - numstream << plotmanager_.GetNplots(); - myname = "Histo" + numstream.str(); + std::string RSnameA[] = {RSname}; + AddHistoLogX(name, nb, xmin, xmax, RSnameA); } - // Creating the vector of SR of interests - std::vector myregions; - for(MAuint32 i=0; iGetName().compare(RSnames[i])==0) - { - myregions.push_back(regions_[j]); - break; - } - } - try + std::string RSnameA[] = {RSname}; + AddHistoFrequency(name, RSnameA); + } + + /// this method associates an arbitrary number of RS with an histo + template + void AddHisto(const std::string &name, MAuint32 nb, + MAfloat64 xmin, MAfloat64 xmax, std::string const (&RSnames)[NRS]) + { + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) { - if (myregions.size()==i) throw EXCEPTION_WARNING("Assigning the histo \"" + name + - "\" to the non-existing signal region \"" + RSnames[i] + - "\"","",0); + std::stringstream numstream; + numstream << plotmanager_.GetNplots(); + myname = "Histo" + numstream.str(); } - catch (const std::exception& e) + // Creating the vector of SR of interests + std::vector myregions; + for (MAuint32 i = 0; i < NRS; i++) { - MANAGE_EXCEPTION(e); + for (MAuint32 j = 0; j < regions_.size(); j++) + { + if (regions_[j]->GetName().compare(RSnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the histo \"" + name + + "\" to the non-existing signal region \"" + RSnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } } - } - - // Creating the histo - plotmanager_.Add_Histo(myname, nb, xmin, xmax,myregions); - } - - /// this method associates an arbitrary number of RS with an histo - template void AddHistoLogX(const std::string&name, MAuint32 nb, - MAfloat64 xmin,MAfloat64 xmax, std::string const(&RSnames)[NRS]) - { - // The name of the histo - std::string myname=name; - if(myname.compare("")==0) - { - std::stringstream numstream; - numstream << plotmanager_.GetNplots(); - myname = "Histo" + numstream.str(); + // Creating the histo + plotmanager_.Add_Histo(myname, nb, xmin, xmax, myregions); } - // Creating the vector of SR of interests - std::vector myregions; - for(MAuint32 i=0; i + void AddHistoLogX(const std::string &name, MAuint32 nb, + MAfloat64 xmin, MAfloat64 xmax, std::string const (&RSnames)[NRS]) { - for(MAuint32 j=0; j myregions; + for (MAuint32 i = 0; i < NRS; i++) { - if(regions_[j]->GetName().compare(RSnames[i])==0) + for (MAuint32 j = 0; j < regions_.size(); j++) { - myregions.push_back(regions_[j]); - break; + if (regions_[j]->GetName().compare(RSnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the histo \"" + name + + "\" to the non-existing signal region \"" + RSnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); } } - try + + // Creating the histo + plotmanager_.Add_HistoLogX(myname, nb, xmin, xmax, myregions); + } + + /// this method associates an arbitrary number of RS with an histo + template + void AddHistoFrequency(const std::string &name, std::string const (&RSnames)[NRS]) + { + // The name of the histo + std::string myname = name; + if (myname.compare("") == 0) { - if (myregions.size()==i) throw EXCEPTION_WARNING("Assigning the histo \"" + name + - "\" to the non-existing signal region \"" + RSnames[i] + - "\"","",0); + std::stringstream numstream; + numstream << plotmanager_.GetNplots(); + myname = "Histo" + numstream.str(); } - catch (const std::exception& e) + // Creating the vector of SR of interests + std::vector myregions; + for (MAuint32 i = 0; i < NRS; i++) { - MANAGE_EXCEPTION(e); + for (MAuint32 j = 0; j < regions_.size(); j++) + { + if (regions_[j]->GetName().compare(RSnames[i]) == 0) + { + myregions.push_back(regions_[j]); + break; + } + } + try + { + if (myregions.size() == i) + throw EXCEPTION_WARNING("Assigning the histo \"" + name + + "\" to the non-existing signal region \"" + RSnames[i] + + "\"", + "", 0); + } + catch (const std::exception &e) + { + MANAGE_EXCEPTION(e); + } } + + // Creating the histo + plotmanager_.Add_HistoFrequency(myname, myregions); } - // Creating the histo - plotmanager_.Add_HistoLogX(myname, nb, xmin, xmax,myregions); - } + /// Filling an histo with a value val + void FillHisto(std::string const &, MAfloat64 val); - /// this method associates an arbitrary number of RS with an histo - template void AddHistoFrequency(const std::string&name, std::string const(&RSnames)[NRS]) - { - // The name of the histo - std::string myname=name; - if(myname.compare("")==0) - { - std::stringstream numstream; - numstream << plotmanager_.GetNplots(); - myname = "Histo" + numstream.str(); - } - // Creating the vector of SR of interests - std::vector myregions; - for(MAuint32 i=0; iGetName().compare(RSnames[i])==0) - { - myregions.push_back(regions_[j]); - break; - } + if (regions_[i]->GetName().compare(RSname) == 0) + return regions_[i]->IsSurviving(); } + + // The region has not been found try { - if (myregions.size()==i) throw EXCEPTION_WARNING("Assigning the histo \"" + name + - "\" to the non-existing signal region \"" + RSnames[i] + - "\"","",0); + throw EXCEPTION_WARNING("Checking whether the non-declared region \"" + + RSname + "\" is surviving the applied cuts.", + "", 0); } - catch (const std::exception& e) + catch (const std::exception &e) { MANAGE_EXCEPTION(e); } - } - - // Creating the histo - plotmanager_.Add_HistoFrequency(myname,myregions); - } - - /// Filling an histo with a value val - void FillHisto(std::string const&, MAfloat64 val); - - /// Writing the definition saf file - void WriteHistoDefinition(SAFWriter& output); - /// Checking if a given RS is surviging - MAbool IsSurviving(const std::string &RSname) - { - // Looking for the region and checking its status - for(MAuint32 i=0; iGetName().compare(RSname) == 0) - return regions_[i]->IsSurviving(); - } - - // The region has not been found - try - { - throw EXCEPTION_WARNING("Checking whether the non-declared region \"" + - RSname + "\" is surviving the applied cuts.","",0); + return false; } - catch (const std::exception& e) - { - MANAGE_EXCEPTION(e); - } - - return false; - } - /// Dumping the content of the counters - void HeadSR(std::ostream &, const std::string&); - void DumpSR(std::ostream &); - -}; + /// Dumping the content of the counters + void HeadSR(std::ostream &, const std::string &, MAbool &); + void DumpSR(std::ostream &, MAbool &); + }; } #endif diff --git a/tools/SampleAnalyzer/Test/HEPTopTagger/Test.cpp b/tools/SampleAnalyzer/Test/HEPTopTagger/Test.cpp new file mode 100644 index 00000000..2f8d4774 --- /dev/null +++ b/tools/SampleAnalyzer/Test/HEPTopTagger/Test.cpp @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +/// STL headers +#include +#include + +#define EPSILON 1E-3 + +/// Fastjet headers +#include "fastjet/PseudoJet.hh" +#include "fastjet/ClusterSequence.hh" + +/// SampleAnalyzer headers +#include "SampleAnalyzer/Interfaces/HEPTopTagger/HTT.h" + +using namespace MA5; + +// ----------------------------------------------------------------------- +// main program +// ----------------------------------------------------------------------- +int main(int argc, char *argv[]) +{ + std::cout << "BEGIN-SAMPLEANALYZER-TEST" << std::endl; + + /// Collect data + std::ifstream fin("../Test/Substructure/input.dat",std::ifstream::in); + std::vector input_clusters; + + while(!fin.eof()){ + double x,y,z,e; + fastjet::PseudoJet p; + fin >> x >> y >> z >> e; + if(!fin.eof()){ + p.reset(x/1000., y/1000., z/1000., e/1000.); + input_clusters.push_back(p); + } + } + std::cout << " * ReadEvent: " << input_clusters.size() << " particles are read." << std::endl; + + // jet definition + fastjet::JetDefinition jet_def(fastjet::cambridge_algorithm,1.5); + fastjet::ClusterSequence clust_seq(input_clusters, jet_def); + std::vector jets = sorted_by_pt(clust_seq.inclusive_jets(200.)); + + std::vector Ma5Jet; + Ma5Jet.reserve(jets.size()); + for (auto &jet: jets) + { + RecJetFormat* current_jet = new RecJetFormat(jet); + Ma5Jet.push_back(current_jet); + } + + std::cout << " * TESTING HEPTOPTAGGER" << std::endl; + MA5::Substructure::HTT tagger; + MA5::Substructure::HTT::InputParameters param; + param.max_subjet = 30.; + param.mass_drop = 0.8; + param.filtering_R = 0.3; + param.filt_N = 5; + param.filtering_minpt = 30.; + param.mode = Substructure::HTT::TWO_STEP_FILTER; + tagger.Initialize(param); + tagger.get_settings(); + + tagger.Execute(Ma5Jet[1]); + if (tagger.is_tagged()){ + std::cout << " * Input fatjet: pT = " << Ma5Jet[1]->pt() << std::endl; + std::cout << " * Output: pT = " << tagger.top()->pt() + << " Mass = " << tagger.top()->m() << std::endl; + assert(std::fabs(tagger.top()->m() - 177.188) < EPSILON); + } + std::cout << " * HEPTOPTAGGER PASSED " << std::endl; + + std::cout << "END-SAMPLEANALYZER-TEST" << std::endl; + return 0; +} diff --git a/tools/SampleAnalyzer/Test/Substructure/Test.cpp b/tools/SampleAnalyzer/Test/Substructure/Test.cpp new file mode 100644 index 00000000..9b381179 --- /dev/null +++ b/tools/SampleAnalyzer/Test/Substructure/Test.cpp @@ -0,0 +1,112 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2012-2022 Jack Araz, Eric Conte & Benjamin Fuks +// The MadAnalysis development team, email: +// +// This file is part of MadAnalysis 5. +// Official website: +// +// MadAnalysis 5 is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// MadAnalysis 5 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with MadAnalysis 5. If not, see +// +//////////////////////////////////////////////////////////////////////////////// + +/// STL headers +#include +#include + +#define EPSILON 1E-3 + +/// Fastjet headers +#include "fastjet/PseudoJet.hh" +#include "fastjet/ClusterSequence.hh" + +/// SampleAnalyzer headers +#include "SampleAnalyzer/Interfaces/substructure/ClusterBase.h" +#include "SampleAnalyzer/Commons/DataFormat/RecJetFormat.h" +#include "SampleAnalyzer/Interfaces/substructure/SoftDrop.h" +#include "SampleAnalyzer/Interfaces/substructure/Filter.h" +#include "SampleAnalyzer/Interfaces/substructure/EnergyCorrelator.h" +#include "SampleAnalyzer/Interfaces/substructure/Nsubjettiness.h" + +using namespace MA5; + +int main(int argc, char *argv[]) +{ + std::cout << "BEGIN-SAMPLEANALYZER-TEST" << std::endl; + /// Collect data + std::ifstream fin("../Test/Substructure/input.dat",std::ifstream::in); + std::vector input_clusters; + + while(!fin.eof()){ + double x,y,z,e; + fastjet::PseudoJet p; + fin >> x >> y >> z >> e; + if(!fin.eof()){ + p.reset(x/1000., y/1000., z/1000., e/1000.); + input_clusters.push_back(p); + } + } + std::cout << " * ReadEvent: " << input_clusters.size() << " particles are read." << std::endl; + + // jet definition + fastjet::JetDefinition jet_def(fastjet::cambridge_algorithm,1.5); + fastjet::ClusterSequence clust_seq(input_clusters, jet_def); + std::vector jets = sorted_by_pt(clust_seq.inclusive_jets(200.)); + + std::vector Ma5Jet; + Ma5Jet.reserve(jets.size()); + for (auto &jet: jets) + { + RecJetFormat* current_jet = new RecJetFormat(jet); + Ma5Jet.push_back(current_jet); + } + + /// Test Soft Drop + std::cout << " * TESTING SOFTDROP" << std::endl; + Substructure::SoftDrop softDrop; + softDrop.Initialize(2.0, 0.1); + const RecJetFormat * softdrop_jet = softDrop.Execute(Ma5Jet[0]); + double sn = softdrop_jet->m(); + assert(std::fabs(24.8832 - sn) < EPSILON); + std::cout << " * SOFTDROP PASSED" << std::endl; + + /// Test Jet Filtering + std::cout << " * TESTING JET FILTERING" << std::endl; + Substructure::Filter jetFiltering; + jetFiltering.Initialize(0.2, Substructure::SelectorPtFractionMin(0.03)); + const RecJetFormat * filteredJet = jetFiltering.Execute(Ma5Jet[0]); + assert(std::fabs(389.646 - filteredJet->pt()) < EPSILON); + std::cout << " * JET FILTERING PASSED" << std::endl; + + /// Test Energy Correlator + std::cout << " * TESTING ENERGY CORRELATOR" << std::endl; + Substructure::EnergyCorrelator EC; + EC.Initialize(1, 0.1, Substructure::EnergyCorrelator::Measure::pt_R, + Substructure::EnergyCorrelator::Strategy::storage_array); + double ec = EC.Execute(Ma5Jet[0]); + assert(std::fabs(438.954 - ec) < EPSILON); + std::cout << " * ENERGY CORRELATOR PASSED " << std::endl; + + /// Test Nsubjettiness + std::cout << " * TESTING NSUBJETTINESS" << std::endl; + Substructure::Nsubjettiness nsub; + nsub.Initialize(1,Substructure::Nsubjettiness::KT_Axes, + Substructure::Nsubjettiness::NormalizedMeasure, 0.1, 0.2); + double tau1 = nsub.Execute(Ma5Jet[0]); + assert(std::fabs(0.916149 - tau1) < EPSILON); + std::cout << " * NSUBJETTINESS PASSED " << std::endl; + + std::cout << "END-SAMPLEANALYZER-TEST" << std::endl; + return 0; +} diff --git a/tools/SampleAnalyzer/Test/Substructure/input.dat b/tools/SampleAnalyzer/Test/Substructure/input.dat new file mode 100644 index 00000000..fe164801 --- /dev/null +++ b/tools/SampleAnalyzer/Test/Substructure/input.dat @@ -0,0 +1,487 @@ +-262828.28125 -37260.6914062 384220.0625 467003.34375 +91748.5859375 -27.1914653778 -307108.8125 320520.875 +49375.2070312 31864.6445312 -289290.25 295198.4375 +-56361.40625 -9070.01269531 87140.8359375 104174.84375 +-38652.3828125 -9321.82910156 52296.1054688 65694.640625 +27339.0273438 -803.389892578 -92703.5078125 96654.0625 +-26921.8417969 -428.954956055 37357.5664062 46049.5078125 +20283.6035156 15317.3222656 -125727.453125 128270.953125 +11743.2900391 10041.6083984 -62235.0117188 64124.375 +12284.4560547 4137.37011719 -20377.8066406 24151.2050781 +12948.5683594 3389.88183594 -22987.4921875 26600.4042969 +8350.02148438 6227.83154297 -54209.8945312 55201.6445312 +12593.4316406 2621.63623047 -17925.65625 22063.46875 +8381.69042969 5947.32861328 -44970.9453125 46130.3515625 +8744.58789062 10235.875 -12780.5859375 18562.9824219 +10077.0 2011.40698242 -13120.5322266 16665.5351562 +7958.91552734 -304.003234863 -27919.90625 29033.7382812 +5247.63671875 5161.31152344 -26414.5761719 27420.9160156 +-5823.84423828 -4992.96630859 -42936.3984375 43616.296875 +7877.40722656 3169.27709961 -12834.9238281 15389.3837891 +9008.80859375 1094.70837402 -14217.6708984 16867.1035156 +6030.64404297 4830.66845703 -27466.8945312 28533.0390625 +7088.68164062 -1248.40454102 -24956.8691406 25974.0878906 +-5385.23876953 -4034.65014648 -41866.0351562 42403.3515625 +-5953.47314453 -818.315734863 11296.3476562 12795.3486328 +-6033.20166016 2157.71728516 -11531.7246094 13192.2685547 +2813.2199707 4162.75683594 -5983.00830078 7812.75488281 +-3796.89697266 -2010.4954834 -23267.8339844 23661.1621094 +-3449.09790039 -1948.15405273 -26755.5195312 27047.1699219 +2825.33569336 3332.71801758 -39253.1054688 39495.515625 +-704.811889648 -3554.98388672 4685.0703125 5923.22167969 +1787.67114258 3390.96850586 -30731.9589844 30970.1113281 +2822.04589844 1908.34851074 -4727.93066406 5827.44091797 +-2718.5065918 -1361.89526367 -17808.9648438 18066.6621094 +2314.6706543 2173.609375 -23550.4609375 23763.5546875 +2079.96191406 1817.25952148 -13189.3427734 13475.4384766 +-3139.3605957 -359.250671387 -21060.9414062 21296.6640625 +2381.96313477 -1837.50708008 -1978.39282227 3600.5859375 +-2215.61645508 -2164.63720703 -5743.60400391 6525.61083984 +2028.18005371 -2506.23217773 1749.79455566 3668.30957031 +2217.0690918 2310.91259766 -25428.984375 25629.8457031 +-981.927062988 -2704.92260742 -5464.68798828 6176.05078125 +600.509643555 3844.10693359 -6967.27539062 7980.01855469 +704.931640625 2972.93164062 -7098.66845703 7728.28222656 +2085.75830078 1349.60131836 28900.1816406 29006.7636719 +1915.98986816 916.612670898 -7508.51025391 7803.13525391 +2094.40600586 232.242874146 -13610.8945312 13773.0507812 +1526.36010742 1242.13476562 -7716.13769531 7963.13085938 +-2746.13793945 88.2766647339 -18135.4335938 18342.3828125 +2191.77661133 552.271057129 1168.96289062 2544.67333984 +255.844009399 -3903.72094727 2934.05859375 4890.11181641 +1913.65844727 898.008178711 -13810.4902344 13971.3330078 +1621.09521484 1574.62231445 -11646.4091797 11863.6513672 +2223.62207031 570.982849121 -5756.26855469 6197.18847656 +-522.127258301 -2244.05273438 3040.63769531 3814.953125 +-174.492858887 -3164.26489258 -817.360229492 3272.78125 +1614.54602051 722.862976074 -5324.75439453 5610.90917969 +938.118774414 1266.47949219 2650.36450195 3083.58056641 +312.832977295 1838.39990234 -2887.26757812 3437.13427734 +2097.16943359 -178.851150513 -3859.69067383 4396.28466797 +462.524047852 1668.72412109 -48369.1914062 48400.1796875 +1763.11669922 -100.443534851 -7347.39160156 7556.64160156 +-2007.359375 -1439.74328613 -14646.8828125 14853.7382812 +-1491.56774902 -2015.51147461 -27279.4179688 27394.4101562 +-250.73765564 1558.46508789 -11323.9423828 11433.4316406 +-820.134094238 -1374.69604492 -7668.22949219 7833.52734375 +-1485.52844238 -1044.64208984 -10141.0625 10302.3886719 +1736.36889648 780.41595459 -7111.36132812 7361.75830078 +564.364501953 2735.49438477 -3625.45092773 4576.60693359 +1132.23474121 1322.04504395 -6660.22607422 6883.92089844 +-1198.35314941 1567.47412109 3504.90332031 4022.1105957 +-1329.75085449 -517.757507324 -8186.36132812 8309.80273438 +162.938156128 -2149.66577148 1266.98266602 2500.57128906 +318.917999268 1652.02612305 -711.65222168 1826.84094238 +-1373.86242676 -504.761016846 -6853.77734375 7008.31982422 +-538.830505371 -1113.89794922 175.269561768 1249.73046875 +-1525.13366699 -1239.56445312 20253.0859375 20348.21875 +1436.31091309 -1275.0567627 825.262207031 2090.41064453 +-1260.11132812 -343.291564941 -7511.16552734 7623.86621094 +806.304260254 1052.7734375 -6650.68603516 6781.59863281 +-845.054504395 -339.39730835 312.721160889 962.861450195 +1310.94665527 -562.239746094 -1123.6862793 1815.86499023 +-1415.40917969 -480.199432373 471.943450928 1567.38806152 +871.563781738 1207.51098633 690.198608398 1641.36535645 +1038.77307129 951.005249023 993.350524902 1723.4284668 +1192.66125488 223.306976318 30405.125 30429.3261719 +1617.2479248 109.64969635 -3562.63891602 3914.06567383 +1270.22314453 1107.73010254 2815.06884766 3281.02807617 +482.555938721 -1518.50341797 -18428.8730469 18497.6230469 +438.629180908 1399.40026855 6344.6796875 6511.96435547 +995.477294922 1118.9453125 -2744.21826172 3126.29931641 +822.610168457 912.888305664 879.369628906 1511.0736084 +849.860778809 -522.42376709 -477.870422363 1106.14196777 +887.648376465 1082.79089355 -2830.91870117 3158.23632812 +-863.762634277 -559.446044922 -644.490783691 1214.26281738 +-611.824768066 -789.309875488 651.943786621 1192.63171387 +872.105895996 1260.16955566 -3333.99682617 3669.35009766 +-458.224487305 -1236.43591309 -9177.515625 9271.75976562 +49.6180877686 1512.18591309 -1691.99401855 2269.80444336 +-529.809936523 -1684.52746582 -20542.5351562 20618.2949219 +-382.146606445 -1297.02770996 946.741149902 1650.64709473 +-846.894958496 779.324035645 802.80670166 1403.23754883 +-1020.53814697 -465.639007568 79.17628479 1124.53845215 +-541.511291504 -756.554626465 -33.6217536926 930.988647461 +-601.907958984 918.814025879 1657.37524414 1988.31713867 +-284.526245117 -790.704650879 459.430664062 957.729370117 +-1179.81591797 174.548751831 -1288.37561035 1755.66064453 +-372.674224854 1065.50354004 -937.564025879 1467.38208008 +-641.194702148 1292.24365234 8523.02539062 8644.24609375 +-1329.95727539 474.188293457 -2533.83496094 2900.68286133 +-774.682983398 -693.28894043 1207.16540527 1593.12011719 +-173.357635498 -1362.89648438 -6724.88134766 6863.78662109 +923.385009766 -447.741119385 1435.65075684 1764.71105957 +-131.506134033 -1240.15856934 -1371.10131836 1853.4309082 +152.407089233 1024.84313965 -4442.35107422 4561.58007812 +-388.034667969 -1743.34667969 -4857.14892578 5175.10644531 +28.8218517303 827.351989746 611.513244629 1029.21838379 +-713.239257812 -535.20300293 -603.27545166 1076.61218262 +408.54196167 -1047.60595703 2223.99169922 2492.09228516 +-536.688293457 581.162963867 447.101898193 908.67199707 +-538.630065918 778.856384277 4092.98364258 4201.1015625 +1298.83300781 261.48348999 -7382.58203125 7500.52392578 +296.064178467 490.221160889 -814.047180176 995.310791016 +-650.196838379 -914.89440918 6232.91210938 6333.16503906 +-525.977172852 504.729675293 317.242828369 795.01385498 +735.250549316 -213.968917847 83.1222686768 770.250183105 +-890.990905762 -420.830627441 83.0220413208 988.865966797 +783.354309082 -245.334060669 -2967.29418945 3078.74438477 +734.996337891 -875.291381836 -6173.00585938 6277.92626953 +1010.52886963 -133.647521973 -4768.70410156 4876.43017578 +-589.18182373 -1015.94714355 -3689.71875 3872.11938477 +492.598022461 -551.046691895 161.226623535 756.504638672 +952.441467285 -208.858718872 1017.33483887 1409.16174316 +587.325561523 -553.907165527 -282.663391113 855.373046875 +-517.000732422 817.67565918 5933.26708984 6011.6171875 +426.454437256 539.410827637 -516.087890625 859.752380371 +-53.6471290588 -819.964416504 777.189025879 1131.03601074 +727.422729492 345.823547363 -567.226867676 985.131469727 +308.830718994 -1019.74041748 -4115.98193359 4251.65332031 +-1198.95483398 -86.7623596191 -4723.87841797 4874.42773438 +517.332763672 867.619873047 -4177.671875 4298.0625 +-668.43145752 735.75378418 4155.03076172 4272.28466797 +834.549743652 -118.977394104 -2343.74291992 2490.73486328 +573.262023926 -397.155883789 -305.467834473 761.362426758 +823.065307617 -465.268920898 1062.48510742 1422.24694824 +344.761657715 314.649261475 -613.287109375 770.704772949 +334.78237915 -991.119628906 2778.61816406 2969.02612305 +503.9140625 79.8409805298 -188.871566772 544.03717041 +900.073974609 -425.625366211 -1177.66235352 1542.13452148 +815.48638916 147.437774658 -222.811889648 858.138122559 +200.588439941 730.981933594 700.556762695 1032.15795898 +699.409973145 -31.4416770935 -3636.48291016 3703.26489258 +-561.655639648 272.765411377 360.038879395 720.75378418 +-67.3348236084 1097.43554688 -2401.57910156 2641.30297852 +455.367797852 -957.807006836 3556.61816406 3711.37255859 +-267.922607422 -348.292541504 234.385818481 498.023010254 +516.044921875 -308.130828857 -106.130371094 610.336486816 +938.558349609 -128.904434204 -5032.88183594 5121.27001953 +-638.60925293 210.899688721 -215.054443359 706.079956055 +-431.378997803 912.12097168 -2317.87646484 2527.96435547 +421.531524658 -379.098175049 -124.144950867 580.358703613 +832.04901123 310.176757812 -2575.70019531 2724.47192383 +523.560852051 477.808563232 -1087.71936035 1298.28747559 +146.527374268 729.412597656 -858.203613281 1135.79333496 +236.483352661 317.019256592 271.149993896 479.528839111 +626.035339355 -277.622253418 167.327728271 704.977233887 +-237.485610962 -597.302490234 379.810211182 746.609313965 +-415.548339844 49.4954338074 588.368225098 722.016174316 +-767.734863281 -124.035804749 -4185.78417969 4257.41601562 +-376.712036133 -28.4294128418 22143.0078125 22146.2304688 +-1466.69152832 362.372497559 -17770.0761719 17834.1835938 +-35.7425804138 -602.385925293 468.195983887 763.776000977 +118.548225403 667.631713867 -362.680389404 768.975219727 +-810.63092041 -0.766242802143 -4476.29492188 4549.10302734 +760.559082031 37.2016944885 -2249.82788086 2375.19677734 +-673.293029785 246.188217163 1015.38427734 1242.95507812 +-615.966796875 -141.921203613 -795.820983887 1016.31085205 +-625.619750977 -94.9657592773 545.519104004 835.469726562 +-674.986083984 -60.0000457764 -2100.16357422 2206.78344727 +-983.894714355 -189.238250732 5618.57324219 5707.20800781 +-462.86038208 628.733886719 -977.716369629 1251.1895752 +-681.070556641 406.60559082 -4293.76806641 4366.42089844 +388.348693848 -380.472320557 -305.118011475 623.434753418 +-791.956054688 334.706115723 -3534.76953125 3637.83154297 +-60.0955429077 386.388641357 -738.289916992 835.451782227 +533.533203125 -556.23651123 -1723.53491211 1888.02258301 +300.582397461 -587.664123535 -372.446044922 757.901672363 +-649.266784668 -480.324707031 3841.48706055 3925.46582031 +-469.191223145 21.6893558502 526.020935059 705.201293945 +-475.140289307 -422.237976074 2271.65283203 2358.90869141 +627.509887695 159.860198975 -2268.89355469 2359.49194336 +-524.50390625 -258.241394043 -415.043670654 716.975769043 +97.7850723267 -363.942871094 -526.411315918 647.398803711 +-423.86126709 -563.23626709 -131.224624634 717.016967773 +468.814849854 398.713439941 -1710.11083984 1817.48144531 +97.6282196045 408.330047607 -199.558151245 464.852813721 +158.529266357 510.820892334 3709.49560547 3747.85644531 +217.423309326 867.723205566 983.342468262 1329.3527832 +462.597351074 -221.711029053 -293.458618164 590.990722656 +593.361694336 86.7153091431 -2784.77758789 2848.61083984 +301.84854126 319.171295166 -828.247741699 937.537841797 +-451.792205811 -367.286407471 216.360641479 621.150085449 +57.599647522 -694.848449707 2061.38354492 2176.10522461 +-344.99307251 137.072219849 -559.782348633 671.688415527 +74.6533203125 491.861297607 504.520111084 708.54864502 +462.521942139 413.522399902 294.856262207 686.926147461 +-223.304122925 -778.011535645 -4365.04199219 4439.45458984 +-593.881958008 -86.4216842651 -628.596679688 869.078979492 +-654.293457031 516.888305664 2925.91943359 3042.41308594 +308.123626709 536.714172363 711.274841309 942.82244873 +173.813980103 358.704406738 643.456542969 756.912475586 +403.918395996 110.70362854 315.307495117 524.236755371 +-253.448684692 -691.819458008 -4047.29370117 4113.81054688 +-282.351898193 -254.000045776 -733.335571289 825.844848633 +-475.100158691 -364.081573486 -481.698272705 768.315551758 +-547.64276123 199.301010132 233.105102539 627.671447754 +-278.313720703 374.846618652 188.98828125 503.671600342 +-277.796386719 166.296508789 -362.516021729 486.048583984 +416.798095703 197.326034546 -990.376037598 1092.47558594 +-573.639648438 -16.9672050476 -901.180541992 1068.39916992 +352.827148438 -327.371582031 -981.545043945 1093.20166016 +-493.110473633 -84.2465438843 -1393.92749023 1480.97583008 +488.145233154 725.678405762 4190.03320312 4280.33544922 +-333.722717285 120.859825134 188.820053101 402.033538818 +147.969024658 564.411743164 666.423461914 885.762756348 +51.8463935852 488.826599121 53.2623825073 494.445526123 +-316.197845459 110.937149048 580.84197998 670.571044922 +-27.8103256226 -317.200073242 387.858734131 501.820373535 +324.063934326 437.047302246 -2411.89111328 2472.49804688 +-636.129882812 218.908782959 -1222.38769531 1395.28271484 +169.190734863 309.595794678 -119.753662109 372.580200195 +338.617919922 -242.122360229 444.244720459 608.801025391 +-160.208831787 -515.892700195 47.0025596619 542.237365723 +-294.32623291 511.082977295 2777.48657227 2839.4128418 +500.136413574 -202.411132812 229.591659546 586.360839844 +5.63457632065 -555.795349121 253.65536499 610.967468262 +462.86138916 409.835021973 -507.220977783 799.67401123 +-662.945373535 391.005767822 2575.82421875 2688.35498047 +290.333984375 -206.520736694 632.408691406 725.868713379 +-604.27166748 -250.062332153 -2796.03857422 2871.49902344 +571.509094238 -33.6293334961 -1431.41113281 1541.65222168 +-26.2659912109 433.382873535 -161.049438477 463.08480835 +-156.630844116 -522.260131836 389.788360596 670.241638184 +349.069488525 -393.421447754 -699.447998047 875.1328125 +536.940734863 206.954956055 -1305.26501465 1426.48254395 +72.0006408691 514.795227051 762.119018555 922.509399414 +-466.163360596 -454.779602051 2003.78515625 2106.96166992 +420.062744141 167.231811523 -829.331359863 944.56854248 +-316.611907959 46.2869796753 -459.694763184 560.09362793 +461.769683838 21.3243484497 -561.858459473 727.578796387 +713.323791504 155.398742676 2509.33740234 2613.37988281 +151.880142212 448.439025879 -430.491394043 639.912475586 +-354.073486328 -119.888580322 17.9272441864 374.249511719 +-377.810058594 131.730407715 -322.07711792 513.640930176 +404.681243896 -230.214706421 -651.016723633 800.367736816 +754.399108887 -284.005645752 2994.89868164 3101.48266602 +190.535842896 -543.331298828 -2091.59301758 2169.39477539 +-138.606689453 -290.071502686 -557.816955566 643.826904297 +-99.6377105713 389.992492676 -138.461990356 425.668334961 +199.540161133 120.513793945 -492.237487793 544.644470215 +140.776580811 -387.11138916 1213.13269043 1281.15734863 +197.653152466 -561.432006836 1923.80603027 2013.77807617 +-217.050094604 34.339214325 462.049926758 511.644470215 +194.867889404 412.699279785 -354.015716553 577.599609375 +-389.516204834 -93.1831436157 -1031.07617188 1106.13024902 +394.682434082 -251.406311035 -617.98815918 775.17010498 +434.605224609 156.028564453 781.891784668 908.06463623 +-331.840270996 148.312042236 -496.01171875 614.932556152 +-613.820678711 -153.514358521 3967.40722656 4017.54443359 +-334.732299805 356.984619141 2878.83227539 2920.12988281 +-429.916870117 113.178840637 735.996276855 859.842102051 +251.299819946 -121.22593689 352.710388184 449.724304199 +205.583816528 437.387145996 -2335.59594727 2385.07446289 +104.813278198 288.961395264 -402.654296875 506.571807861 +500.685852051 -247.550827026 1657.0300293 1748.63269043 +172.375793457 479.123535156 2582.60009766 2632.31762695 +269.613494873 122.841186523 -407.748321533 504.023895264 +463.969665527 213.867614746 1848.93408203 1918.21911621 +-319.873931885 47.0999565125 -211.167480469 386.172821045 +344.343994141 359.908111572 -614.543151855 791.056213379 +-286.990692139 256.091766357 445.16293335 588.316833496 +-302.182067871 -47.797416687 -360.491638184 472.813720703 +266.249267578 82.690826416 -70.6683197021 287.611633301 +-149.067932129 -251.618408203 -4.61803674698 292.496826172 +-95.1179351807 -355.493652344 306.690704346 479.043151855 +32.0886955261 303.170288086 -121.342590332 328.12487793 +-475.029388428 341.353210449 -1915.39050293 2002.7220459 +212.276916504 508.549316406 2596.06445312 2653.90917969 +278.998199463 -271.806152344 -312.554229736 499.40838623 +315.761016846 304.05557251 -1385.42468262 1453.11950684 +171.852920532 -286.031066895 12.7945156097 333.9324646 +-17.6159324646 -268.700317383 151.720672607 309.078216553 +128.488037109 -597.067260742 1897.08337402 1992.96862793 +-530.381835938 78.6207504272 -2039.44995117 2108.75366211 +479.200286865 -85.4499206543 -954.213562012 1071.19470215 +102.341445923 -159.653213501 231.835128784 299.517028809 +-326.195953369 81.1711044312 65.5880355835 342.48260498 +-54.5026741028 343.759368896 -486.809844971 598.43536377 +-297.390808105 183.343917847 489.430908203 601.330932617 +66.450630188 541.080749512 2030.26428223 2102.17919922 +424.039337158 315.36315918 -1390.52709961 1487.5579834 +135.606994629 -542.359375 1131.7557373 1262.30505371 +300.006622314 515.374755859 3171.39526367 3226.97436523 +-232.625640869 -488.262084961 -3304.32421875 3348.29394531 +-355.56942749 263.937530518 1111.25134277 1196.23254395 +259.941467285 190.144119263 329.010894775 460.404724121 +-56.679233551 259.404418945 -461.680023193 532.589538574 +628.396850586 212.266067505 3604.41577148 3664.93554688 +-251.757629395 -13.1753025055 310.52053833 399.973114014 +-123.085548401 446.650146484 -1433.63110352 1506.63354492 +-292.178222656 115.445121765 256.161529541 405.357147217 +190.950286865 210.480300903 154.712982178 323.573913574 +459.692260742 -308.790466309 3003.34204102 3053.9699707 +-609.905822754 88.3035964966 -3474.88085938 3529.10473633 +396.213867188 84.3817062378 -2070.54589844 2109.80224609 +-456.605499268 98.8492126465 -1880.04919434 1937.22607422 +-164.544616699 9.20334815979 215.798736572 271.530334473 +-479.104553223 -119.672813416 -2051.58642578 2110.18237305 +-36.602191925 -273.757476807 374.200897217 465.090515137 +-436.196563721 -87.2987594604 -1892.67553711 1944.25024414 +-214.1197052 -191.587921143 146.143981934 322.352661133 +58.9035415649 368.769348145 -350.373199463 512.07598877 +-236.277282715 118.350708008 -337.138397217 428.364501953 +260.056060791 96.7209701538 -281.221710205 395.056640625 +-281.198883057 163.421859741 -210.2159729 387.25994873 +-264.817871094 332.861785889 -1342.33239746 1408.11279297 +262.019805908 36.643081665 135.458938599 297.230926514 +-251.715316772 -63.4830818176 -253.558868408 362.881256104 +347.9559021 158.801452637 -883.803588867 963.016113281 +374.597381592 61.5379981995 -881.764038086 960.009338379 +-23.932800293 312.515289307 -624.864624023 699.066772461 +281.37789917 72.8103942871 -924.723205566 969.323425293 +-433.695648193 53.7456359863 -2307.03027344 2348.05639648 +257.729614258 -39.1830558777 -355.778839111 441.065124512 +-146.164962769 -260.103240967 499.8722229 582.142700195 +355.016143799 -126.603157043 -1146.71496582 1207.07080078 +-138.08215332 51.7156028748 255.152069092 294.692657471 +-168.015975952 278.885375977 -1318.15380859 1357.76867676 +132.063751221 -140.952407837 -142.850524902 240.238815308 +95.8837509155 -266.76184082 -552.183044434 620.694519043 +135.615203857 -242.973403931 189.839279175 336.847900391 +20.6344642639 -290.318969727 527.892944336 602.811645508 +-167.970367432 -213.385147095 -455.352203369 530.181945801 +97.2250823975 -374.248962402 -1296.18945312 1352.63525391 +-91.2280807495 -367.808013916 -889.321716309 966.694580078 +-131.47227478 211.87979126 -91.8306884766 265.727081299 +-55.2641525269 -148.862075806 138.252944946 210.54196167 +-143.674880981 -193.43862915 -67.8905563354 250.339981079 +-30.2230625153 248.029647827 -363.470031738 441.069824219 +113.644088745 -187.894989014 472.587738037 521.112915039 +3.3240942955 249.213134766 166.733566284 299.863830566 +-383.713012695 135.277450562 920.890563965 1006.76464844 +-382.265594482 17.7993602753 -1302.96435547 1357.99853516 +-223.464401245 24.9094543457 181.689498901 289.081115723 +-189.236953735 207.208312988 -495.655975342 569.579467773 +222.078536987 297.124511719 -1494.32763672 1539.68078613 +-223.431472778 -196.718185425 957.71295166 1002.91265869 +-344.869598389 -102.645675659 -1241.64172363 1292.72790527 +-172.276107788 185.804870605 70.0271987915 262.88079834 +-87.6056137085 -200.651199341 14.1392669678 219.398193359 +365.271942139 -50.3414382935 2583.91455078 2610.09057617 +-128.827575684 360.034942627 -1517.47949219 1564.91711426 +147.933319092 133.809631348 -100.383560181 223.307281494 +182.054428101 115.89629364 364.396881104 423.510162354 +227.978164673 103.810997009 496.736297607 556.325195312 +-236.795196533 -76.6067047119 537.746154785 592.546630859 +52.0244255066 202.5887146 221.462692261 304.621826172 +-198.262893677 6.91983938217 -114.469871521 229.04019165 +164.477416992 179.123977661 642.093200684 686.60168457 +11.3924407959 -225.364883423 -156.393783569 274.55078125 +-377.296539307 -57.265171051 1347.79162598 1400.77624512 +53.9463348389 208.212753296 -349.218414307 410.14175415 +-226.705459595 105.810073853 -361.151641846 439.342285156 +9.05097484589 -230.571640015 -191.034866333 299.565551758 +205.304382324 -13.4783067703 -126.156303406 241.344085693 +52.2612380981 -316.610015869 -842.544128418 901.58404541 +-199.450576782 -268.484985352 1588.97912598 1623.79785156 +102.144836426 132.941543579 19.01121521 168.725952148 +-162.219360352 -159.069946289 -78.9279632568 240.516098022 +-274.397918701 -126.455024719 870.174682617 921.134643555 +-172.870407104 -311.16595459 2078.16040039 2108.42578125 +142.09487915 103.34009552 -204.136001587 269.335540771 +128.987762451 -173.421676636 -346.717529297 408.565734863 +-200.201080322 117.854873657 -252.305221558 342.96963501 +136.163497925 284.958526611 -1377.5847168 1413.32287598 +-243.369186401 -273.252746582 -1287.58056641 1338.56616211 +-78.6706848145 72.0934371948 -163.837936401 195.523422241 +85.2420272827 -63.8692359924 -68.0201263428 126.381248474 +5.48315286636 169.746551514 19.1963806152 170.916519165 +-174.321136475 -104.290061951 422.362365723 468.672851562 +-171.783859253 76.5187225342 60.4166183472 197.522094727 +-175.505126953 25.5033969879 -217.225921631 280.427490234 +123.021682739 107.014671326 -451.839294434 480.359466553 +257.343231201 218.456741333 1710.3013916 1743.2956543 +150.419433594 -38.9184989929 -401.071899414 430.115478516 +69.3821640015 149.40536499 230.240112305 283.101318359 +-65.3087005615 -76.3590698242 199.564559937 223.4322052 +-101.875679016 112.979660034 -163.442932129 223.286026001 +-258.444122314 -157.256561279 -1107.35888672 1147.94018555 +26.7573318481 -93.475112915 -207.100631714 228.788604736 +-90.1658096313 -251.101425171 1174.62353516 1204.5423584 +130.258453369 280.837738037 1293.95117188 1330.46862793 +98.7972183228 -273.000793457 -1406.56286621 1436.21362305 +233.238555908 -12.0738554001 1060.44787598 1085.86169434 +180.79699707 26.977306366 -9.73153781891 183.057449341 +-135.318725586 -108.293296814 -45.3031349182 179.139526367 +-241.098632812 156.288497925 1572.01745605 1598.05932617 +-158.164474487 26.3298530579 -153.631286621 222.062683105 +143.044540405 -130.906036377 602.377807617 632.816833496 +-38.0151290894 -153.505233765 150.350479126 218.206954956 +176.451507568 -152.510238647 503.92175293 555.276184082 +-209.217941284 42.8756561279 127.991287231 248.982406616 +-226.651504517 106.940330505 76.5094833374 262.03213501 +90.9969940186 -58.3109817505 -209.628112793 235.848617554 +-190.11050415 -168.852767944 -1228.45581055 1254.49475098 +184.489456177 -26.777256012 -1039.73449707 1056.31494141 +245.028427124 -175.379852295 -1342.34960938 1375.75415039 +89.744758606 -161.848114014 502.412475586 535.413146973 +-142.788375854 -123.909431458 -670.08404541 696.243286133 +-129.925552368 44.6646118164 -235.412002563 272.569976807 +-3.10773539543 243.49937439 -975.948791504 1005.87158203 +-130.704086304 121.191932678 -607.82244873 633.418640137 +134.020446777 -46.7718048096 -376.337371826 402.217468262 +25.1293697357 170.080566406 596.797546387 621.068603516 +-137.978118896 -104.483901978 -166.665588379 240.275390625 +-37.2089080811 75.2833099365 -160.025909424 180.721801758 +-75.1667709351 3.75725960732 -183.045562744 197.913711548 +-6.59699249268 128.646194458 -325.193634033 349.777435303 +271.550994873 19.8085670471 1403.52368164 1429.68908691 +7.60999155045 -173.525817871 380.973937988 418.700683594 +87.3937835693 -63.5869140625 -207.347915649 233.824996948 +70.2305145264 51.5499992371 241.805297852 257.020477295 +91.5034408569 57.7856636047 -185.578186035 214.828598022 +67.8807525635 211.434646606 -1140.46276855 1161.88110352 +-65.2170333862 9.60854530334 113.410140991 131.177154541 +-110.315155029 38.7354698181 -4.27238368988 116.996253967 +-59.7876815796 -103.070579529 -545.44317627 558.30670166 +-223.654174805 -61.4167022705 1192.27661133 1214.6262207 +-70.257598877 32.8206558228 170.350860596 187.170349121 +9.43720436096 -61.059135437 -104.676460266 121.55015564 +6.63288640976 137.884368896 -465.530578613 485.566497803 +54.5453643799 113.486709595 -221.424118042 254.721557617 +28.1700057983 219.639907837 1144.94055176 1166.15783691 +-141.597320557 129.026733398 979.586486816 998.141967773 +-80.9826049805 -75.3437576294 -248.48147583 271.988800049 +-67.3579406738 -139.726715088 -886.251831055 899.723815918 +76.3685150146 120.071853638 620.328430176 636.440673828 +-53.4710731506 -38.8368110657 -337.47164917 343.881622314 +104.30229187 64.1203765869 -261.096923828 288.378204346 +-80.242477417 -36.8715782166 306.120422363 318.60333252 +-90.038772583 99.4113616943 -325.559204102 352.105651855 +117.634368896 -18.4335079193 -519.202575684 532.680908203 +81.977973938 -73.9195022583 -80.9333877563 136.874740601 +82.7330703735 -76.2519989014 -541.958740234 553.514587402 +9.33701038361 110.972351074 -225.654510498 251.638626099 +66.8926849365 31.8457736969 83.4559936523 111.596092224 +49.5910148621 -2.2472307682 -32.2575263977 59.201915741 +-6.24311637878 -113.670272827 -352.448669434 370.378143311 +-36.5033340454 -80.7571258545 204.021392822 222.438613892 +-32.5940551758 93.2269668579 -440.178283691 451.121459961 +5.00377035141 -94.771156311 141.518661499 170.394073486 +-38.3466682434 -83.0532684326 -298.994232178 312.675323486 +23.6306476593 65.3635787964 63.7607917786 94.3199005127 +101.937843323 -27.0256843567 141.090637207 176.148452759 +-39.9993515015 110.605171204 -348.257354736 367.58215332 +68.3928146362 -107.130355835 187.432174683 226.462600708 +107.049041748 -26.8194923401 1.71462702751 110.37084198 +95.2299728394 -69.8327484131 -216.167831421 246.320709229 +-66.8646240234 139.910812378 -443.23928833 469.581695557 +-30.3158168793 46.7943191528 -32.6409225464 64.6079483032 +22.1420478821 61.4740638733 -123.377555847 139.611434937 +-15.6072301865 -62.802898407 -189.245330811 200.003967285 +-65.5332717896 140.362091064 35.4454345703 158.910369873 +28.5883274078 59.5948486328 -212.651702881 222.687194824 +-9.90988254547 27.4723072052 -32.4371299744 43.6474609375 +-56.8140068054 -97.529876709 -193.117675781 223.683578491 +2.33134198189 65.6356201172 65.0542678833 92.442024231 +-29.886844635 -43.8190879822 -224.325531006 230.510910034 +33.0511398315 -16.1610527039 -25.3651657104 44.6872367859 +74.1563262939 18.1758918762 -88.0356216431 116.532371521 +17.1007156372 -29.3813762665 16.0730609894 37.6037635803 +-10.3711366653 2.94795441628 11.6719636917 15.8897972107 +-0.340210616589 -7.37204265594 9.37533473969 11.9314565659 +-15.8926486969 0.626824915409 13.8912763596 21.1172142029 +-3.47081518173 -3.99431276321 24.684173584 25.2449893951 +-3.17013216019 1.83064675331 -6.8429479599 7.76060199738 +-0.348987787962 1.07221770287 1.96187603474 2.26283025742