diff --git a/CommonTools/Utils/interface/TypedStringObjectMethodCaller.h b/CommonTools/Utils/interface/TypedStringObjectMethodCaller.h new file mode 100644 index 0000000000000..eb3bd7c8a5a69 --- /dev/null +++ b/CommonTools/Utils/interface/TypedStringObjectMethodCaller.h @@ -0,0 +1,43 @@ +#ifndef CommonTools_Utils_TypedStringObjectMethodCaller_h +#define CommonTools_Utils_TypedStringObjectMethodCaller_h +/* \class TypedStringObjectMethodCaller + * + * Object's method (or a chain of methods) caller functor with generic return-type, specified by string expression + * + */ + +#include "FWCore/Utilities/interface/EDMException.h" +#include "CommonTools/Utils/interface/parser/Exception.h" +#include "CommonTools/Utils/interface/parser/MethodChain.h" +#include "CommonTools/Utils/interface/parser/MethodChainGrammar.h" +#include "FWCore/Reflection/interface/ObjectWithDict.h" + +template +struct TypedStringObjectMethodCaller { + TypedStringObjectMethodCaller(const std::string expr, bool lazy = DefaultLazyness) : type_(typeid(T)) { + using namespace boost::spirit::classic; + reco::parser::MethodChainGrammar grammar(methodchain_, type_, lazy); + const char* startingFrom = expr.c_str(); + try { + if (!parse(startingFrom, grammar >> end_p, space_p).full) { + throw edm::Exception(edm::errors::Configuration, "failed to parse \"" + expr + "\""); + } + } catch (reco::parser::BaseException& e) { + throw edm::Exception(edm::errors::Configuration) + << "MethodChainGrammer parse error:" << reco::parser::baseExceptionWhat(e) << " (char " + << e.where - startingFrom << ")\n"; + } + } + + R operator()(const T& t) const { + edm::ObjectWithDict o(type_, const_cast(&t)); + edm::ObjectWithDict ret = methodchain_->value(o); + return *static_cast(ret.address()); + } + +private: + reco::parser::MethodChainPtr methodchain_; + edm::TypeWithDict type_; +}; + +#endif diff --git a/CommonTools/Utils/interface/parser/MethodChain.h b/CommonTools/Utils/interface/parser/MethodChain.h new file mode 100644 index 0000000000000..4d21f595a7983 --- /dev/null +++ b/CommonTools/Utils/interface/parser/MethodChain.h @@ -0,0 +1,75 @@ +#ifndef CommonTools_Utils_MethodChain_h +#define CommonTools_Utils_MethodChain_h + +/* \class reco::parser::MethodChain + * + * Chain of methods + * Based on ExpressionBase and ExpressionVar, but remove final conversion to double + * + */ + +#include "CommonTools/Utils/interface/parser/MethodInvoker.h" +#include "CommonTools/Utils/interface/TypeCode.h" + +#include +#include + +namespace reco { + namespace parser { + + /// Based on Expression, but its value method returns an edm::ObjectWithDict instead of a double + class MethodChainBase { + public: // Public Methods + virtual ~MethodChainBase() {} + virtual edm::ObjectWithDict value(const edm::ObjectWithDict&) const = 0; + }; + + /// Shared ptr to MethodChainBase + typedef std::shared_ptr MethodChainPtr; + + /// Evaluate an object's method or datamember (or chain of them) + class MethodChain : public MethodChainBase { + private: // Private Data Members + std::vector methods_; + using Objects = std::vector>; + mutable oneapi::tbb::concurrent_queue objectsCache_; + + private: // Private Methods + [[nodiscard]] Objects initObjects_() const; + + Objects borrowObjects() const; + void returnObjects(Objects&&) const; + + public: // Public Static Methods + /// allocate an object to hold the result of a given member (if needed) + /// this method is used also from the LazyInvoker code + /// returns true if objects returned from this will require a destructor + static bool makeStorage(edm::ObjectWithDict& obj, const edm::TypeWithDict& retType); + + /// delete an objecty, if needed + /// this method is used also from the LazyInvoker code + static void delStorage(edm::ObjectWithDict&); + + public: // Public Methods + MethodChain(const std::vector& methods); + MethodChain(const MethodChain&); + ~MethodChain(); + edm::ObjectWithDict value(const edm::ObjectWithDict&) const override; + }; + + /// Same as MethodChain but with lazy resolution of object methods + /// using the dynamic type of the object, and not the one fixed at compile time + class LazyMethodChain : public MethodChainBase { + private: // Private Data Members + std::vector methods_; + + public: + LazyMethodChain(const std::vector& methods); + ~LazyMethodChain() override; + edm::ObjectWithDict value(const edm::ObjectWithDict&) const override; + }; + + } // namespace parser +} // namespace reco + +#endif // CommonTools_Utils_MethodChain_h diff --git a/CommonTools/Utils/interface/parser/MethodChainGrammar.h b/CommonTools/Utils/interface/parser/MethodChainGrammar.h new file mode 100644 index 0000000000000..27d4f68b780ae --- /dev/null +++ b/CommonTools/Utils/interface/parser/MethodChainGrammar.h @@ -0,0 +1,76 @@ +#ifndef CommonTools_Utils_MethodChainGrammar_h +#define CommonTools_Utils_MethodChainGrammar_h +/* \class MethodChainGrammer + * + * subset grammar of the full Grammer (CommonTools/Utils/interface/parser/Grammar.h), allowing only a chain of methods + * + */ + +#include "boost/spirit/include/classic_core.hpp" +#include "boost/spirit/include/classic_grammar_def.hpp" +#include "boost/spirit/include/classic_chset.hpp" +#include "FWCore/Utilities/interface/EDMException.h" +#include "FWCore/Reflection/interface/ObjectWithDict.h" +#include "CommonTools/Utils/interface/parser/MethodChain.h" +#include "CommonTools/Utils/interface/parser/MethodChainSetter.h" +#include "CommonTools/Utils/interface/parser/MethodSetter.h" +#include "CommonTools/Utils/interface/parser/MethodArgumentSetter.h" +#include "CommonTools/Utils/interface/parser/MethodInvoker.h" +#include "CommonTools/Utils/interface/parser/MethodStack.h" +#include "CommonTools/Utils/interface/parser/TypeStack.h" +#include "CommonTools/Utils/interface/parser/MethodArgumentStack.h" +#include "CommonTools/Utils/interface/parser/AnyMethodArgument.h" +#include "CommonTools/Utils/interface/parser/Exception.h" + +namespace reco { + namespace parser { + struct MethodChainGrammar : public boost::spirit::classic::grammar { + MethodChainPtr* methchain_; + bool lazy_; + mutable MethodStack methStack; + mutable LazyMethodStack lazyMethStack; + mutable MethodArgumentStack methArgStack; + mutable TypeStack typeStack; + + MethodChainGrammar(MethodChainPtr& methchain, const edm::TypeWithDict& iType, bool lazy = false) + : methchain_(&methchain), lazy_(lazy) { + typeStack.push_back(iType); + } + + template + struct definition { + typedef boost::spirit::classic::rule rule; + rule metharg, method, arrayAccess, methodchain; + definition(const MethodChainGrammar& self) { + using namespace boost::spirit::classic; + + MethodArgumentSetter methodArg_s(self.methArgStack); + MethodSetter method_s(self.methStack, self.lazyMethStack, self.typeStack, self.methArgStack, self.lazy_); + MethodChainSetter methodchain_s(*self.methchain_, self.methStack, self.lazyMethStack, self.typeStack); + + BOOST_SPIRIT_DEBUG_RULE(methodchain); + BOOST_SPIRIT_DEBUG_RULE(arrayAccess); + BOOST_SPIRIT_DEBUG_RULE(method); + BOOST_SPIRIT_DEBUG_RULE(metharg); + + boost::spirit::classic::assertion expectParenthesis(kMissingClosingParenthesis); + boost::spirit::classic::assertion expect(kSyntaxError); + + metharg = (strict_real_p[methodArg_s]) | (int_p[methodArg_s]) | + (ch_p('"') >> *(~ch_p('"')) >> ch_p('"'))[methodArg_s] | + (ch_p('\'') >> *(~ch_p('\'')) >> ch_p('\''))[methodArg_s]; + method = // alnum_p doesn't accept underscores, so we use chset<>; lexeme_d needed to avoid whitespace skipping within method names + (lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")] >> ch_p('(') >> metharg >> *(ch_p(',') >> metharg) >> + expectParenthesis(ch_p(')')))[method_s] | + ((lexeme_d[alpha_p >> *chset<>("a-zA-Z0-9_")])[method_s] >> !(ch_p('(') >> ch_p(')'))); + arrayAccess = (ch_p('[') >> metharg >> *(ch_p(',') >> metharg) >> expectParenthesis(ch_p(']')))[method_s]; + methodchain = (method >> *(arrayAccess | (ch_p('.') >> expect(method))))[methodchain_s]; + } + + rule const& start() const { return methodchain; } + }; + }; + } // namespace parser +} // namespace reco + +#endif diff --git a/CommonTools/Utils/interface/parser/MethodChainSetter.h b/CommonTools/Utils/interface/parser/MethodChainSetter.h new file mode 100644 index 0000000000000..e8ee3a3a46606 --- /dev/null +++ b/CommonTools/Utils/interface/parser/MethodChainSetter.h @@ -0,0 +1,36 @@ +#ifndef CommonTools_Utils_MethodChainSetter_h +#define CommonTools_Utils_MethodChainSetter_h +/* \class reco::parser::MethodChainSetter + * + * Method Chain setter, used to construct MethodChain when parsing with boost::spirit + * + */ +#include "CommonTools/Utils/interface/parser/MethodChain.h" +#include "CommonTools/Utils/interface/parser/MethodStack.h" +#include "CommonTools/Utils/interface/parser/TypeStack.h" + +#include + +namespace reco { + namespace parser { + struct MethodChainSetter { + MethodChainSetter(MethodChainPtr &methchain, + MethodStack &methStack, + LazyMethodStack &lazyMethStack, + TypeStack &typeStack) + : methchain_(methchain), methStack_(methStack), lazyMethStack_(lazyMethStack), typeStack_(typeStack) {} + void operator()(const char *, const char *) const; + + private: + void push(const char *, const char *) const; + void lazyPush(const char *, const char *) const; + + MethodChainPtr &methchain_; + MethodStack &methStack_; + LazyMethodStack &lazyMethStack_; + TypeStack &typeStack_; + }; + } // namespace parser +} // namespace reco + +#endif diff --git a/CommonTools/Utils/src/MethodChain.cc b/CommonTools/Utils/src/MethodChain.cc new file mode 100644 index 0000000000000..39554f33b4ae2 --- /dev/null +++ b/CommonTools/Utils/src/MethodChain.cc @@ -0,0 +1,122 @@ +#include "CommonTools/Utils/interface/parser/MethodChain.h" +#include "CommonTools/Utils/interface/parser/MethodInvoker.h" + +#include "FWCore/Reflection/interface/ObjectWithDict.h" +#include "FWCore/Reflection/interface/FunctionWithDict.h" +#include "FWCore/Reflection/interface/MemberWithDict.h" +#include "FWCore/Reflection/interface/TypeWithDict.h" + +#include +#include + +using namespace reco::parser; +using namespace std; + +MethodChain::Objects MethodChain::initObjects_() const { + Objects objects(methods_.size(), {edm::ObjectWithDict(), false}); + assert(objects.size() == methods_.size()); + auto IO = objects.begin(); + for (auto const& method : methods_) { + if (method.isFunction()) { + edm::TypeWithDict retType = method.method().finalReturnType(); + IO->second = makeStorage(IO->first, retType); + } else { + *IO = {edm::ObjectWithDict(), false}; + } + ++IO; + } + return objects; +} + +MethodChain::MethodChain(const vector& methods) : methods_(methods) { returnObjects(initObjects_()); } + +MethodChain::MethodChain(const MethodChain& rhs) : methods_(rhs.methods_) { returnObjects(initObjects_()); } + +MethodChain::Objects MethodChain::borrowObjects() const { + Objects objects; + if (objectsCache_.try_pop(objects)) { + return objects; + } + return initObjects_(); +} + +void MethodChain::returnObjects(Objects&& iOb) const { objectsCache_.push(std::move(iOb)); } + +MethodChain::~MethodChain() { + Objects objects; + while (objectsCache_.try_pop(objects)) { + for (auto& o : objects) { + delStorage(o.first); + } + } +} + +void MethodChain::delStorage(edm::ObjectWithDict& obj) { + if (!obj.address()) { + return; + } + if (obj.typeOf().isPointer() || obj.typeOf().isReference()) { + // just delete a void*, as that's what it was + void** p = static_cast(obj.address()); + delete p; + } else { + //std::cout << "Calling Destruct on a " << + // obj.typeOf().qualifiedName() << std::endl; + obj.typeOf().deallocate(obj.address()); + } +} + +bool MethodChain::makeStorage(edm::ObjectWithDict& obj, const edm::TypeWithDict& retType) { + static const edm::TypeWithDict tVoid(edm::TypeWithDict::byName("void")); + bool ret = false; + if (retType == tVoid) { + obj = edm::ObjectWithDict::byType(tVoid); + } else if (retType.isPointer() || retType.isReference()) { + // in this case, I have to allocate a void*, not an object! + obj = edm::ObjectWithDict(retType, new void*); + } else { + obj = edm::ObjectWithDict(retType, retType.allocate()); + ret = retType.isClass(); + //std::cout << "MethodChain: reserved memory at " << obj.address() << + // " for a " << retType.qualifiedName() << " returned by " << + // member.name() << std::endl; + } + return ret; +} + +edm::ObjectWithDict MethodChain::value(const edm::ObjectWithDict& obj) const { + edm::ObjectWithDict val(obj); + auto objects = borrowObjects(); + auto IO = objects.begin(); + for (auto& m : methods_) { + val = m.invoke(val, IO->first); + ++IO; + } + for (auto RI = objects.rbegin(), RE = objects.rend(); RI != RE; ++RI) { + if (RI->second) { + RI->first.destruct(false); + } + } + returnObjects(std::move(objects)); + return val; +} + +LazyMethodChain::LazyMethodChain(const std::vector& methods) : methods_(methods) {} + +LazyMethodChain::~LazyMethodChain() {} + +edm::ObjectWithDict LazyMethodChain::value(const edm::ObjectWithDict& o) const { + edm::ObjectWithDict val = o; + std::vector storage; + storage.reserve(methods_.size()); + + std::vector::const_iterator I = methods_.begin(); + std::vector::const_iterator E = methods_.end(); + for (; I < E; ++I) { + val = I->invoke(val, storage); + } + while (not storage.empty()) { + storage.pop_back(); + } + return val; +} diff --git a/CommonTools/Utils/src/MethodChainSetter.cc b/CommonTools/Utils/src/MethodChainSetter.cc new file mode 100644 index 0000000000000..67371d0ecf0b3 --- /dev/null +++ b/CommonTools/Utils/src/MethodChainSetter.cc @@ -0,0 +1,30 @@ +#include "CommonTools/Utils/interface/parser/MethodChainSetter.h" +#include "CommonTools/Utils/interface/parser/MethodChain.h" +#include "CommonTools/Utils/interface/returnType.h" +#include "CommonTools/Utils/interface/parser/Exception.h" +#include + +using namespace reco::parser; +using namespace std; + +void MethodChainSetter::operator()(const char *begin, const char *end) const { + //std::cerr << "MethodChainSetter: Pushed [" << std::string(begin,end) << "]" << std::endl; + if (!methStack_.empty()) + push(begin, end); + else if (!lazyMethStack_.empty()) + lazyPush(begin, end); + else + throw Exception(begin) << " Expression didn't parse neither hastily nor lazyly. This must not happen.\n"; +} + +void MethodChainSetter::push(const char *begin, const char *end) const { + methchain_ = std::shared_ptr(new MethodChain(methStack_)); + methStack_.clear(); + typeStack_.resize(1); +} + +void MethodChainSetter::lazyPush(const char *begin, const char *end) const { + methchain_ = std::shared_ptr(new LazyMethodChain(lazyMethStack_)); + lazyMethStack_.clear(); + typeStack_.resize(1); +} diff --git a/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h b/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h index b93ace3c45387..edf00a8f8e18a 100644 --- a/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h +++ b/PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h @@ -14,6 +14,7 @@ #include "CommonTools/Utils/interface/StringCutObjectSelector.h" #include "CommonTools/Utils/interface/StringObjectFunction.h" +#include "CommonTools/Utils/interface/TypedStringObjectMethodCaller.h" #include #include @@ -73,6 +74,55 @@ class FuncVariable : public Variable { StringFunctor precisionFunc_; }; +// Collection variables: i.e. variables that is variable-size collection, e.g. std::vector +template +class CollectionVariable : public VariableBase { +public: + CollectionVariable(const std::string &aname, const edm::ParameterSet &cfg) : VariableBase(aname, cfg) {} + virtual std::unique_ptr> getCounts(std::vector &selobjs) const = 0; + virtual void fill(std::vector &selobjs, nanoaod::FlatTable &out) const = 0; +}; + +template +class FuncCollectionVariable : public CollectionVariable { +public: + FuncCollectionVariable(const std::string &aname, const edm::ParameterSet &cfg) + : CollectionVariable(aname, cfg), + func_(cfg.getParameter("expr"), cfg.getUntrackedParameter("lazyEval")), + precisionFunc_(cfg.existsAs("precision") ? cfg.getParameter("precision") : "23", + cfg.getUntrackedParameter("lazyEval")) {} + ~FuncCollectionVariable() override {} + + std::unique_ptr> getCounts(std::vector &selobjs) const override { + auto counts = std::make_unique>(); + for (auto const &obj : selobjs) + counts->push_back(func_(*obj).size()); + return counts; + } + + void fill(std::vector &selobjs, nanoaod::FlatTable &out) const override { + std::vector vals; + for (unsigned int i = 0; i < selobjs.size(); ++i) { + for (ValType val : func_(*selobjs[i])) { + if constexpr (std::is_same()) { + if (this->precision_ == -2) { + auto prec = precisionFunc_(*selobjs[i]); + if (prec > 0) { + val = MiniFloatConverter::reduceMantissaToNbitsRounding(val, prec); + } + } + } + vals.push_back(val); + } + } + out.template addColumn(this->name_, vals, this->doc_, this->precision_); + } + +protected: + CollectionStringFunctor func_; // functor to get collection objects + PrecisionStringFunctor precisionFunc_; // functor to get output precision +}; + // External variables: i.e. variables that are not member or methods of the object template class ExtVariable : public VariableBase { @@ -486,6 +536,186 @@ class SimpleTypedExternalFlatTableProducer : public SimpleFlatTableProducer { typedef TypedValueMapVariable, uint16_t> UInt16TypedExtVar; }; +template +class SimpleCollectionFlatTableProducer : public SimpleFlatTableProducer { +public: + SimpleCollectionFlatTableProducer(edm::ParameterSet const ¶ms) : SimpleFlatTableProducer(params) { + if (params.existsAs("collectionVariables")) { + edm::ParameterSet const &collectionVarsPSet = params.getParameter("collectionVariables"); + for (const std::string &coltablename : + collectionVarsPSet.getParameterNamesForType()) { // tables of variables + const auto &coltablePSet = collectionVarsPSet.getParameter(coltablename); + CollectionVariableTableInfo coltable; + coltable.name = + coltablePSet.existsAs("name") ? coltablePSet.getParameter("name") : coltablename; + coltable.doc = coltablePSet.getParameter("doc"); + coltable.useCount = coltablePSet.getParameter("useCount"); + coltable.useOffset = coltablePSet.getParameter("useOffset"); + const auto &colvarsPSet = coltablePSet.getParameter("variables"); + for (const std::string &colvarname : colvarsPSet.getParameterNamesForType()) { // variables + const auto &colvarPSet = colvarsPSet.getParameter(colvarname); + const std::string &type = colvarPSet.getParameter("type"); + if (type == "int") + coltable.colvars.push_back(std::make_unique(colvarname, colvarPSet)); + else if (type == "uint") + coltable.colvars.push_back(std::make_unique(colvarname, colvarPSet)); + else if (type == "float") + coltable.colvars.push_back(std::make_unique(colvarname, colvarPSet)); + else if (type == "double") + coltable.colvars.push_back(std::make_unique(colvarname, colvarPSet)); + else if (type == "uint8") + coltable.colvars.push_back(std::make_unique(colvarname, colvarPSet)); + else if (type == "int16") + coltable.colvars.push_back(std::make_unique(colvarname, colvarPSet)); + else if (type == "uint16") + coltable.colvars.push_back(std::make_unique(colvarname, colvarPSet)); + else + throw cms::Exception("Configuration", + "unsupported type " + type + " for variable " + colvarname + " in " + coltablename); + } + this->coltables.push_back(std::move(coltable)); + edm::stream::EDProducer<>::produces(coltables.back().name + "Table"); + } + } + } + + ~SimpleCollectionFlatTableProducer() override {} + + static void fillDescriptions(edm::ConfigurationDescriptions &descriptions) { + edm::ParameterSetDescription desc = SimpleFlatTableProducer::baseDescriptions(); + edm::ParameterSetDescription colvariable; + colvariable.add("expr")->setComment( + "a function to define the content of the branch in the flat table"); + colvariable.add("doc")->setComment("few words of self documentation"); + colvariable.addUntracked("lazyEval", false) + ->setComment("if true, can use methods of inheriting classes in `expr`. Can cause problems with threading."); + colvariable.ifValue(edm::ParameterDescription( + "type", "int", true, edm::Comment("the c++ type of the branch in the flat table")), + edm::allowedValues("int", "uint", "float", "double", "uint8", "int16", "uint16")); + colvariable.addOptionalNode( + edm::ParameterDescription( + "precision", true, edm::Comment("the precision with which to store the value in the flat table")) xor + edm::ParameterDescription( + "precision", true, edm::Comment("the precision with which to store the value in the flat table")), + false); + edm::ParameterSetDescription colvariables; + colvariables.setComment("a parameters set to define all variable to fill the flat table"); + colvariables.addNode( + edm::ParameterWildcard("*", edm::RequireAtLeastOne, true, colvariable)); + + edm::ParameterSetDescription coltable; + coltable.addOptional("name")->setComment( + "name of the branch in the flat table containing flatten collections of variables"); + coltable.add("doc")->setComment( + "few words description of the table containing flatten collections of variables"); + coltable.add("useCount", true) + ->setComment("whether to use count for the main table to index table with flatten collections of variables"); + coltable.add("useOffset", false) + ->setComment("whether to use offset for the main table to index table with flatten collections of variables"); + coltable.add("variables", colvariables); + + edm::ParameterSetDescription coltables; + coltables.setComment("a parameters set to define variables to be flatten to fill the table"); + coltables.addOptionalNode( + edm::ParameterWildcard("*", edm::RequireZeroOrMore, true, coltable), false); + desc.addOptional("collectionVariables", coltables); + + descriptions.addWithDefaultLabel(desc); + } + + void produce(edm::Event &iEvent, const edm::EventSetup &iSetup) override { + // same as SimpleFlatTableProducer + edm::Handle> prod; + iEvent.getByToken(this->src_, prod); + + std::vector selobjs; + std::vector> selptrs; // for external variables + if (prod.isValid() || !(this->skipNonExistingSrc_)) { + if (this->singleton_) { + assert(prod->size() == 1); + selobjs.push_back(&(*prod)[0]); + if (!this->extvars_.empty() || !this->typedextvars_.empty()) + selptrs.emplace_back(prod->ptrAt(0)); + } else { + for (unsigned int i = 0, n = prod->size(); i < n; ++i) { + const auto &obj = (*prod)[i]; + if (this->cut_(obj)) { + selobjs.push_back(&obj); + if (!this->extvars_.empty() || !this->typedextvars_.empty()) + selptrs.emplace_back(prod->ptrAt(i)); + } + if (selobjs.size() >= this->maxLen_) + break; + } + } + } + + auto out = std::make_unique(selobjs.size(), this->name_, this->singleton_, this->extension_); + for (const auto &var : this->vars_) + var->fill(selobjs, *out); + for (const auto &var : this->extvars_) + var->fill(iEvent, selptrs, *out); + for (const auto &var : this->typedextvars_) + var->fill(iEvent, selptrs, *out); + + // collection variable tables + for (const auto &coltable : this->coltables) { + std::unique_ptr> counts = coltable.colvars[0]->getCounts(selobjs); + // compute size + unsigned int coltablesize = 0; + for (auto const &count : *counts) + coltablesize += count; + // add count branch if requested + if (coltable.useCount) + out->template addColumn("n" + coltable.name, *counts, "counts for " + coltable.name); + // add offset branch if requested + if (coltable.useOffset) { + unsigned int offset = 0; + std::vector offsets; + for (auto const &count : *counts) { + offsets.push_back(offset); + offset += count; + } + out->template addColumn("o" + coltable.name, offsets, "offsets for " + coltable.name); + } + + std::unique_ptr outcoltable = + std::make_unique(coltablesize, coltable.name, false, false); + for (const auto &colvar : coltable.colvars) { + colvar->fill(selobjs, *outcoltable); + } + outcoltable->setDoc(coltable.doc); + iEvent.put(std::move(outcoltable), coltable.name + "Table"); + } + + // put the main table into the event + out->setDoc(this->doc_); + iEvent.put(std::move(out)); + } + +protected: + template + using VectorVar = + FuncCollectionVariable>, StringObjectFunction, R>; + + using IntVectorVar = VectorVar; + using UIntVectorVar = VectorVar; + using FloatVectorVar = VectorVar; + using DoubleVectorVar = VectorVar; + using UInt8VectorVar = VectorVar; + using Int16VectorVar = VectorVar; + using UInt16VectorVar = VectorVar; + + struct CollectionVariableTableInfo { + std::string name; + std::string doc; + bool useCount; + bool useOffset; + std::vector>> colvars; + }; + std::vector coltables; +}; + template class BXVectorSimpleFlatTableProducer : public SimpleFlatTableProducerBase> { public: diff --git a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc index c3c3b1e769575..aa12667124e13 100644 --- a/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc +++ b/PhysicsTools/NanoAOD/plugins/SimpleFlatTableProducerPlugins.cc @@ -3,6 +3,8 @@ #include "DataFormats/Candidate/interface/Candidate.h" typedef SimpleFlatTableProducer SimpleCandidateFlatTableProducer; +typedef SimpleCollectionFlatTableProducer SimpleCandidateCollectionFlatTableProducer; + #include "DataFormats/TrackReco/interface/Track.h" typedef SimpleFlatTableProducer SimpleTrackFlatTableProducer; @@ -50,6 +52,7 @@ typedef EventSingletonSimpleFlatTableProducer SimpleBeamspotFlat #include "FWCore/Framework/interface/MakerMacros.h" DEFINE_FWK_MODULE(SimpleCandidateFlatTableProducer); +DEFINE_FWK_MODULE(SimpleCandidateCollectionFlatTableProducer); DEFINE_FWK_MODULE(SimpleTrackFlatTableProducer); DEFINE_FWK_MODULE(SimpleSuperclusterFlatTableProducer); DEFINE_FWK_MODULE(SimplePFJetFlatTableProducer);