diff --git a/bin/rivet-mkanalysis b/bin/rivet-mkanalysis --- a/bin/rivet-mkanalysis +++ b/bin/rivet-mkanalysis @@ -1,306 +1,306 @@ #! /usr/bin/env python """\ %prog: make templates of analysis source files for Rivet Usage: %prog [--help|-h] [--srcroot=] Without the --srcroot flag, the analysis files will be created in the current directory. """ import rivet, sys, os rivet.util.check_python_version() rivet.util.set_process_name(os.path.basename(__file__)) import logging ## Handle command line from optparse import OptionParser parser = OptionParser(usage=__doc__) parser.add_option("--srcroot", metavar="DIR", dest="SRCROOT", default=None, help="install the templates into the Rivet source tree (rooted " + "at directory DIR) rather than just creating all in the current dir") parser.add_option("-q", "--quiet", dest="LOGLEVEL", default=logging.INFO, action="store_const", const=logging.WARNING, help="only write out warning and error messages") parser.add_option("-v", "--verbose", dest="LOGLEVEL", default=logging.INFO, action="store_const", const=logging.DEBUG, help="provide extra debugging messages") parser.add_option("-i", "--inline-info", dest="INLINE", action="store_true", default=False, help="Put analysis info into source file instead of separate data file.") opts, args = parser.parse_args() logging.basicConfig(format="%(msg)s", level=opts.LOGLEVEL) ANANAMES = args ## Work out installation paths ANAROOT = os.path.abspath(opts.SRCROOT or os.getcwd()) if not os.access(ANAROOT, os.W_OK): logging.error("Can't write to source root directory %s" % ANAROOT) sys.exit(1) ANASRCDIR = os.getcwd() ANAINFODIR = os.getcwd() ANAPLOTDIR = os.getcwd() if opts.SRCROOT: ANASRCDIR = os.path.join(ANAROOT, "src/Analyses") ANAINFODIR = os.path.join(ANAROOT, "data/anainfo") ANAPLOTDIR = os.path.join(ANAROOT, "data/plotinfo") if not (os.path.exists(ANASRCDIR) and os.path.exists(ANAINFODIR) and os.path.exists(ANAPLOTDIR)): logging.error("Rivet analysis dirs do not exist under %s" % ANAROOT) sys.exit(1) if not (os.access(ANASRCDIR, os.W_OK) and os.access(ANAINFODIR, os.W_OK) and os.access(ANAPLOTDIR, os.W_OK)): logging.error("Can't write to Rivet analysis dirs under %s" % ANAROOT) sys.exit(1) ## Check for disallowed characters in analysis names import string allowedchars = string.letters + string.digits + "_" all_ok = True for ananame in ANANAMES: for c in ananame: if c not in allowedchars: logging.error("Analysis name '%s' contains disallowed character '%s'!" % (ananame, c)) all_ok = False break if not all_ok: logging.error("Exiting... please ensure that all analysis names are valid") sys.exit(1) ## Now make each analysis for ANANAME in ANANAMES: logging.info("Writing templates for %s to %s" % (ANANAME, ANAROOT)) ## Extract some metadata from the name if it matches the standard pattern import re re_stdana = re.compile(r"^(\w+)_(\d{4})_(I|S)(\d+)$") match = re_stdana.match(ANANAME) STDANA = False ANAEXPT = "" ANACOLLIDER = "" ANAYEAR = "" INSPIRE_SPIRES = 'I' ANAINSPIREID = "" if match: STDANA = True ANAEXPT = match.group(1) if ANAEXPT.upper() in ("ALICE", "ATLAS", "CMS", "LHCB"): ANACOLLIDER = "LHC" elif ANAEXPT.upper() in ("CDF", "D0"): ANACOLLIDER = "Tevatron" elif ANAEXPT.upper() == "BABAR": ANACOLLIDER = "PEP-II" elif ANAEXPT.upper() == "BELLE": ANACOLLIDER = "KEKB" ANAYEAR = match.group(2) INSPIRE_SPIRES = match.group(3) ANAINSPIREID = match.group(4) if INSPIRE_SPIRES == "I": ANAREFREPO = "Inspire" else: ANAREFREPO = "Spires" KEYWORDS = { "ANANAME" : ANANAME, "ANAEXPT" : ANAEXPT, "ANACOLLIDER" : ANACOLLIDER, "ANAYEAR" : ANAYEAR, "ANAREFREPO" : ANAREFREPO, "ANAINSPIREID" : ANAINSPIREID } ## Try to get bib info from SPIRES ANABIBKEY = "" ANABIBTEX = "" bibkey, bibtex = None, None if STDANA: try: logging.debug("Getting Inspire/SPIRES biblio data for '%s'" % ANANAME) bibkey, bibtex = rivet.spiresbib.get_bibtex_from_repo(INSPIRE_SPIRES, ANAINSPIREID) except Exception, e: logging.error("Inspire/SPIRES oops: %s" % e) if bibkey and bibtex: ANABIBKEY = bibkey ANABIBTEX = bibtex KEYWORDS["ANABIBKEY"] = ANABIBKEY KEYWORDS["ANABIBTEX"] = ANABIBTEX ## Try to download YODA data file from HepData if STDANA: try: import urllib hdurl = None if INSPIRE_SPIRES == "I": hdurl = "http://hepdata.cedar.ac.uk/view/ins%s/yoda" % ANAINSPIREID elif INSPIRE_SPIRES == "S": hdurl = "http://hepdata.cedar.ac.uk/view/irn%s/yoda" % ANAINSPIREID if hdurl: logging.debug("Getting data file from HepData at %s" % hdurl) httpstream = urllib.urlopen(hdurl) yodastr = httpstream.read() if not yodastr or "" in yodastr: logging.warning("Problem encountered when getting data from HepData (%s). No reference data file written." % hdurl) else: f = open("%s.yoda" % ANANAME, "w") f.write(yodastr) f.close() httpstream.close() else: logging.warning("Could not identify a URL for getting reference data from HepData. No reference data file written.") except Exception, e: logging.error("HepData oops: %s" % e) if opts.INLINE: KEYWORDS["ANAREFREPO_LOWER"] = KEYWORDS["ANAREFREPO"].lower() INLINEMETHODS=""" public: string experiment() const { return "%(ANAEXPT)s"; } string year() const { return "%(ANAYEAR)s"; } string %(ANAREFREPO_LOWER)sId() const { return "%(ANAINSPIREID)s"; } string collider() const { return ""; } string summary() const { return ""; } string description() const { return ""; } string runInfo() const { return ""; } string bibKey() const { return "%(ANABIBKEY)s"; } string bibTeX() const { return "%(ANABIBTEX)s"; } string status() const { return "UNVALIDATED"; } vector authors() const { return vector(); } vector references() const { return vector(); } vector todos() const { return vector(); } """ % KEYWORDS del KEYWORDS["ANAREFREPO_LOWER"] else: INLINEMETHODS="" KEYWORDS["INLINEMETHODS"] = INLINEMETHODS ANASRCFILE = os.path.join(ANASRCDIR, ANANAME+".cc") logging.debug("Writing implementation template to %s" % ANASRCFILE) f = open(ANASRCFILE, "w") src = '''\ // -*- C++ -*- #include "Rivet/Analysis.hh" #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Add a short analysis description here class %(ANANAME)s : public Analysis { public: /// Constructor DEFAULT_RIVET_ANALYSIS_CTOR(%(ANANAME)s); /// @name Analysis methods //@{ /// Book histograms and initialise projections before the run void init() { - // Initialise and register projections + // Initialise and declare projections declare(FinalState(Cuts::abseta < 5 && Cuts::pT > 100*MeV), "FS"); // Book histograms _h_XXXX = bookProfile1D(1, 1, 1); _h_YYYY = bookHisto1D(2, 1, 1); _h_ZZZZ = bookCounter(3, 1, 1); } /// Perform the per-event analysis void analyze(const Event& event) { /// @todo Do the event by event analysis here } /// Normalise histograms etc., after the run void finalize() { normalize(_h_YYYY); // normalize to unity scale(_h_ZZZZ, crossSection()/picobarn/sumOfWeights()); // norm to cross section } //@} /// @name Histograms //@{ Profile1DPtr _h_XXXX; Histo1DPtr _h_YYYY; CounterPtr _h_ZZZZ; //@} %(INLINEMETHODS)s }; // The hook for the plugin system DECLARE_RIVET_PLUGIN(%(ANANAME)s); } ''' % KEYWORDS f.write(src) f.close() ANAPLOTFILE = os.path.join(ANAPLOTDIR, ANANAME+".plot") logging.debug("Writing plot template to %s" % ANAPLOTFILE) f = open(ANAPLOTFILE, "w") src = '''\ # BEGIN PLOT /%(ANANAME)s/d01-x01-y01 #Title=[Uncomment and insert title for histogram d01-x01-y01 here] #XLabel=[Uncomment and insert x-axis label for histogram d01-x01-y01 here] #YLabel=[Uncomment and insert y-axis label for histogram d01-x01-y01 here] # + any additional plot settings you might like, see make-plots documentation # END PLOT # ... add more histograms as you need them ... ''' % KEYWORDS f.write(src) f.close() if opts.INLINE: sys.exit(0) ANAINFOFILE = os.path.join(ANAINFODIR, ANANAME+".info") logging.debug("Writing info template to %s" % ANAINFOFILE) f = open(ANAINFOFILE, "w") src = """\ Name: %(ANANAME)s Year: %(ANAYEAR)s Summary: Experiment: %(ANAEXPT)s Collider: %(ANACOLLIDER)s %(ANAREFREPO)sID: %(ANAINSPIREID)s Status: UNVALIDATED Authors: - Your Name #References: #- '' #- '' #- '' RunInfo: NeedCrossSection: no #Beams: #Energies: Description: ' 50\;\GeV$.>' BibKey: %(ANABIBKEY)s BibTeX: '%(ANABIBTEX)s' ToDo: - Implement the analysis, test it, remove this ToDo, and mark as VALIDATED :-) """ % KEYWORDS f.write(src) f.close() logging.info("Use e.g. 'rivet-buildplugin Rivet%s.so %s.cc' to compile the plugin" % (ANANAME, ANANAME)) diff --git a/include/Rivet/Projections/NonPromptFinalState.hh b/include/Rivet/Projections/NonPromptFinalState.hh --- a/include/Rivet/Projections/NonPromptFinalState.hh +++ b/include/Rivet/Projections/NonPromptFinalState.hh @@ -1,57 +1,57 @@ // -*- C++ -*- #ifndef RIVET_NonPromptFinalState_HH #define RIVET_NonPromptFinalState_HH #include "Rivet/Projections/FinalState.hh" namespace Rivet { /// @brief Find final state particles NOT directly connected to the hard process. /// /// See PromptFinalState for details. class NonPromptFinalState : public FinalState { public: /// @name Constructors //@{ // Constructor from a final state. NonPromptFinalState(const FinalState& fsp, bool accepttaudecays=false, bool acceptmudecays=false); /// Constructor from a Cut (and implicit general FS). - NonPromptFinalState(const Cut& c, bool accepttaudecays=false, bool acceptmudecays=false); + NonPromptFinalState(const Cut& c=Cuts::open(), bool accepttaudecays=false, bool acceptmudecays=false); // /// Constructor from a Cut and optional FinalState. // NonPromptFinalState(const Cut& c, const FinalState& fsp=FinalState(), // bool accepttaudecays=false, bool acceptmudecays=false); /// Clone on the heap. DEFAULT_RIVET_PROJ_CLONE(NonPromptFinalState); //@} /// Treat particles from decays of prompt muons as non-prompt? void acceptMuonDecays(bool acc=true) { _acceptMuDecays = acc; } /// Treat particles from decays of prompt taus as non-prompt? void acceptTauDecays(bool acc=true) { _acceptTauDecays = acc; } protected: /// Apply the projection on the supplied event. void project(const Event& e); /// Compare projections. int compare(const Projection& p) const; private: bool _acceptMuDecays, _acceptTauDecays; }; } #endif diff --git a/include/Rivet/Tools/JetUtils.hh b/include/Rivet/Tools/JetUtils.hh --- a/include/Rivet/Tools/JetUtils.hh +++ b/include/Rivet/Tools/JetUtils.hh @@ -1,91 +1,130 @@ #ifndef RIVET_JETUTILS_HH #define RIVET_JETUTILS_HH #include "Rivet/Jet.hh" #include "Rivet/Tools/ParticleBaseUtils.hh" namespace Rivet { /// std::function instantiation for functors taking a Jet and returning a bool using JetSelector = function; /// std::function instantiation for functors taking two Jets and returning a bool using JetSorter = function; /// @name Unbound functions for converting between Jets, Particles and PseudoJets //@{ inline PseudoJets mkPseudoJets(const Particles& ps) { PseudoJets rtn; rtn.reserve(ps.size()); for (const Particle& p : ps) rtn.push_back(p); return rtn; } inline PseudoJets mkPseudoJets(const Jets& js) { PseudoJets rtn; rtn.reserve(js.size()); for (const Jet& j : js) rtn.push_back(j); return rtn; } inline Jets mkJets(const PseudoJets& pjs) { Jets rtn; rtn.reserve(pjs.size()); for (const PseudoJet& pj : pjs) rtn.push_back(pj); return rtn; } //@} + /// @name Jet classifier -> bool functors + //@{ + + /// std::function instantiation for functors taking a Jet and returning a bool + using JetSelector = function; + /// std::function instantiation for functors taking two Jets and returning a bool + using JetSorter = function; + + + /// Base type for Jet -> bool functors + struct BoolJetFunctor { + virtual bool operator()(const Jet& p) const = 0; + }; + + + /// B-tagging functor, with a tag selection cut as the stored state + struct HasBTag : BoolJetFunctor { + HasBTag(const Cut& c=Cuts::open()) : cut(c) {} + // HasBTag(const std::function& f) : selector(f) {} + bool operator() (const Jet& j) const { return j.bTagged(cut); } + // const std::function selector; + const Cut cut; + }; + using hasBTag = HasBTag; + + /// C-tagging functor, with a tag selection cut as the stored state + struct HasCTag : BoolJetFunctor { + HasCTag(const Cut& c=Cuts::open()) : cut(c) {} + // HasCTag(const std::function& f) : selector(f) {} + bool operator() (const Jet& j) const { return j.cTagged(cut); } + // const std::function selector; + const Cut cut; + }; + using hasCTag = HasCTag; + + //@} + + + /// @name Unbound functions for filtering jets //@{ /// Filter a jet collection in-place to the subset that passes the supplied Cut Jets& ifilter_select(Jets& jets, const Cut& c); /// Alias for ifilter_select /// @deprecated Use ifilter_select inline Jets& ifilterBy(Jets& jets, const Cut& c) { return ifilter_select(jets, c); } /// Filter a jet collection in-place to the subset that passes the supplied Cut inline Jets filter_select(const Jets& jets, const Cut& c) { Jets rtn = jets; return ifilter_select(rtn, c); } /// Alias for ifilter_select /// @deprecated Use filter_select inline Jets filterBy(const Jets& jets, const Cut& c) { return filter_select(jets, c); } /// Filter a jet collection in-place to the subset that passes the supplied Cut inline Jets filter_select(const Jets& jets, const Cut& c, Jets& out) { out = filter_select(jets, c); return out; } /// Alias for ifilter_select /// @deprecated Use filter_select inline Jets filterBy(const Jets& jets, const Cut& c, Jets& out) { return filter_select(jets, c, out); } /// Filter a jet collection in-place to the subset that fails the supplied Cut Jets& ifilter_discard(Jets& jets, const Cut& c); /// Filter a jet collection in-place to the subset that fails the supplied Cut inline Jets filter_discard(const Jets& jets, const Cut& c) { Jets rtn = jets; return ifilter_discard(rtn, c); } /// Filter a jet collection in-place to the subset that fails the supplied Cut inline Jets filter_discard(const Jets& jets, const Cut& c, Jets& out) { out = filter_discard(jets, c); return out; } //@} } #endif