diff --git a/Configuration/PyReleaseValidation/python/relval_nano.py b/Configuration/PyReleaseValidation/python/relval_nano.py index 3eb5dcff90122..25e6311d175fe 100644 --- a/Configuration/PyReleaseValidation/python/relval_nano.py +++ b/Configuration/PyReleaseValidation/python/relval_nano.py @@ -225,6 +225,12 @@ def next(self, index: int = None) -> None: steps['ScoutingPFMonitor2024MINIAOD14.0'] = {'INPUT': InputInfo(location='STD', ls=lumis_Run2024D, dataSet='/ScoutingPFMonitor/Run2024D-PromptReco-v1/MINIAOD')} +steps['L1Scouting2024RAW14.0'] = {'INPUT': InputInfo(location='STD', ls={386873: [[1, 332]]}, + dataSet='/L1Scouting/Run2024I-v1/L1SCOUT')} + +steps['L1ScoutingSelection2024RAW14.0'] = {'INPUT': InputInfo(location='STD', ls={386873: [[1, 332]]}, + dataSet='/L1ScoutingSelection/Run2024I-v1/L1SCOUT')} + steps['ZMuSkim2024RAWRECO14.0'] = {'INPUT': InputInfo(location='STD', ls=lumis_Run2024D, dataSet='/Muon0/Run2024D-ZMu-PromptReco-v1/RAW-RECO')} @@ -261,6 +267,12 @@ def next(self, index: int = None) -> None: steps['scoutingNANO_withPrompt_data14.0'] = merge([{'-s': 'NANO:@Prompt+@ScoutMonitor'}, steps['NANO_data14.0']]) +steps['l1ScoutingNANO_data14.0'] = merge([{'-s': 'NANO:@L1Scout', '-n': '1000'}, + steps['NANO_data14.0']]) + +steps['l1ScoutingSelectionNANO_data14.0'] = merge([{'-s': 'NANO:@L1ScoutSelect', '-n': '1000'}, + steps['NANO_data14.0']]) + # DPG custom NANO steps['muDPGNANO_data14.0'] = merge([{'-s': 'RAW2DIGI,NANO:@MUDPG', '-n': '100'}, steps['NANO_data14.0']]) @@ -456,6 +468,8 @@ def next(self, index: int = None) -> None: workflows[_wfn()] = ['lepTrackInfoNANOdata140Xrun3', ['MuonEG2024MINIAOD14.0', 'lepTrackInfoNANO_data14.0']] workflows[_wfn()] = ['ScoutingNANOdata140Xrun3', ['ScoutingPFRun32024RAW14.0', 'scoutingNANO_data14.0']] workflows[_wfn()] = ['ScoutingNANOwithPromptdata140Xrun3', ['ScoutingPFMonitor2024MINIAOD14.0', 'scoutingNANO_withPrompt_data14.0']] +workflows[_wfn()] = ['L1ScoutingNANOdata140Xrun3', ['L1Scouting2024RAW14.0', 'l1ScoutingNANO_data14.0']] +workflows[_wfn()] = ['L1ScoutingSelectionNANOdata140Xrun3', ['L1ScoutingSelection2024RAW14.0', 'l1ScoutingSelectionNANO_data14.0']] # DPG custom NANOs, data _wfn.subnext() diff --git a/DataFormats/L1Scouting/interface/OrbitCollection.h b/DataFormats/L1Scouting/interface/OrbitCollection.h index d1376436f66ef..a0826a3c36619 100644 --- a/DataFormats/L1Scouting/interface/OrbitCollection.h +++ b/DataFormats/L1Scouting/interface/OrbitCollection.h @@ -117,6 +117,9 @@ class OrbitCollection { T& operator[](std::size_t i) { return data_[i]; } const T& operator[](std::size_t i) const { return data_[i]; } + //used by OrbitFlatTable + const std::vector& bxOffsets() const { return bxOffsets_; }; + // used by ROOT storage CMS_CLASS_VERSION(3) diff --git a/DataFormats/L1Scouting/src/classes_def.xml b/DataFormats/L1Scouting/src/classes_def.xml index a81f921621cd7..364be98166efe 100644 --- a/DataFormats/L1Scouting/src/classes_def.xml +++ b/DataFormats/L1Scouting/src/classes_def.xml @@ -46,5 +46,5 @@ - + diff --git a/DataFormats/NanoAOD/interface/FlatTable.h b/DataFormats/NanoAOD/interface/FlatTable.h index b12ed53ddaac1..6a2f6a9058291 100644 --- a/DataFormats/NanoAOD/interface/FlatTable.h +++ b/DataFormats/NanoAOD/interface/FlatTable.h @@ -184,7 +184,7 @@ namespace nanoaod { : name(aname), doc(docString), type(atype), firstIndex(anIndex) {} }; - private: + protected: template auto beginData(unsigned int column) const { return bigVector().cbegin() + columns_[column].firstIndex; @@ -194,6 +194,7 @@ namespace nanoaod { return bigVector().begin() + columns_[column].firstIndex; } + private: template auto const &bigVector() const { return bigVectorImpl(*this); diff --git a/DataFormats/NanoAOD/interface/OrbitFlatTable.h b/DataFormats/NanoAOD/interface/OrbitFlatTable.h new file mode 100644 index 0000000000000..1a5ad409de8a0 --- /dev/null +++ b/DataFormats/NanoAOD/interface/OrbitFlatTable.h @@ -0,0 +1,102 @@ +#ifndef DataFormats_L1Scouting_OrbitFlatTable_h +#define DataFormats_L1Scouting_OrbitFlatTable_h + +/** + * A cross-breed of a FlatTable and an OrbitCollection + */ + +#include "DataFormats/NanoAOD/interface/FlatTable.h" + +#include +#include +#include +#include + +namespace l1ScoutingRun3 { + + class OrbitFlatTable : public nanoaod::FlatTable { + public: + static constexpr unsigned int NBX = 3564; + + OrbitFlatTable() : nanoaod::FlatTable(), bxOffsets_(orbitBufferSize_ + 1, 0) {} + + OrbitFlatTable(std::vector bxOffsets, + const std::string &name, + bool singleton = false, + bool extension = false) + : nanoaod::FlatTable(bxOffsets.back(), name, singleton, extension), bxOffsets_(bxOffsets) { + if (bxOffsets.size() != orbitBufferSize_ + 1) { + throw cms::Exception("LogicError") << "Mismatch between bxOffsets.size() " << bxOffsets.size() + << " and orbitBufferSize_ + 1" << (orbitBufferSize_ + 1); + } + } + + ~OrbitFlatTable() {} + + using FlatTable::nRows; + using FlatTable::size; + + /// number of rows for single BX + unsigned int nRows(unsigned bx) const { + if (bx >= orbitBufferSize_) + throwBadBx(bx); + return bxOffsets_[bx + 1] - bxOffsets_[bx]; + }; + unsigned int size(unsigned bx) const { return nRows(bx); } + + /// get a column by index (const) + template + auto columnData(unsigned int column) const { + return nanoaod::FlatTable::columnData(column); + } + + /// get a column by index and bx (const) + template + auto columnData(unsigned int column, unsigned bx) const { + if (bx >= orbitBufferSize_) + throwBadBx(bx); + auto begin = beginData(column); + return std::span(begin + bxOffsets_[bx], begin + bxOffsets_[bx + 1]); + } + + /// get a column by index (non-const) + template + auto columnData(unsigned int column) { + return nanoaod::FlatTable::columnData(column); + } + + /// get a column by index and bx (non-const) + template + auto columnData(unsigned int column, unsigned bx) { + if (bx >= orbitBufferSize_) + throwBadBx(bx); + auto begin = beginData(column); + return std::span(begin + bxOffsets_[bx], begin + bxOffsets_[bx + 1]); + } + + /// get a column value for singleton (const) + template + const auto &columValue(unsigned int column, unsigned bx) const { + if (!singleton()) + throw cms::Exception("LogicError", "columnValue works only for singleton tables"); + if (bx >= orbitBufferSize_ || bxOffsets_[bx + 1] == bxOffsets_[bx]) + throwBadBx(bx); + auto begin = beginData(column); + return *(begin + bxOffsets_[bx]); + } + + private: + std::vector bxOffsets_; + + // there are 3564 BX in one orbtit [1,3564], one extra + // count added to keep first entry of the vector + static constexpr int orbitBufferSize_ = NBX + 1; + + [[noreturn]] void throwBadBx(unsigned bx) const { + throw cms::Exception("OrbitFlatTable") << "Trying to access bad bx " << bx; + } + }; + +} // namespace l1ScoutingRun3 + +#endif diff --git a/DataFormats/NanoAOD/src/classes.h b/DataFormats/NanoAOD/src/classes.h index acdf6f161f7cb..b4cf7b8f40850 100644 --- a/DataFormats/NanoAOD/src/classes.h +++ b/DataFormats/NanoAOD/src/classes.h @@ -1,6 +1,7 @@ #include "Rtypes.h" #include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "DataFormats/NanoAOD/interface/OrbitFlatTable.h" #include "DataFormats/NanoAOD/interface/MergeableCounterTable.h" #include "DataFormats/NanoAOD/interface/UniqueString.h" #include "DataFormats/Common/interface/Wrapper.h" diff --git a/DataFormats/NanoAOD/src/classes_def.xml b/DataFormats/NanoAOD/src/classes_def.xml index 37611ab572d1a..188873a69e885 100644 --- a/DataFormats/NanoAOD/src/classes_def.xml +++ b/DataFormats/NanoAOD/src/classes_def.xml @@ -44,5 +44,10 @@ + + + + + diff --git a/L1TriggerScouting/Utilities/plugins/BuildFile.xml b/L1TriggerScouting/Utilities/plugins/BuildFile.xml index 3b64e94601896..9aa83f2b1afe8 100644 --- a/L1TriggerScouting/Utilities/plugins/BuildFile.xml +++ b/L1TriggerScouting/Utilities/plugins/BuildFile.xml @@ -1,8 +1,15 @@ + + + + + + + diff --git a/L1TriggerScouting/Utilities/plugins/L1ScoutingEtSumOrbitFlatTableProducer.cc b/L1TriggerScouting/Utilities/plugins/L1ScoutingEtSumOrbitFlatTableProducer.cc new file mode 100644 index 0000000000000..9630fd6e5326f --- /dev/null +++ b/L1TriggerScouting/Utilities/plugins/L1ScoutingEtSumOrbitFlatTableProducer.cc @@ -0,0 +1,416 @@ +#include + +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/MakerMacros.h" + +#include "DataFormats/L1Scouting/interface/OrbitCollection.h" +#include "DataFormats/NanoAOD/interface/OrbitFlatTable.h" +#include "DataFormats/L1Scouting/interface/L1ScoutingCalo.h" +#include "DataFormats/L1Trigger/interface/EtSum.h" +#include "L1TriggerScouting/Utilities/interface/conversion.h" + +class L1ScoutingEtSumOrbitFlatTableProducer : public edm::stream::EDProducer<> { +public: + explicit L1ScoutingEtSumOrbitFlatTableProducer(const edm::ParameterSet&); + ~L1ScoutingEtSumOrbitFlatTableProducer() override = default; + + static void fillDescriptions(edm::ConfigurationDescriptions&); + + void produce(edm::Event&, edm::EventSetup const&) override; + +private: + std::unique_ptr produceSingle(l1ScoutingRun3::BxSumsOrbitCollection const&) const; + std::unique_ptr produceMultiple(l1ScoutingRun3::BxSumsOrbitCollection const&) const; + + edm::EDGetTokenT src_; + + std::string name_; + std::string doc_; + bool singleton_; + bool writePhysicalValues_; + bool writeHardwareValues_; + bool writeHF_; + bool writeAsym_; + bool writeMinBias_; + bool writeTowerCount_; + bool writeCentrality_; + int ptPrecision_; + int phiPrecision_; +}; + +L1ScoutingEtSumOrbitFlatTableProducer::L1ScoutingEtSumOrbitFlatTableProducer(const edm::ParameterSet& params) + : src_(consumes>(params.getParameter("src"))), + name_(params.getParameter("name")), + doc_(params.getParameter("doc")), + singleton_(params.getParameter("singleton")), + writePhysicalValues_(params.getParameter("writePhysicalValues")), + writeHardwareValues_(params.getParameter("writeHardwareValues")), + writeHF_(params.getParameter("writeHF")), + writeAsym_(params.getParameter("writeAsym")), + writeMinBias_(params.getParameter("writeMinBias")), + writeTowerCount_(params.getParameter("writeTowerCount")), + writeCentrality_(params.getParameter("writeCentrality")), + ptPrecision_(params.getParameter("ptPrecision")), + phiPrecision_(params.getParameter("phiPrecision")) { + if (!writePhysicalValues_ && !writeHardwareValues_) { + throw cms::Exception("L1ScoutingEtSumOrbitFlatTableProducer") + << "writePhysicalValues and writeHardwareValues cannot be false at the same time!"; + } + produces(); +} + +void L1ScoutingEtSumOrbitFlatTableProducer::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + + desc.add("src"); + desc.add("name"); + desc.add("doc"); + desc.add("singleton", true) + ->setComment("whether to output as singleton (one EtSum per bx) or not (multiple EtSums per bx)"); + desc.add("writePhysicalValues", true); + desc.add("writeHardwareValues", false); + desc.add("writeHF", true); + desc.add("writeAsym", true); + desc.add("writeMinBias", true); + desc.add("writeTowerCount", true); + desc.add("writeCentrality", true); + desc.add("ptPrecision", -1); + desc.add("phiPrecision", -1); + + descriptions.addDefault(desc); +} + +void L1ScoutingEtSumOrbitFlatTableProducer::produce(edm::Event& iEvent, edm::EventSetup const&) { + edm::Handle src; + iEvent.getByToken(src_, src); + + auto out = singleton_ ? produceSingle(*src) : produceMultiple(*src); + iEvent.put(std::move(out)); +} + +std::unique_ptr L1ScoutingEtSumOrbitFlatTableProducer::produceSingle( + l1ScoutingRun3::BxSumsOrbitCollection const& src) const { + using namespace l1ScoutingRun3; + auto out = std::make_unique(src.bxOffsets(), name_, /*singleton=*/true); + out->setDoc(doc_); + + unsigned int nobjs = out->size(); + + // physical values (float) + std::vector totalEt(nobjs); + std::vector totalEtEm(nobjs); + std::vector missEt(nobjs); + std::vector missEtPhi(nobjs); + std::vector missEtHF(nobjs); + std::vector missEtHFPhi(nobjs); + std::vector totalHt(nobjs); + std::vector missHt(nobjs); + std::vector missHtPhi(nobjs); + std::vector missHtHF(nobjs); + std::vector missHtHFPhi(nobjs); + std::vector asymEt(nobjs); + std::vector asymHt(nobjs); + std::vector asymEtHF(nobjs); + std::vector asymHtHF(nobjs); + + // hardware values (int) + std::vector hwTotalEt(nobjs); + std::vector hwTotalEtEm(nobjs); + std::vector hwMissEt(nobjs); + std::vector hwMissEtPhi(nobjs); + std::vector hwMissEtHF(nobjs); + std::vector hwMissEtHFPhi(nobjs); + std::vector hwTotalHt(nobjs); + std::vector hwMissHt(nobjs); + std::vector hwMissHtPhi(nobjs); + std::vector hwMissHtHF(nobjs); + std::vector hwMissHtHFPhi(nobjs); + std::vector hwAsymEt(nobjs); + std::vector hwAsymHt(nobjs); + std::vector hwAsymEtHF(nobjs); + std::vector hwAsymHtHF(nobjs); + + std::vector minBiasHFP0(nobjs); + std::vector minBiasHFM0(nobjs); + std::vector minBiasHFP1(nobjs); + std::vector minBiasHFM1(nobjs); + std::vector towerCount(nobjs); + std::vector centrality(nobjs); + + for (unsigned int i = 0; i < nobjs; i++) { + const auto& sums = src[i]; + + // physical values + totalEt[i] = demux::fEt(sums.hwTotalEt()); + totalEtEm[i] = demux::fEt(sums.hwTotalEtEm()); + missEt[i] = demux::fEt(sums.hwMissEt()); + missEtPhi[i] = demux::fPhi(sums.hwMissEtPhi()); + missEtHF[i] = demux::fEt(sums.hwMissEtHF()); + missEtHFPhi[i] = demux::fPhi(sums.hwMissEtHFPhi()); + totalHt[i] = demux::fEt(sums.hwTotalHt()); + missHt[i] = demux::fEt(sums.hwMissHt()); + missHtPhi[i] = demux::fPhi(sums.hwMissHtPhi()); + missHtHF[i] = demux::fEt(sums.hwMissHtHF()); + missHtHFPhi[i] = demux::fPhi(sums.hwMissHtHFPhi()); + asymEt[i] = demux::fEt(sums.hwAsymEt()); + asymHt[i] = demux::fEt(sums.hwAsymHt()); + asymEtHF[i] = demux::fEt(sums.hwAsymEtHF()); + asymHtHF[i] = demux::fEt(sums.hwAsymHtHF()); + + // hardware values + hwTotalEt[i] = sums.hwTotalEt(); + hwTotalEtEm[i] = sums.hwTotalEtEm(); + hwMissEt[i] = sums.hwMissEt(); + hwMissEtPhi[i] = sums.hwMissEtPhi(); + hwMissEtHF[i] = sums.hwMissEtHF(); + hwMissEtHFPhi[i] = sums.hwMissEtHFPhi(); + hwTotalHt[i] = sums.hwTotalHt(); + hwMissHt[i] = sums.hwMissHt(); + hwMissHtPhi[i] = sums.hwMissHtPhi(); + hwMissHtHF[i] = sums.hwMissHtHF(); + hwMissHtHFPhi[i] = sums.hwMissHtHFPhi(); + hwAsymEt[i] = sums.hwAsymEt(); + hwAsymHt[i] = sums.hwAsymHt(); + hwAsymEtHF[i] = sums.hwAsymEtHF(); + hwAsymHtHF[i] = sums.hwAsymHtHF(); + + minBiasHFP0[i] = sums.minBiasHFP0(); + minBiasHFM0[i] = sums.minBiasHFM0(); + minBiasHFP1[i] = sums.minBiasHFP1(); + minBiasHFM1[i] = sums.minBiasHFM1(); + towerCount[i] = sums.towerCount(); + centrality[i] = sums.centrality(); + } + + // fill table + + if (writePhysicalValues_) { + out->template addColumn("totalEt", totalEt, "totalEt", ptPrecision_); + out->template addColumn("totalEtEm", totalEtEm, "totalEtEm", ptPrecision_); + out->template addColumn("missEt", missEt, "missEt pt", ptPrecision_); + out->template addColumn("missEtPhi", missEtPhi, "missEt phi", phiPrecision_); + out->template addColumn("totalHt", totalHt, "totalHt", ptPrecision_); + out->template addColumn("missHt", missHt, "missHt pt", ptPrecision_); + out->template addColumn("missHtPhi", missHtPhi, "missHt phi", phiPrecision_); + } + if (writeHardwareValues_) { + out->template addColumn("hwTotalEt", hwTotalEt, "hardware totalEt"); + out->template addColumn("hwTotalEtEm", hwTotalEtEm, "hardware totalEtEm"); + out->template addColumn("hwMissEt", hwMissEt, "hardware missEt pt"); + out->template addColumn("hwMissEtPhi", hwMissEtPhi, "hardware missEt phi"); + out->template addColumn("hwTotalHt", hwTotalHt, "hardware totalHt"); + out->template addColumn("hwMissHt", hwMissHt, "hardware missHt pt"); + out->template addColumn("hwMissHtPhi", hwMissHtPhi, "hardware missHt phi"); + } + + if (writeHF_) { + if (writePhysicalValues_) { + out->template addColumn("missEtHF", missEtHF, "missEtHF", ptPrecision_); + out->template addColumn("missEtHFPhi", missEtHFPhi, "missEtHF phi", phiPrecision_); + out->template addColumn("missHtHF", missHtHF, "missHtHF pt", ptPrecision_); + out->template addColumn("missHtHFPhi", missHtHFPhi, "missHtHF phi", phiPrecision_); + } + if (writeHardwareValues_) { + out->template addColumn("hwMissEtHF", hwMissEtHF, "hardware missEtHF"); + out->template addColumn("hwMissEtHFPhi", hwMissEtHFPhi, "hardware missEtHF phi"); + out->template addColumn("hwMissHtHF", hwMissHtHF, "hardware missHtHF"); + out->template addColumn("hwMissHtHFPhi", hwMissHtHFPhi, "hardware missHtHF phi"); + } + } + if (writeAsym_) { + if (writePhysicalValues_) { + out->template addColumn("asymEt", asymEt, "asymEt", ptPrecision_); + out->template addColumn("asymHt", asymHt, "asymHt", ptPrecision_); + } + if (writeHardwareValues_) { + out->template addColumn("hwAsymEt", hwAsymEt, "hardware asymEt"); + out->template addColumn("hwAsymHt", hwAsymHt, "hardware asymHt"); + } + } + + if (writeAsym_ && writeHF_) { + if (writePhysicalValues_) { + out->template addColumn("asymEtHF", asymEtHF, "asymEtHF", ptPrecision_); + out->template addColumn("asymHtHF", asymHtHF, "asymHtHF", ptPrecision_); + } + if (writeHardwareValues_) { + out->template addColumn("hwAsymEtHF", hwAsymEtHF, "asymEtHF"); + out->template addColumn("hwAsymHtHF", hwAsymHtHF, "asymHtHF"); + } + } + + if (writeMinBias_) { + out->template addColumn("minBiasHFP0", minBiasHFP0, "minBiasHFP0"); + out->template addColumn("minBiasHFM0", minBiasHFM0, "minBiasHFM0"); + out->template addColumn("minBiasHFP1", minBiasHFP1, "minBiasHFP1"); + out->template addColumn("minBiasHFM1", minBiasHFM1, "minBiasHFM1"); + } + + if (writeTowerCount_) { + out->template addColumn("towerCount", towerCount, "towerCount"); + } + + if (writeCentrality_) { + out->template addColumn("centrality", centrality, "centrality"); + } + + return out; +} + +std::unique_ptr L1ScoutingEtSumOrbitFlatTableProducer::produceMultiple( + l1ScoutingRun3::BxSumsOrbitCollection const& src) const { + using namespace l1ScoutingRun3; + // compute number of objects per bx to adjust bxOffsets + unsigned int nitems = 5; // totalEt, totalEtEm, missEt, totalHt, missHt + if (writeHF_) + nitems += 2; // missEtHF, missHtHF + if (writeAsym_) + nitems += (writeHF_ ? 4 : 2); // asymEt, asymHt, asymEtHF, asymHtHF + if (writeMinBias_) + nitems += 4; // minBiasHFP0, minBiasHFM0, minBiasHFP1, minBiasHFM1 + if (writeTowerCount_) + nitems += 1; // towerCount + if (writeCentrality_) + nitems += 1; // centrality + + // adjust bxOffsets since each bx now contains multiple objects instead of single object + std::vector offsets(src.bxOffsets()); + for (auto& v : offsets) + v *= nitems; + + auto out = std::make_unique(offsets, name_, /*singleton=*/false); + out->setDoc(doc_); + + unsigned int nobjs = out->size(); + + // physical values + std::vector pt(nobjs); + std::vector phi(nobjs, 0.); + + // hardware values + std::vector hwEt(nobjs); + std::vector hwPhi(nobjs, 0); + + std::vector sumType(nobjs); + + unsigned int i = 0; + for (const l1ScoutingRun3::BxSums& sums : src) { + assert(i + nitems <= nobjs && i % nitems == 0); + + // totalEt + pt[i] = demux::fEt(sums.hwTotalEt()); + hwEt[i] = sums.hwTotalEt(); + sumType[i++] = l1t::EtSum::kTotalEt; + // totalEtEm + pt[i] = demux::fEt(sums.hwTotalEtEm()); + hwEt[i] = sums.hwTotalEtEm(); + sumType[i++] = l1t::EtSum::kTotalEtEm; + // missEt + pt[i] = demux::fEt(sums.hwMissEt()); + phi[i] = demux::fPhi(sums.hwMissEtPhi()); + hwEt[i] = sums.hwMissEt(); + hwPhi[i] = sums.hwMissEtPhi(); + sumType[i++] = l1t::EtSum::kMissingEt; + // totalHt + pt[i] = demux::fEt(sums.hwTotalHt()); + hwEt[i] = sums.hwTotalHt(); + sumType[i++] = l1t::EtSum::kTotalHt; + // missHt + pt[i] = demux::fEt(sums.hwMissHt()); + phi[i] = demux::fPhi(sums.hwMissHtPhi()); + hwEt[i] = sums.hwMissHt(); + hwPhi[i] = sums.hwMissHtPhi(); + sumType[i++] = l1t::EtSum::kMissingHt; + + if (writeHF_) { + // missEtHF + pt[i] = demux::fEt(sums.hwMissEtHF()); + phi[i] = demux::fPhi(sums.hwMissEtHFPhi()); + hwEt[i] = sums.hwMissEtHF(); + hwPhi[i] = sums.hwMissEtHFPhi(); + sumType[i++] = l1t::EtSum::kMissingEtHF; + // missHtHF + pt[i] = demux::fEt(sums.hwMissHtHF()); + phi[i] = demux::fPhi(sums.hwMissHtHFPhi()); + hwEt[i] = sums.hwMissHtHF(); + hwPhi[i] = sums.hwMissHtHFPhi(); + sumType[i++] = l1t::EtSum::kMissingHtHF; + } + + if (writeAsym_) { + // asymEt + pt[i] = demux::fEt(sums.hwAsymEt()); + hwEt[i] = sums.hwAsymEt(); + sumType[i++] = l1t::EtSum::kAsymEt; + // asymHt + pt[i] = demux::fEt(sums.hwAsymHt()); + hwEt[i] = sums.hwAsymHt(); + sumType[i++] = l1t::EtSum::kAsymHt; + + if (writeHF_) { + // asymEtHF + pt[i] = demux::fEt(sums.hwAsymEtHF()); + hwEt[i] = sums.hwAsymEtHF(); + sumType[i++] = l1t::EtSum::kAsymEtHF; + // asymHtHF + pt[i] = demux::fEt(sums.hwAsymHtHF()); + hwEt[i] = sums.hwAsymHtHF(); + sumType[i++] = l1t::EtSum::kAsymHtHF; + } + } + + if (writeMinBias_) { + // minBiasHFP0 + pt[i] = sums.minBiasHFP0(); + hwEt[i] = sums.minBiasHFP0(); + sumType[i++] = l1t::EtSum::kMinBiasHFP0; + // minBiasHFM0 + pt[i] = sums.minBiasHFM0(); + hwEt[i] = sums.minBiasHFM0(); + sumType[i++] = l1t::EtSum::kMinBiasHFM0; + // minBiasHFP1 + pt[i] = sums.minBiasHFP1(); + hwEt[i] = sums.minBiasHFP1(); + sumType[i++] = l1t::EtSum::kMinBiasHFP1; + // minBiasHFM1 + pt[i] = sums.minBiasHFM1(); + hwEt[i] = sums.minBiasHFM1(); + sumType[i++] = l1t::EtSum::kMinBiasHFM1; + } + + if (writeTowerCount_) { + // towerCount + pt[i] = sums.towerCount(); + hwEt[i] = sums.towerCount(); + sumType[i++] = l1t::EtSum::kTowerCount; + } + + if (writeCentrality_) { + // centrality + pt[i] = sums.centrality(); + hwEt[i] = sums.centrality(); + sumType[i++] = l1t::EtSum::kCentrality; + } + } + + // fill table + + if (writePhysicalValues_) { + out->template addColumn("pt", pt, "pt", ptPrecision_); + out->template addColumn("phi", phi, "phi", phiPrecision_); + } + if (writeHardwareValues_) { + out->template addColumn("hwEt", pt, "hardware Et"); + out->template addColumn("hwPhi", phi, "hardware phi"); + } + + out->template addColumn( + "etSumType", + sumType, + "the type of the EtSum " + "(https://github.com/cms-sw/cmssw/blob/master/DataFormats/L1Trigger/interface/EtSum.h#L27-L56)"); + return out; +} + +DEFINE_FWK_MODULE(L1ScoutingEtSumOrbitFlatTableProducer); diff --git a/L1TriggerScouting/Utilities/plugins/L1ScoutingPhysicalValueMapProducer.cc b/L1TriggerScouting/Utilities/plugins/L1ScoutingPhysicalValueMapProducer.cc new file mode 100644 index 0000000000000..f51733561f17d --- /dev/null +++ b/L1TriggerScouting/Utilities/plugins/L1ScoutingPhysicalValueMapProducer.cc @@ -0,0 +1,149 @@ +// system include files +#include +#include + +// user include files +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/Event.h" +#include "FWCore/Framework/interface/EventSetup.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/allowedValues.h" + +#include "DataFormats/Common/interface/ValueMap.h" +#include "DataFormats/L1Scouting/interface/OrbitCollection.h" +#include "L1TriggerScouting/Utilities/interface/conversion.h" + +#include "CommonTools/Utils/interface/TypedStringObjectMethodCaller.h" + +/* + * Base class + */ +template +class L1ScoutingPhysicalValueMapProducer : public edm::stream::EDProducer<> { +public: + using TOrbitCollection = OrbitCollection; + + L1ScoutingPhysicalValueMapProducer(edm::ParameterSet const &); + ~L1ScoutingPhysicalValueMapProducer() override = default; + + static void fillDescriptions(edm::ConfigurationDescriptions &descriptions); + +private: + void produce(edm::Event &, edm::EventSetup const &) override; + + void putValueMap(edm::Event &, edm::Handle &, const std::vector &, const std::string &); + + edm::EDGetTokenT src_; + + static const std::unordered_map> func_lookup_; + + std::vector labels_; + std::vector> getters_; + std::vector> funcs_; +}; + +template +const std::unordered_map> L1ScoutingPhysicalValueMapProducer::func_lookup_ = { + {"ugmt::fPt", l1ScoutingRun3::ugmt::fPt}, + {"ugmt::fEta", l1ScoutingRun3::ugmt::fEta}, + {"ugmt::fPhi", l1ScoutingRun3::ugmt::fPhi}, + {"ugmt::fPtUnconstrained", l1ScoutingRun3::ugmt::fPtUnconstrained}, + {"ugmt::fEtaAtVtx", l1ScoutingRun3::ugmt::fEtaAtVtx}, + {"ugmt::fPhiAtVtx", l1ScoutingRun3::ugmt::fPhiAtVtx}, + {"demux::fEt", l1ScoutingRun3::demux::fEt}, + {"demux::fEta", l1ScoutingRun3::demux::fEta}, + {"demux::fPhi", l1ScoutingRun3::demux::fPhi}, +}; + +template +L1ScoutingPhysicalValueMapProducer::L1ScoutingPhysicalValueMapProducer(edm::ParameterSet const ¶ms) + : src_(consumes(params.getParameter("src"))) { + auto conversionsPSet = params.getParameter("conversions"); + for (const std::string &retname : conversionsPSet.getParameterNamesForType()) { + labels_.emplace_back(retname); + const auto &conversionPSet = conversionsPSet.getParameter(retname); + const std::string &arg = conversionPSet.getParameter("arg"); + getters_.emplace_back(arg); + const std::string &func_name = conversionPSet.getParameter("func"); + auto it = func_lookup_.find(func_name); + if (it != func_lookup_.end()) { + funcs_.emplace_back(it->second); + } else { + std::stringstream ss; + for (auto const &func : func_lookup_) + ss << "\n" << func.first; + throw cms::Exception("L1ScoutingPhysicalValueMapProducer") + << "Unrecognised function: " + func_name + "\nAllowed functions are" + ss.str(); + } + produces>(retname); + } +} + +template +void L1ScoutingPhysicalValueMapProducer::fillDescriptions(edm::ConfigurationDescriptions &descriptions) { + edm::ParameterSetDescription desc; + + desc.add("src"); + + edm::ParameterSetDescription conversion; + conversion.add("func")->setComment("function used to convert"); + conversion.add("arg")->setComment("attribute of src to be converted"); + + edm::ParameterSetDescription conversions; + conversions.setComment("a parameter set to define all conversions"); + conversions.addNode( + edm::ParameterWildcard("*", edm::RequireZeroOrMore, true, conversion)); + desc.add("conversions", conversions); + + descriptions.addWithDefaultLabel(desc); +} + +template +void L1ScoutingPhysicalValueMapProducer::produce(edm::Event &iEvent, edm::EventSetup const &) { + edm::Handle src = iEvent.getHandle(src_); + + unsigned int nobjs = src->size(); + unsigned int nconversions = labels_.size(); + + // convert values + std::vector> converted_values(nconversions, std::vector(nobjs)); + for (unsigned int iobj = 0; iobj < nobjs; iobj++) { + const auto &obj = (*src)[iobj]; + for (unsigned int iconversion = 0; iconversion < nconversions; iconversion++) { + int value = (getters_[iconversion])(obj); + converted_values[iconversion][iobj] = (funcs_[iconversion])(value); + } + } + + // put to ValueMap + for (unsigned int iconversion = 0; iconversion < nconversions; iconversion++) { + putValueMap(iEvent, src, converted_values[iconversion], labels_[iconversion]); + } +} + +template +void L1ScoutingPhysicalValueMapProducer::putValueMap(edm::Event &iEvent, + edm::Handle &handle, + const std::vector &values, + const std::string &label) { + std::unique_ptr> valuemap(new edm::ValueMap()); + edm::ValueMap::Filler filler(*valuemap); + filler.insert(handle, values.begin(), values.end()); + filler.fill(); + iEvent.put(std::move(valuemap), label); +} + +#include "DataFormats/L1Scouting/interface/L1ScoutingMuon.h" +using L1ScoutingMuonPhysicalValueMapProducer = L1ScoutingPhysicalValueMapProducer; + +#include "DataFormats/L1Scouting/interface/L1ScoutingCalo.h" +using L1ScoutingJetPhysicalValueMapProducer = L1ScoutingPhysicalValueMapProducer; +using L1ScoutingEGammaPhysicalValueMapProducer = L1ScoutingPhysicalValueMapProducer; +using L1ScoutingTauPhysicalValueMapProducer = L1ScoutingPhysicalValueMapProducer; + +DEFINE_FWK_MODULE(L1ScoutingMuonPhysicalValueMapProducer); +DEFINE_FWK_MODULE(L1ScoutingJetPhysicalValueMapProducer); +DEFINE_FWK_MODULE(L1ScoutingEGammaPhysicalValueMapProducer); +DEFINE_FWK_MODULE(L1ScoutingTauPhysicalValueMapProducer); diff --git a/L1TriggerScouting/Utilities/plugins/OrbitNanoAODOutputModule.cc b/L1TriggerScouting/Utilities/plugins/OrbitNanoAODOutputModule.cc new file mode 100644 index 0000000000000..b561b9129689a --- /dev/null +++ b/L1TriggerScouting/Utilities/plugins/OrbitNanoAODOutputModule.cc @@ -0,0 +1,415 @@ +// -*- C++ -*- +// +// Package: L1TriggerScouting/Utilities +// Class : OrbitNanoAODOutputModule +// +// Implementation: +// Adapt from NanoAODOutputModule for OrbitFlatTable +// This handles rotating OrbitCollection to Event +// +// +// Author original version: Giovanni Petrucciani +// adapted by Patin Inkaew + +// system include files +#include +#include + +#include "Compression.h" +#include "TFile.h" +#include "TObjString.h" +#include "TROOT.h" +#include "TTree.h" +#include + +// user include files +#include "FWCore/Framework/interface/one/OutputModule.h" +#include "FWCore/Framework/interface/RunForOutput.h" +#include "FWCore/Framework/interface/LuminosityBlockForOutput.h" +#include "FWCore/Framework/interface/EventForOutput.h" +#include "FWCore/ServiceRegistry/interface/Service.h" +#include "FWCore/Framework/interface/MakerMacros.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/MessageLogger/interface/JobReport.h" +#include "FWCore/Utilities/interface/GlobalIdentifier.h" +#include "FWCore/Utilities/interface/Digest.h" +#include "IOPool/Provenance/interface/CommonProvenanceFiller.h" +#include "DataFormats/Provenance/interface/BranchType.h" +#include "DataFormats/Provenance/interface/BranchDescription.h" +#include "DataFormats/Provenance/interface/ProcessHistoryRegistry.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "L1TriggerScouting/Utilities/plugins/OrbitTableOutputBranches.h" +#include "L1TriggerScouting/Utilities/plugins/SelectedBxTableOutputBranches.h" + +#include "oneapi/tbb/task_arena.h" + +class OrbitNanoAODOutputModule : public edm::one::OutputModule<> { +public: + OrbitNanoAODOutputModule(edm::ParameterSet const& pset); + ~OrbitNanoAODOutputModule() override; + + static void fillDescriptions(edm::ConfigurationDescriptions& descriptions); + +private: + void write(edm::EventForOutput const& e) override; + void writeLuminosityBlock(edm::LuminosityBlockForOutput const&) override; + void writeRun(edm::RunForOutput const&) override; + bool isFileOpen() const override; + void openFile(edm::FileBlock const&) override; + void reallyCloseFile() override; + + std::string m_fileName; + std::string m_logicalFileName; + int m_compressionLevel; + int m_eventsSinceFlush{0}; + std::string m_compressionAlgorithm; + bool m_skipEmptyBXs; + bool m_writeProvenance; + bool m_fakeName; //crab workaround, remove after crab is fixed + int m_autoFlush; + edm::ProcessHistoryRegistry m_processHistoryRegistry; + edm::JobReport::Token m_jrToken; + std::unique_ptr m_file; + std::unique_ptr m_tree, m_lumiTree, m_runTree, m_metaDataTree, m_parameterSetsTree; + + static constexpr int m_firstFlush{1000}; + + class CommonEventBranches { + public: + void branch(TTree& tree) { + tree.Branch("run", &m_run, "run/i"); + tree.Branch("luminosityBlock", &m_luminosityBlock, "luminosityBlock/i"); + tree.Branch("bunchCrossing", &m_bunchCrossing, "bunchCrossing/i"); + tree.Branch("orbitNumber", &m_orbitNumber, "orbitNumber/i"); + } + void fill(const edm::EventAuxiliary& aux) { + m_run = aux.id().run(); + m_luminosityBlock = aux.id().luminosityBlock(); + m_orbitNumber = aux.id().event(); // in L1Scouting, one processing event is one orbit + } + void setBx(unsigned bx) { m_bunchCrossing = bx; } + + private: + UInt_t m_run; + UInt_t m_luminosityBlock; + UInt_t m_bunchCrossing; + UInt_t m_orbitNumber; + } m_commonBranches; + + class CommonLumiBranches { + public: + void branch(TTree& tree) { + tree.Branch("run", &m_run, "run/i"); + tree.Branch("luminosityBlock", &m_luminosityBlock, "luminosityBlock/i"); + tree.Branch("nOrbits", &m_orbits, "nOrbits/i"); + } + void fill(const edm::LuminosityBlockID& id, unsigned int nOrbits) { + m_run = id.run(); + m_luminosityBlock = id.value(); + m_orbits = nOrbits; + } + + private: + UInt_t m_run; + UInt_t m_luminosityBlock; + UInt_t m_orbits; + } m_commonLumiBranches; + + class CommonRunBranches { + public: + void branch(TTree& tree) { tree.Branch("run", &m_run, "run/i"); } + void fill(const edm::RunID& id) { m_run = id.run(); } + + private: + UInt_t m_run; + } m_commonRunBranches; + + std::vector m_tables; + std::vector m_selbxs; + unsigned int m_nOrbits; + + std::vector> m_nanoMetadata; + + edm::EDGetTokenT> m_bxMaskToken; + std::vector allBXs_; +}; + +// +// constants, enums and typedefs +// + +// +// static data member definitions +// + +// +// constructors and destructor +// +OrbitNanoAODOutputModule::OrbitNanoAODOutputModule(edm::ParameterSet const& pset) + : edm::one::OutputModuleBase::OutputModuleBase(pset), + edm::one::OutputModule<>(pset), + m_fileName(pset.getUntrackedParameter("fileName")), + m_logicalFileName(pset.getUntrackedParameter("logicalFileName")), + m_compressionLevel(pset.getUntrackedParameter("compressionLevel")), + m_compressionAlgorithm(pset.getUntrackedParameter("compressionAlgorithm")), + m_skipEmptyBXs(pset.getParameter("skipEmptyBXs")), + m_writeProvenance(pset.getUntrackedParameter("saveProvenance", true)), + m_fakeName(pset.getUntrackedParameter("fakeNameForCrab", false)), + m_autoFlush(pset.getUntrackedParameter("autoFlush", -10000000)), + m_processHistoryRegistry(), + m_nOrbits(0) { + edm::InputTag bxMask = pset.getParameter("selectedBx"); + if (!bxMask.label().empty()) { + m_bxMaskToken = consumes>(bxMask); + } else { + allBXs_.resize(l1ScoutingRun3::OrbitFlatTable::NBX); + for (unsigned int i = 0; i < l1ScoutingRun3::OrbitFlatTable::NBX; ++i) { + allBXs_[i] = i + 1; + } + } +} + +OrbitNanoAODOutputModule::~OrbitNanoAODOutputModule() {} + +void OrbitNanoAODOutputModule::write(edm::EventForOutput const& iEvent) { + //Get data from 'e' and write it to the file + edm::Service jr; + jr->eventWrittenToFile(m_jrToken, iEvent.id().run(), iEvent.id().event()); + m_nOrbits++; + + if (m_autoFlush) { + int64_t events = m_tree->GetEntriesFast(); + if (events == m_firstFlush) { + m_tree->FlushBaskets(); + float maxMemory; + if (m_autoFlush > 0) { + // Estimate the memory we'll be using at the first full flush by + // linearly scaling the number of events. + float percentClusterDone = m_firstFlush / static_cast(m_autoFlush); + maxMemory = static_cast(m_tree->GetTotBytes()) / percentClusterDone; + } else if (m_tree->GetZipBytes() == 0) { + maxMemory = 100 * 1024 * 1024; // Degenerate case of no information in the tree; arbitrary value + } else { + // Estimate the memory we'll be using by scaling the current compression ratio. + float cxnRatio = m_tree->GetTotBytes() / static_cast(m_tree->GetZipBytes()); + maxMemory = -m_autoFlush * cxnRatio; + float percentBytesDone = -m_tree->GetZipBytes() / static_cast(m_autoFlush); + m_autoFlush = m_firstFlush / percentBytesDone; + } + //std::cout << "OptimizeBaskets: total bytes " << m_tree->GetTotBytes() << std::endl; + //std::cout << "OptimizeBaskets: zip bytes " << m_tree->GetZipBytes() << std::endl; + //std::cout << "OptimizeBaskets: autoFlush " << m_autoFlush << std::endl; + //std::cout << "OptimizeBaskets: maxMemory " << static_cast(maxMemory) << std::endl; + //m_tree->OptimizeBaskets(static_cast(maxMemory), 1, "d"); + m_tree->OptimizeBaskets(static_cast(maxMemory), 1, ""); + } + if (m_eventsSinceFlush == m_autoFlush) { + m_tree->FlushBaskets(); + m_eventsSinceFlush = 0; + } + m_eventsSinceFlush++; + } + + m_commonBranches.fill(iEvent.eventAuxiliary()); + // fill all tables, starting from main tables and then doing extension tables + for (unsigned int extensions = 0; extensions <= 1; ++extensions) { + for (auto& t : m_tables) { + t.beginFill(iEvent, *m_tree, extensions); + } + } + // get m_table, read parameters, book branches, etc. + for (auto& t : m_selbxs) { + t.beginFill(iEvent, *m_tree); + } + // get a lust of selected BXs to be filled + const std::vector* selbx = &allBXs_; + if (!m_bxMaskToken.isUninitialized()) { + edm::Handle> handle; + iEvent.getByToken(m_bxMaskToken, handle); + selbx = &*handle; + } + // convert from orbit as event to collision as event + tbb::this_task_arena::isolate([&] { + for (unsigned bx : *selbx) { + if (m_skipEmptyBXs) { + bool empty = true; + for (auto& t : m_tables) { + if (t.hasBx(bx)) { + empty = false; + break; + } + } + if (empty) { + continue; + } + } + + m_commonBranches.setBx(bx); + for (auto& t : m_tables) { + t.fillBx(bx); + } + for (auto& t : m_selbxs) { + t.fillBx(bx); + } + m_tree->Fill(); + } // bx loop + }); + + // set m_table to nullptr + for (auto& t : m_tables) { + t.endFill(); + } + for (auto& t : m_selbxs) { + t.endFill(); + } + m_processHistoryRegistry.registerProcessHistory(iEvent.processHistory()); +} + +void OrbitNanoAODOutputModule::writeLuminosityBlock(edm::LuminosityBlockForOutput const& iLumi) { + edm::Service jr; + jr->reportLumiSection(m_jrToken, iLumi.id().run(), iLumi.id().value()); + + m_commonLumiBranches.fill(iLumi.id(), m_nOrbits); + + tbb::this_task_arena::isolate([&] { m_lumiTree->Fill(); }); + + m_processHistoryRegistry.registerProcessHistory(iLumi.processHistory()); + + m_nOrbits = 0; +} + +void OrbitNanoAODOutputModule::writeRun(edm::RunForOutput const& iRun) { + edm::Service jr; + jr->reportRunNumber(m_jrToken, iRun.id().run()); + + m_commonRunBranches.fill(iRun.id()); + + tbb::this_task_arena::isolate([&] { m_runTree->Fill(); }); + + m_processHistoryRegistry.registerProcessHistory(iRun.processHistory()); +} + +bool OrbitNanoAODOutputModule::isFileOpen() const { return nullptr != m_file.get(); } + +void OrbitNanoAODOutputModule::openFile(edm::FileBlock const&) { + m_file = std::make_unique(m_fileName.c_str(), "RECREATE", "", m_compressionLevel); + edm::Service jr; + cms::Digest branchHash; + m_jrToken = jr->outputFileOpened(m_fileName, + m_logicalFileName, + std::string(), + m_fakeName ? "PoolOutputModule" : "OrbitNanoAODOutputModule", + description().moduleLabel(), + edm::createGlobalIdentifier(), + std::string(), + branchHash.digest().toString(), + std::vector()); + + if (m_compressionAlgorithm == std::string("ZLIB")) { + m_file->SetCompressionAlgorithm(ROOT::kZLIB); + } else if (m_compressionAlgorithm == std::string("LZMA")) { + m_file->SetCompressionAlgorithm(ROOT::kLZMA); + } else if (m_compressionAlgorithm == std::string("ZSTD")) { + m_file->SetCompressionAlgorithm(ROOT::kZSTD); + } else if (m_compressionAlgorithm == std::string("LZ4")) { + m_file->SetCompressionAlgorithm(ROOT::kLZ4); + } else { + throw cms::Exception("Configuration") + << "OrbitNanoAODOutputModule configured with unknown compression algorithm '" << m_compressionAlgorithm << "'\n" + << "Allowed compression algorithms are ZLIB, LZMA, ZSTD, and LZ4\n"; + } + /* Setup file structure here */ + m_tables.clear(); + const auto& keeps = keptProducts(); + for (const auto& keep : keeps[edm::InEvent]) { + if (keep.first->className() == "l1ScoutingRun3::OrbitFlatTable") + m_tables.emplace_back(keep.first, keep.second); + else if (keep.first->className() == "std::vector") + m_selbxs.emplace_back(keep.first, keep.second); + else + throw cms::Exception("Configuration", "OrbitNanoAODOutputModule cannot handle class " + keep.first->className()); + } + + // create the trees + m_tree = std::make_unique("Events", "Events"); + m_tree->SetAutoSave(0); + m_tree->SetAutoFlush(0); + m_commonBranches.branch(*m_tree); + + m_lumiTree = std::make_unique("LuminosityBlocks", "LuminosityBlocks"); + m_lumiTree->SetAutoSave(0); + m_commonLumiBranches.branch(*m_lumiTree); + + m_runTree = std::make_unique("Runs", "Runs"); + m_runTree->SetAutoSave(0); + m_commonRunBranches.branch(*m_runTree); + + if (m_writeProvenance) { + m_metaDataTree = std::make_unique(edm::poolNames::metaDataTreeName().c_str(), "Job metadata"); + m_metaDataTree->SetAutoSave(0); + m_parameterSetsTree = std::make_unique(edm::poolNames::parameterSetsTreeName().c_str(), "Parameter sets"); + m_parameterSetsTree->SetAutoSave(0); + } +} +void OrbitNanoAODOutputModule::reallyCloseFile() { + if (m_writeProvenance) { + int basketSize = 16384; // fixme configurable? + edm::fillParameterSetBranch(m_parameterSetsTree.get(), basketSize); + edm::fillProcessHistoryBranch(m_metaDataTree.get(), basketSize, m_processHistoryRegistry); + if (m_metaDataTree->GetNbranches() != 0) { + m_metaDataTree->SetEntries(-1); + } + if (m_parameterSetsTree->GetNbranches() != 0) { + m_parameterSetsTree->SetEntries(-1); + } + } + m_file->Write(); + m_file->Close(); + m_file.reset(); + m_tree.release(); // apparently root has ownership + m_lumiTree.release(); // + m_runTree.release(); // + m_metaDataTree.release(); // + m_parameterSetsTree.release(); // + edm::Service jr; + jr->outputFileClosed(m_jrToken); +} + +void OrbitNanoAODOutputModule::fillDescriptions(edm::ConfigurationDescriptions& descriptions) { + edm::ParameterSetDescription desc; + + desc.addUntracked("fileName"); + desc.addUntracked("logicalFileName", ""); + + desc.addUntracked("compressionLevel", 9)->setComment("ROOT compression level of output file."); + desc.addUntracked("compressionAlgorithm", "ZLIB") + ->setComment("Algorithm used to compress data in the ROOT output file, allowed values are ZLIB and LZMA"); + desc.add("skipEmptyBXs", false)->setComment("Skip BXs where all input collections are empty"); + desc.addUntracked("saveProvenance", true) + ->setComment("Save process provenance information, e.g. for edmProvDump"); + desc.addUntracked("fakeNameForCrab", false) + ->setComment( + "Change the OutputModule name in the fwk job report to fake PoolOutputModule. This is needed to run on " + "crab " + "(and publish) till crab is fixed"); + desc.addUntracked("autoFlush", -10000000)->setComment("Autoflush parameter for ROOT file"); + + //replace with whatever you want to get from the EDM by default + const std::vector keep = {"drop *", "keep l1ScoutingRun3OrbitFlatTable_*Table_*_*"}; + edm::one::OutputModule<>::fillDescription(desc, keep); + + //Used by Workflow management for their own meta data + edm::ParameterSetDescription dataSet; + dataSet.setAllowAnything(); + desc.addUntracked("dataset", dataSet) + ->setComment("PSet is only used by Data Operations and not by this module."); + + edm::ParameterSetDescription branchSet; + branchSet.setAllowAnything(); + desc.add("branches", branchSet); + + desc.add("selectedBx", edm::InputTag())->setComment("selected Bx (1-3564)"); + descriptions.addDefault(desc); +} + +DEFINE_FWK_MODULE(OrbitNanoAODOutputModule); diff --git a/L1TriggerScouting/Utilities/plugins/OrbitTableOutputBranches.cc b/L1TriggerScouting/Utilities/plugins/OrbitTableOutputBranches.cc new file mode 100644 index 0000000000000..304ecbc32af6e --- /dev/null +++ b/L1TriggerScouting/Utilities/plugins/OrbitTableOutputBranches.cc @@ -0,0 +1,127 @@ +#include "L1TriggerScouting/Utilities/plugins/OrbitTableOutputBranches.h" + +#include + +namespace { + std::string makeBranchName(const std::string &baseName, const std::string &leafName) { + return baseName.empty() ? leafName : (leafName.empty() ? baseName : baseName + "_" + leafName); + } +} // namespace + +void OrbitTableOutputBranches::defineBranchesFromFirstEvent(const l1ScoutingRun3::OrbitFlatTable &tab) { + m_baseName = tab.name(); + for (size_t i = 0; i < tab.nColumns(); i++) { + const std::string &var = tab.columnName(i); + // get columnIndex + int columnIndex = tab.columnIndex(var); + if (columnIndex == -1) + throw cms::Exception("LogicError", "Missing column in input for " + m_baseName + "_" + var); + + switch (tab.columnType(i)) { + case l1ScoutingRun3::OrbitFlatTable::ColumnType::UInt8: + m_uint8Branches.emplace_back(var, tab.columnDoc(i), "b", columnIndex); + break; + case l1ScoutingRun3::OrbitFlatTable::ColumnType::Int16: + m_int16Branches.emplace_back(var, tab.columnDoc(i), "S", columnIndex); + break; + case l1ScoutingRun3::OrbitFlatTable::ColumnType::UInt16: + m_uint16Branches.emplace_back(var, tab.columnDoc(i), "s", columnIndex); + break; + case l1ScoutingRun3::OrbitFlatTable::ColumnType::Int32: + m_int32Branches.emplace_back(var, tab.columnDoc(i), "I", columnIndex); + break; + case l1ScoutingRun3::OrbitFlatTable::ColumnType::UInt32: + m_uint32Branches.emplace_back(var, tab.columnDoc(i), "i", columnIndex); + break; + case l1ScoutingRun3::OrbitFlatTable::ColumnType::Bool: + m_uint8Branches.emplace_back(var, tab.columnDoc(i), "O", columnIndex); + break; + case l1ScoutingRun3::OrbitFlatTable::ColumnType::Float: + m_floatBranches.emplace_back(var, tab.columnDoc(i), "F", columnIndex); + break; + case l1ScoutingRun3::OrbitFlatTable::ColumnType::Double: + m_doubleBranches.emplace_back(var, tab.columnDoc(i), "D", columnIndex); + break; + default: + throw cms::Exception("LogicError", "Unsupported type"); + } + } +} + +void OrbitTableOutputBranches::branch(TTree &tree) { + if (!m_singleton) { + if (m_extension == IsExtension) { + m_counterBranch = tree.FindBranch(("n" + m_baseName).c_str()); + if (!m_counterBranch) { + throw cms::Exception("LogicError", + "Trying to save an extension table for " + m_baseName + + " before having saved the corresponding main table\n"); + } + } else { + if (tree.FindBranch(("n" + m_baseName).c_str()) != nullptr) { + throw cms::Exception("LogicError", "Trying to save multiple main tables for " + m_baseName + "\n"); + } + m_counterBranch = tree.Branch(("n" + m_baseName).c_str(), &m_counter, ("n" + m_baseName + "/I").c_str()); + m_counterBranch->SetTitle(m_doc.c_str()); + } + } + std::string varsize = m_singleton ? "" : "[n" + m_baseName + "]"; + for (std::vector *branches : {&m_uint8Branches, + &m_int16Branches, + &m_uint16Branches, + &m_int32Branches, + &m_uint32Branches, + &m_floatBranches, + &m_doubleBranches}) { + for (auto &pair : *branches) { + std::string branchName = makeBranchName(m_baseName, pair.name); + pair.branch = + tree.Branch(branchName.c_str(), (void *)nullptr, (branchName + varsize + "/" + pair.rootTypeCode).c_str()); + pair.branch->SetTitle(pair.title.c_str()); + } + } +} + +void OrbitTableOutputBranches::beginFill(const edm::OccurrenceForOutput &iWhatever, TTree &tree, bool extensions) { + if (m_extension != DontKnowYetIfMainOrExtension) { + if (extensions != m_extension) + return; // do nothing, wait to be called with the proper flag + } + + iWhatever.getByToken(m_token, m_handle); + m_table = m_handle.product(); + m_singleton = m_table->singleton(); + if (!m_branchesBooked) { + m_extension = m_table->extension() ? IsExtension : IsMain; + if (extensions != m_extension) + return; // do nothing, wait to be called with the proper flag + defineBranchesFromFirstEvent(*m_table); + m_doc = m_table->doc(); + m_branchesBooked = true; + branch(tree); + } +} + +bool OrbitTableOutputBranches::hasBx(uint32_t bx) { return (m_table->size(bx) != 0); } + +void OrbitTableOutputBranches::fillBx(uint32_t bx) { + m_counter = m_table->size(bx); + if (m_counter != 0) { + for (auto &pair : m_uint8Branches) + fillColumn(pair, bx); + for (auto &pair : m_int16Branches) + fillColumn(pair, bx); + for (auto &pair : m_uint16Branches) + fillColumn(pair, bx); + for (auto &pair : m_int32Branches) + fillColumn(pair, bx); + for (auto &pair : m_uint32Branches) + fillColumn(pair, bx); + for (auto &pair : m_floatBranches) + fillColumn(pair, bx); + for (auto &pair : m_doubleBranches) + fillColumn(pair, bx); + } +} + +void OrbitTableOutputBranches::endFill() { m_table = nullptr; } diff --git a/L1TriggerScouting/Utilities/plugins/OrbitTableOutputBranches.h b/L1TriggerScouting/Utilities/plugins/OrbitTableOutputBranches.h new file mode 100644 index 0000000000000..7ba52b60e3bd7 --- /dev/null +++ b/L1TriggerScouting/Utilities/plugins/OrbitTableOutputBranches.h @@ -0,0 +1,73 @@ +#ifndef L1TriggerScouting_Utilities_OrbitTableOutputBranches_h +#define L1TriggerScouting_Utilities_OrbitTableOutputBranches_h + +#include +#include +#include +#include "FWCore/Framework/interface/OccurrenceForOutput.h" +#include "DataFormats/NanoAOD/interface/OrbitFlatTable.h" +#include "DataFormats/Provenance/interface/BranchDescription.h" +#include "FWCore/Utilities/interface/EDGetToken.h" + +class OrbitTableOutputBranches { +public: + OrbitTableOutputBranches(const edm::BranchDescription *desc, const edm::EDGetToken &token) + : m_token(token), m_extension(DontKnowYetIfMainOrExtension), m_branchesBooked(false) { + if (desc->className() != "l1ScoutingRun3::OrbitFlatTable") + throw cms::Exception("Configuration", + "OrbitNanoAODOutputModule can only write out l1ScoutingRun3::OrbitFlatTable objects"); + } + + void defineBranchesFromFirstEvent(const l1ScoutingRun3::OrbitFlatTable &tab); + void branch(TTree &tree); + + /// Fill the current table, if extensions == table.extension(). + /// This parameter is used so that the fill is called first for non-extensions and then for extensions + void beginFill(const edm::OccurrenceForOutput &iWhatever, TTree &tree, bool extensions); + bool hasBx(uint32_t bx); + void fillBx(uint32_t bx); + void endFill(); + +private: + edm::EDGetToken m_token; + std::string m_baseName; + bool m_singleton = false; + enum { IsMain = 0, IsExtension = 1, DontKnowYetIfMainOrExtension = 2 } m_extension; + std::string m_doc; + typedef Int_t CounterType; + CounterType m_counter; + struct NamedBranchPtr { + std::string name, title, rootTypeCode; + int columnIndex; + TBranch *branch; + NamedBranchPtr(const std::string &aname, + const std::string &atitle, + const std::string &rootType, + int columnIndex, + TBranch *branchptr = nullptr) + : name(aname), title(atitle), rootTypeCode(rootType), columnIndex(columnIndex), branch(branchptr) {} + }; + TBranch *m_counterBranch = nullptr; + std::vector m_uint8Branches; + std::vector m_int16Branches; + std::vector m_uint16Branches; + std::vector m_int32Branches; + std::vector m_uint32Branches; + std::vector m_floatBranches; + std::vector m_doubleBranches; + bool m_branchesBooked; + + edm::Handle m_handle; + const l1ScoutingRun3::OrbitFlatTable *m_table; + + template + void fillColumn(NamedBranchPtr &pair, uint32_t bx) { + pair.branch->SetAddress( + m_counter == 0 + ? static_cast(nullptr) + : const_cast( + &m_table->columnData(pair.columnIndex, bx).front())); // SetAddress should take a const * ! + } +}; + +#endif diff --git a/L1TriggerScouting/Utilities/plugins/SelectedBxTableOutputBranches.cc b/L1TriggerScouting/Utilities/plugins/SelectedBxTableOutputBranches.cc new file mode 100644 index 0000000000000..98f0fd28c81fe --- /dev/null +++ b/L1TriggerScouting/Utilities/plugins/SelectedBxTableOutputBranches.cc @@ -0,0 +1,13 @@ +#include "L1TriggerScouting/Utilities/plugins/SelectedBxTableOutputBranches.h" + +void SelectedBxTableOutputBranches::beginFill(const edm::OccurrenceForOutput &iWhatever, TTree &tree) { + if (m_branch == nullptr) { + m_branch = tree.Branch(m_name.c_str(), &m_value, (m_name + "/O").c_str()); + m_branch->SetTitle("SelectionBx bit"); + } + iWhatever.getByToken(m_token, m_handle); + m_bitset.reset(); + for (unsigned bx : *m_handle) { + m_bitset[bx] = true; + } +} diff --git a/L1TriggerScouting/Utilities/plugins/SelectedBxTableOutputBranches.h b/L1TriggerScouting/Utilities/plugins/SelectedBxTableOutputBranches.h new file mode 100644 index 0000000000000..c150f62e089cc --- /dev/null +++ b/L1TriggerScouting/Utilities/plugins/SelectedBxTableOutputBranches.h @@ -0,0 +1,38 @@ +#ifndef L1TriggerScouting_Utilities_SelectedBxTableOutputBranches_h +#define L1TriggerScouting_Utilities_SelectedBxTableOutputBranches_h + +#include +#include +#include +#include +#include "FWCore/Framework/interface/OccurrenceForOutput.h" +#include "DataFormats/NanoAOD/interface/OrbitFlatTable.h" +#include "DataFormats/Provenance/interface/BranchDescription.h" +#include "FWCore/Utilities/interface/EDGetToken.h" + +class SelectedBxTableOutputBranches { +public: + SelectedBxTableOutputBranches(const edm::BranchDescription *desc, const edm::EDGetToken &token) + : m_token(token), m_name("SelBx_" + desc->moduleLabel()), m_branch(nullptr) { + if (desc->className() != "std::vector") + throw cms::Exception("Configuration", "SelectedBxTableOutputBranches can only write out vector"); + if (desc->productInstanceName() != "SelBx") { + m_name += "_" + desc->productInstanceName(); + } + } + + void beginFill(const edm::OccurrenceForOutput &iWhatever, TTree &tree); + void fillBx(uint32_t bx) { m_value = m_bitset[bx]; } + void endFill() {} + +private: + edm::EDGetToken m_token; + std::string m_name; + bool m_value; + std::bitset m_bitset; + TBranch *m_branch; + + edm::Handle> m_handle; +}; + +#endif diff --git a/L1TriggerScouting/Utilities/plugins/SimpleOrbitFlatTableProducer.cc b/L1TriggerScouting/Utilities/plugins/SimpleOrbitFlatTableProducer.cc new file mode 100644 index 0000000000000..2ef2dcf36cee2 --- /dev/null +++ b/L1TriggerScouting/Utilities/plugins/SimpleOrbitFlatTableProducer.cc @@ -0,0 +1,305 @@ +#include + +#include "FWCore/Framework/interface/Frameworkfwd.h" +#include "FWCore/Framework/interface/stream/EDProducer.h" +#include "FWCore/Framework/interface/ConsumesCollector.h" +#include "FWCore/ParameterSet/interface/ParameterSet.h" +#include "FWCore/ParameterSet/interface/ParameterSetDescription.h" +#include "FWCore/ParameterSet/interface/EmptyGroupDescription.h" +#include "FWCore/ParameterSet/interface/allowedValues.h" +#include "Utilities/General/interface/ClassName.h" + +#include "CommonTools/Utils/interface/StringCutObjectSelector.h" +#include "CommonTools/Utils/interface/StringObjectFunction.h" + +#include "DataFormats/Common/interface/ValueMap.h" +#include "DataFormats/NanoAOD/interface/FlatTable.h" +#include "PhysicsTools/NanoAOD/interface/SimpleFlatTableProducer.h" + +#include "DataFormats/L1Scouting/interface/OrbitCollection.h" +#include "DataFormats/NanoAOD/interface/OrbitFlatTable.h" + +template +class SimpleOrbitFlatTableProducer : public edm::stream::EDProducer<> { +public: + using TOrbitCollection = OrbitCollection; + + SimpleOrbitFlatTableProducer(edm::ParameterSet const ¶ms) + : name_(params.getParameter("name")), + doc_(params.getParameter("doc")), + singleton_(params.getParameter("singleton")), + extension_(params.getParameter("extension")), + skipNonExistingSrc_(params.getParameter("skipNonExistingSrc")), + cut_(!singleton_ ? params.getParameter("cut") : "", + !singleton_ && params.existsAs("lazyEval") ? params.getUntrackedParameter("lazyEval") : false), + maxLen_(params.existsAs("maxLen") ? params.getParameter("maxLen") + : std::numeric_limits::max()), + src_(consumes(params.getParameter("src"))) { + // variables + edm::ParameterSet const &varsPSet = params.getParameter("variables"); + for (const std::string &vname : varsPSet.getParameterNamesForType()) { + const auto &varPSet = varsPSet.getParameter(vname); + const std::string &type = varPSet.getParameter("type"); + if (type == "int") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "uint") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "int64") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "uint64") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "float") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "double") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "uint8") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "int16") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "uint16") + vars_.push_back(std::make_unique(vname, varPSet)); + else if (type == "bool") + vars_.push_back(std::make_unique(vname, varPSet)); + else + throw cms::Exception("Configuration", "unsupported type " + type + " for variable " + vname); + } + + // external variables + if (params.existsAs("externalVariables")) { + edm::ParameterSet const &extvarsPSet = params.getParameter("externalVariables"); + for (const std::string &vname : extvarsPSet.getParameterNamesForType()) { + const auto &varPSet = extvarsPSet.getParameter(vname); + const std::string &type = varPSet.getParameter("type"); + if (type == "int") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else if (type == "uint") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else if (type == "int64") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else if (type == "uint64") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else if (type == "float") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else if (type == "double") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else if (type == "uint8") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else if (type == "int16") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else if (type == "uint16") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else if (type == "bool") + extvars_.push_back( + std::make_unique(vname, varPSet, this->consumesCollector(), this->skipNonExistingSrc_)); + else + throw cms::Exception("Configuration", "unsupported type " + type + " for variable " + vname); + } + } + + produces(); + } + + ~SimpleOrbitFlatTableProducer() override {} + + static void fillDescriptions(edm::ConfigurationDescriptions &descriptions) { + edm::ParameterSetDescription desc; + std::string classname = ClassName::name(); + desc.add("name")->setComment("name of the branch in the flat table output for " + classname); + desc.add("doc", "")->setComment("few words of self documentation"); + desc.ifValue( + edm::ParameterDescription( + "singleton", false, true, edm::Comment("whether or not the input collection is single-element")), + false >> (edm::ParameterDescription( + "cut", "", true, edm::Comment("selection on the main input collection")) and + edm::ParameterDescription("lazyEval", + false, + false, + edm::Comment("if true, can use methods of inheriting classes. Can " + "cause problems when multi-threading."))) or + true >> edm::EmptyGroupDescription()); + + desc.addOptional("maxLen")->setComment( + "define the maximum length per bx of the input collection to put in the branch"); + desc.add("extension", false)->setComment("whether or not to extend an existing same table"); + desc.add("skipNonExistingSrc", false) + ->setComment("whether or not to skip producing the table on absent input product"); + desc.add("src")->setComment("input collection to fill the flat table"); + + edm::ParameterSetDescription variable; + variable.add("expr")->setComment("a function to define the content of the branch in the flat table"); + variable.add("doc")->setComment("few words description of the branch content"); + variable.addUntracked("lazyEval", false) + ->setComment("if true, can use methods of inheriting classes in `expr`. Can cause problems with threading."); + variable.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", "bool")); + variable.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 variables; + variables.setComment("a parameters set to define all variable to fill the flat table"); + variables.addNode( + edm::ParameterWildcard("*", edm::RequireZeroOrMore, true, variable)); + desc.add("variables", variables); + + // external variables + edm::ParameterSetDescription extvariable; + extvariable.add("src")->setComment("valuemap input collection to fill the flat table"); + extvariable.add("doc")->setComment("few words description of the branch content"); + extvariable.ifValue(edm::ParameterDescription( + "type", "int", true, edm::Comment("the c++ type of the branch in the flat table")), + edm::allowedValues( + "int", "uint", "int64", "uint64", "float", "double", "uint8", "int16", "uint16", "bool")); + extvariable.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, as a function of the object evaluated")), + false); + + edm::ParameterSetDescription extvariables; + extvariables.setComment("a parameters set to define all variable taken form valuemap to fill the flat table"); + extvariables.addOptionalNode( + edm::ParameterWildcard("*", edm::RequireZeroOrMore, true, extvariable), false); + desc.addOptional("externalVariables", extvariables); + + descriptions.addWithDefaultLabel(desc); + } + + void produce(edm::Event &iEvent, const edm::EventSetup &iSetup) override { + edm::Handle src; + iEvent.getByToken(src_, src); + + std::vector selobjs; + std::vector> selptrs; // for external variables + std::vector selbxOffsets; + + if (src.isValid() || !skipNonExistingSrc_) { + if (singleton_) { + // fill objects + for (int i = 0; i < src->size(); i++) { + selobjs.push_back(&(*src)[i]); + if (!extvars_.empty()) + selptrs.emplace_back(src, 0); + } + + // set bx offsets of selected objects + selbxOffsets = src->bxOffsets(); + + } else { // not singleton + // offsets before cut + std::vector bxOffsets = src->bxOffsets(); + + // number of objects per bx after cut + std::vector selbxSizes = std::vector(l1ScoutingRun3::OrbitFlatTable::NBX + 1, 0); + + for (const unsigned int &bx : src->getFilledBxs()) { + const auto &objs = src->bxIterator(bx); + for (unsigned int i = 0; i < objs.size(); i++) { + const auto &obj = objs[i]; + edm::Ptr objptr = edm::Ptr(src, bxOffsets[bx] + i); + if (cut_(obj)) { // apply cut + selobjs.push_back(&obj); + if (!extvars_.empty()) + selptrs.push_back(objptr); + selbxSizes[bx]++; + } + if (selbxSizes[bx] >= maxLen_) // skip to the next bx + break; + } + } + + selbxOffsets = sizes2offsets(selbxSizes); + } + } + + auto out = std::make_unique(selbxOffsets, name_, singleton_, extension_); + out->setDoc(doc_); + + for (const auto &var : this->vars_) + var->fill(selobjs, *out); + for (const auto &var : this->extvars_) + var->fill(iEvent, selptrs, *out); + + iEvent.put(std::move(out)); + } + +private: // private attributes + const std::string name_; + const std::string doc_; + const bool singleton_; + const bool extension_; + const bool skipNonExistingSrc_; + const StringCutObjectSelector cut_; + const unsigned int maxLen_; + const edm::EDGetTokenT src_; + + // variables + typedef FuncVariable, int32_t> IntVar; + typedef FuncVariable, uint32_t> UIntVar; + typedef FuncVariable, int64_t> Int64Var; + typedef FuncVariable, uint64_t> UInt64Var; + typedef FuncVariable, float> FloatVar; + typedef FuncVariable, double> DoubleVar; + typedef FuncVariable, uint8_t> UInt8Var; + typedef FuncVariable, int16_t> Int16Var; + typedef FuncVariable, uint16_t> UInt16Var; + typedef FuncVariable, bool> BoolVar; + std::vector>> vars_; + + // external variables + typedef ValueMapVariable IntExtVar; + typedef ValueMapVariable UIntExtVar; + typedef ValueMapVariable Int64ExtVar; + typedef ValueMapVariable UInt64ExtVar; + typedef ValueMapVariable FloatExtVar; + typedef ValueMapVariable DoubleExtVar; + typedef ValueMapVariable BoolExtVar; + typedef ValueMapVariable UInt8ExtVar; + typedef ValueMapVariable Int16ExtVar; + typedef ValueMapVariable UInt16ExtVar; + std::vector>> extvars_; + +private: // private methods + std::vector sizes2offsets(std::vector sizes) const { + std::vector offsets(sizes.size() + 1, 0); // add extra one for the last offset = total size + for (unsigned int i = 0; i < sizes.size(); i++) { + offsets[i + 1] = offsets[i] + sizes[i]; + } + return offsets; + } +}; + +#include "DataFormats/L1Scouting/interface/L1ScoutingMuon.h" +typedef SimpleOrbitFlatTableProducer SimpleL1ScoutingMuonOrbitFlatTableProducer; + +#include "DataFormats/L1Scouting/interface/L1ScoutingCalo.h" +typedef SimpleOrbitFlatTableProducer SimpleL1ScoutingEGammaOrbitFlatTableProducer; +typedef SimpleOrbitFlatTableProducer SimpleL1ScoutingTauOrbitFlatTableProducer; +typedef SimpleOrbitFlatTableProducer SimpleL1ScoutingJetOrbitFlatTableProducer; + +#include "DataFormats/L1Scouting/interface/L1ScoutingBMTFStub.h" +typedef SimpleOrbitFlatTableProducer SimpleL1ScoutingBMTFStubOrbitFlatTableProducer; + +#include "FWCore/Framework/interface/MakerMacros.h" +DEFINE_FWK_MODULE(SimpleL1ScoutingMuonOrbitFlatTableProducer); +DEFINE_FWK_MODULE(SimpleL1ScoutingEGammaOrbitFlatTableProducer); +DEFINE_FWK_MODULE(SimpleL1ScoutingTauOrbitFlatTableProducer); +DEFINE_FWK_MODULE(SimpleL1ScoutingJetOrbitFlatTableProducer); +DEFINE_FWK_MODULE(SimpleL1ScoutingBMTFStubOrbitFlatTableProducer); diff --git a/PhysicsTools/NanoAOD/python/autoNANO.py b/PhysicsTools/NanoAOD/python/autoNANO.py index e39bcb67d91b2..2eaed5cb274cb 100644 --- a/PhysicsTools/NanoAOD/python/autoNANO.py +++ b/PhysicsTools/NanoAOD/python/autoNANO.py @@ -38,6 +38,11 @@ def expandNanoMapping(seqList, mapping, key): 'customize': '@Scout+PhysicsTools/NanoAOD/custom_run3scouting_cff.customiseScoutingNanoForScoutingPFMonitor'}, 'ScoutFromMini' : {'sequence': '@Scout', 'customize': '@Scout+PhysicsTools/NanoAOD/custom_run3scouting_cff.customiseScoutingNanoFromMini'}, + # L1Scouting nano + 'L1Scout': {'sequence': 'PhysicsTools/NanoAOD/custom_l1scoutingrun3_cff', + 'customize': 'PhysicsTools/NanoAOD/custom_l1scoutingrun3_cff.customiseL1ScoutingNanoAOD'}, + 'L1ScoutSelect': {'sequence': '@L1Scout', + 'customize': '@L1Scout+PhysicsTools/NanoAOD/custom_l1scoutingrun3_cff.customiseL1ScoutingNanoAODSelection'}, # BPH nano 'BPH' : {'sequence': '@PHYS', 'customize': '@PHYS+PhysicsTools/NanoAOD/custom_bph_cff.nanoAOD_customizeBPH'}, diff --git a/PhysicsTools/NanoAOD/python/custom_l1scoutingrun3_cff.py b/PhysicsTools/NanoAOD/python/custom_l1scoutingrun3_cff.py new file mode 100644 index 0000000000000..3a2f938124b7c --- /dev/null +++ b/PhysicsTools/NanoAOD/python/custom_l1scoutingrun3_cff.py @@ -0,0 +1,137 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.l1scoutingrun3_cff import * + +######################### +# Default Configuration # +######################### + +# since L1ScoutingNano should be run standalone only, +# this replace task and sequences in standard NanoAOD +nanoTableTaskCommon = cms.Task( + l1scoutingMuonPhysicalValueMap, + l1scoutingEGammaPhysicalValueMap, + l1scoutingTauPhysicalValueMap, + l1scoutingJetPhysicalValueMap, + l1scoutingMuonTable, + l1scoutingEGammaTable, + l1scoutingTauTable, + l1scoutingJetTable, + l1scoutingEtSumTable, + l1scoutingBMTFStubTable, +) + +nanoSequenceCommon = cms.Sequence(l1scoutingJetPhysicalValueMap + cms.Sequence(nanoTableTaskCommon)) + +nanoSequence = cms.Sequence(nanoSequenceCommon) + +nanoSequenceMC = cms.Sequence(nanoSequenceCommon) + +def customiseL1ScoutingNanoAOD(process): + # change OutputModule to OrbitNanoAODOutputModule + if hasattr(process, "NANOAODoutput"): + print("custom_l1scoutingrun3_cff: Change NANOAODoutput to OrbitNanoAODOutputModule") + setattr(process, "NANOAODoutput", + cms.OutputModule("OrbitNanoAODOutputModule", + # copy from standard NanoAOD + compressionAlgorithm = process.NANOAODoutput.compressionAlgorithm, + compressionLevel = process.NANOAODoutput.compressionLevel, + dataset = process.NANOAODoutput.dataset, + fileName = process.NANOAODoutput.fileName, + # change eventcontent + outputCommands = cms.untracked.vstring( + "drop *", + "keep l1ScoutingRun3OrbitFlatTable_*_*_*"), + # additional parameters for l1scouting + SelectEvents = cms.untracked.PSet( + SelectEvents = cms.vstring('nanoAOD_step') # l1scouting runs standalone only + ), + skipEmptyBXs = cms.bool(True), # drop empty bxs + ) + ) + + return process + +################# +# Customisation # +################# +# these function are designed to be used with --customise flag in cmsDriver.py +# e.g. --customise PhysicsTools/NanoAOD/python/custom_l1scoutingrun3_cff.dropStub + +# configure to run with L1ScoutingSelection dataset +# should be used with default customiseL1ScoutingNanoAOD +def customiseL1ScoutingNanoAODSelection(process): + # change sources + process.l1scoutingMuonPhysicalValueMap.src = cms.InputTag("FinalBxSelectorMuon", "Muon") + process.l1scoutingEGammaPhysicalValueMap.src = cms.InputTag("FinalBxSelectorEGamma", "EGamma") + process.l1scoutingJetPhysicalValueMap.src = cms.InputTag("FinalBxSelectorJet", "Jet") + + process.l1scoutingMuonTable.src = cms.InputTag("FinalBxSelectorMuon", "Muon") + process.l1scoutingEGammaTable.src = cms.InputTag("FinalBxSelectorEGamma", "EGamma") + process.l1scoutingJetTable.src = cms.InputTag("FinalBxSelectorJet", "Jet") + process.l1scoutingEtSumTable.src = cms.InputTag("FinalBxSelectorBxSums", "EtSum") + process.l1scoutingBMTFStubTable.src = cms.InputTag("FinalBxSelectorBMTFStub", "BMTFStub") + + # drop L1Tau + process.nanoTableTaskCommon.remove(process.l1scoutingTauTable) + + # change parameters in OrbitNanoAODOutputModule + process.NANOAODoutput.outputCommands += ["keep uints_*_SelBx_*"] # keep SelBx + process.NANOAODoutput.selectedBx = cms.InputTag("FinalBxSelector", "SelBx") # use to select products + + return process + +def addHardwareValues(process): + # add hardware values to variables + process.l1scoutingMuonTable.variables = cms.PSet( + process.l1scoutingMuonTable.variables, + l1scoutingMuonUnconvertedVariables + ) + process.l1scoutingEGammaTable.variables = cms.PSet( + process.l1scoutingEGammaTable.variables, + l1scoutingCaloObjectUnconvertedVariables + ) + process.l1scoutingTauTable.variables = cms.PSet( + process.l1scoutingTauTable.variables, + l1scoutingCaloObjectUnconvertedVariables + ) + process.l1scoutingJetTable.variables = cms.PSet( + process.l1scoutingJetTable.variables, + l1scoutingCaloObjectUnconvertedVariables + ) + + # EtSum uses dedicated EDProducer and can add hardware values by setting a boolean + process.l1scoutingEtSumTable.writeHardwareValues = cms.bool(True) + + return process + +def keepHardwareValuesOnly(process): + # first, add hardware values + process = addHardwareValues(process) + + # remove physical values + # currently external values are all physical values, so we can simple remove them + process.l1scoutingMuonTable.externalVariables = cms.PSet() + process.l1scoutingEGammaTable.externalVariables = cms.PSet() + process.l1scoutingTauTable.externalVariables = cms.PSet() + process.l1scoutingJetTable.externalVariables = cms.PSet() + + # EtSum uses dedicated EDProducer and can remove physical values by setting a boolean + process.l1scoutingEtSumTable.writePhysicalValues = cms.bool(False) + + return process + +def outputMultipleEtSums(process): + process.l1scoutingEtSumTable.singleton = cms.bool(False) + return process + +def dropEmptyBXs(process): + process.NANOAODoutput.skipEmptyBXs = cms.bool(True) + return process + +def keepEmptyBXs(process): + process.NANOAODoutput.skipEmptyBXs = cms.bool(False) + return process + +def dropBMTFStub(process): + process.nanoTableTaskCommon.remove(process.l1scoutingBMTFStubTable) + return process diff --git a/PhysicsTools/NanoAOD/python/l1scoutingrun3_cff.py b/PhysicsTools/NanoAOD/python/l1scoutingrun3_cff.py new file mode 100644 index 0000000000000..22d87c6a6ad87 --- /dev/null +++ b/PhysicsTools/NanoAOD/python/l1scoutingrun3_cff.py @@ -0,0 +1,184 @@ +import FWCore.ParameterSet.Config as cms +from PhysicsTools.NanoAOD.common_cff import * + +############################## +# Unconverted Hardware Value # +############################## + +# subsets of hardware values which are converted to physical values +# by default, L1ScoutingNano will store physical values + +# Muon +l1scoutingMuonUnconvertedVariables = cms.PSet( + hwPt = Var("hwPt()", "int", doc="hardware pt"), + hwEta = Var("hwEta()", "int", doc="hardware eta"), + hwPhi = Var("hwPhi()", "int", doc="hardware phi"), + hwPtUnconstrained = Var("hwPtUnconstrained", "int", doc="harware unconstrained pt"), + hwEtaAtVtx = Var("hwEtaAtVtx()", "int", doc="hardware eta extrapolated at beam line"), + hwPhiAtVtx = Var("hwPhiAtVtx()", "int", doc="hardware phi extrapolated at beam line"), +) + +# Calo objects +l1scoutingCaloObjectUnconvertedVariables = cms.PSet( + hwEt = Var("hwEt()", "int", doc="hardware Et"), + hwEta = Var("hwEta()", "int", doc="hardware eta"), + hwPhi = Var("hwPhi()", "int", doc="hardware phi"), +) + +################################################# +# Physical Value Conversion from Hardware Value # +################################################# + +# Conversions for muon +l1scoutingMuonConversions = cms.PSet( + fPt = cms.PSet(func=cms.string("ugmt::fPt"), arg=cms.string("hwPt")), + fEta = cms.PSet(func=cms.string("ugmt::fEta"), arg=cms.string("hwEta")), + fPhi = cms.PSet(func=cms.string("ugmt::fPhi"), arg=cms.string("hwPhi")), + fPtUnconstrained = cms.PSet(func=cms.string("ugmt::fPtUnconstrained"), arg=cms.string("hwPtUnconstrained")), + fEtaAtVtx = cms.PSet(func=cms.string("ugmt::fEtaAtVtx"), arg=cms.string("hwEtaAtVtx")), + fPhiAtVtx = cms.PSet(func=cms.string("ugmt::fPhiAtVtx"), arg=cms.string("hwPhiAtVtx")) +) + +l1scoutingMuonPhysicalValueMap = cms.EDProducer("L1ScoutingMuonPhysicalValueMapProducer", + src = cms.InputTag("l1ScGmtUnpacker", "Muon"), + conversions = l1scoutingMuonConversions +) + +# Conversions for Calo objects (EGamma, Tau, Jet) +l1scoutingCaloObjectConversions = cms.PSet( + fEt = cms.PSet(func=cms.string("demux::fEt"), arg=cms.string("hwEt")), + fEta = cms.PSet(func=cms.string("demux::fEta"), arg=cms.string("hwEta")), + fPhi = cms.PSet(func=cms.string("demux::fPhi"), arg=cms.string("hwPhi")), +) + +l1scoutingEGammaPhysicalValueMap = cms.EDProducer("L1ScoutingEGammaPhysicalValueMapProducer", + src = cms.InputTag("l1ScCaloUnpacker", "EGamma"), + conversions = l1scoutingCaloObjectConversions +) + +l1scoutingTauPhysicalValueMap = cms.EDProducer("L1ScoutingTauPhysicalValueMapProducer", + src = cms.InputTag("l1ScCaloUnpacker", "Tau"), + conversions = l1scoutingCaloObjectConversions +) + +l1scoutingJetPhysicalValueMap = cms.EDProducer("L1ScoutingJetPhysicalValueMapProducer", + src = cms.InputTag("l1ScCaloUnpacker", "Jet"), + conversions = l1scoutingCaloObjectConversions +) + +#################### +# Table Definition # +#################### + +# default event content for L1ScoutingNano +# by default, L1ScoutingNano will store physical values + +# Muon +l1scoutingMuonTable = cms.EDProducer("SimpleL1ScoutingMuonOrbitFlatTableProducer", + src = cms.InputTag("l1ScGmtUnpacker", "Muon"), + name = cms.string("L1Muon"), + doc = cms.string("Muons from GMT"), + singleton = cms.bool(False), + extension = cms.bool(False), + variables = cms.PSet( + hwCharge = Var("hwCharge()", "int", doc="charge (0 = invalid)"), + hwQuality = Var("hwQual()", "int", doc="quality"), + tfMuonIndex = Var("tfMuonIndex()", "int", + doc="index of muon at the uGMT input. 3 indices per link/sector/wedge. EMTF+ are 0-17, OMTF+ are 18-35, BMTF are 36-71, OMTF- are 72-89, EMTF- are 90-107"), + ), + externalVariables = cms.PSet( + pt = ExtVar(cms.InputTag("l1scoutingMuonPhysicalValueMap", "fPt"), "float", doc="pt"), + eta = ExtVar(cms.InputTag("l1scoutingMuonPhysicalValueMap", "fEta"), "float", doc="eta"), + phi = ExtVar(cms.InputTag("l1scoutingMuonPhysicalValueMap", "fPhi"), "float", doc="phi"), + ptUnconstrained = ExtVar(cms.InputTag("l1scoutingMuonPhysicalValueMap", "fPtUnconstrained"), "float", doc="unconstrained pt"), + etaAtVtx = ExtVar(cms.InputTag("l1scoutingMuonPhysicalValueMap", "fEtaAtVtx"), "float", doc="eta extrapolated at beam line"), + phiAtVtx = ExtVar(cms.InputTag("l1scoutingMuonPhysicalValueMap", "fPhiAtVtx"), "float", doc="phi extrapolated at beam line"), + ), +) + +# EGamma +l1scoutingEGammaTable = cms.EDProducer("SimpleL1ScoutingEGammaOrbitFlatTableProducer", + src = cms.InputTag("l1ScCaloUnpacker", "EGamma"), + name = cms.string("L1EG"), + doc = cms.string("EGammas from Calo Demux"), + singleton = cms.bool(False), + extension = cms.bool(False), + variables = cms.PSet( + hwIso = Var("hwIso()", "int", doc="hardware isolation (trigger units)") + ), + externalVariables = cms.PSet( + pt = ExtVar(cms.InputTag("l1scoutingEGammaPhysicalValueMap", "fEt"), "float", doc="pt"), + eta = ExtVar(cms.InputTag("l1scoutingEGammaPhysicalValueMap", "fEta"), "float", doc="eta"), + phi = ExtVar(cms.InputTag("l1scoutingEGammaPhysicalValueMap", "fPhi"), "float", doc="phi"), + ), +) + +# Tau +l1scoutingTauTable = cms.EDProducer("SimpleL1ScoutingTauOrbitFlatTableProducer", + src = cms.InputTag("l1ScCaloUnpacker", "Tau"), + name = cms.string("L1Tau"), + doc = cms.string("Taus from Calo Demux"), + singleton = cms.bool(False), + extension = cms.bool(False), + variables = cms.PSet( + hwIso = Var("hwIso()", "int", doc="hardware isolation (trigger units)") + ), + externalVariables = cms.PSet( + pt = ExtVar(cms.InputTag("l1scoutingTauPhysicalValueMap", "fEt"), "float", doc="pt"), + eta = ExtVar(cms.InputTag("l1scoutingTauPhysicalValueMap", "fEta"), "float", doc="eta"), + phi = ExtVar(cms.InputTag("l1scoutingTauPhysicalValueMap", "fPhi"), "float", doc="phi"), + ), +) + +# Jet +l1scoutingJetTable = cms.EDProducer("SimpleL1ScoutingJetOrbitFlatTableProducer", + src = cms.InputTag("l1ScCaloUnpacker", "Jet"), + name = cms.string("L1Jet"), + doc = cms.string("Jets from Calo Demux"), + singleton = cms.bool(False), + extension = cms.bool(False), + skipNonExistingSrc = cms.bool(False), + variables = cms.PSet( + hwQual = Var("hwQual()", "int", doc="qualitiy"), + ), + externalVariables = cms.PSet( + pt = ExtVar(cms.InputTag("l1scoutingJetPhysicalValueMap", "fEt"), "float", doc="pt"), + eta = ExtVar(cms.InputTag("l1scoutingJetPhysicalValueMap", "fEta"), "float", doc="eta"), + phi = ExtVar(cms.InputTag("l1scoutingJetPhysicalValueMap", "fPhi"), "float", doc="phi"), + ), +) + +# EtSum +l1scoutingEtSumTable = cms.EDProducer("L1ScoutingEtSumOrbitFlatTableProducer", + src = cms.InputTag("l1ScCaloUnpacker", "EtSum"), + name = cms.string("L1EtSum"), + doc = cms.string("EtSums from Calo Demux"), + singleton = cms.bool(False), + writePhysicalValues = cms.bool(True), + writeHardwareValues = cms.bool(False), + writeHF = cms.bool(True), + writeAsym = cms.bool(False), + writeMinBias = cms.bool(False), + writeTowerCount = cms.bool(True), + writeCentrality = cms.bool(False), +) + +# BMTF Stub +l1scoutingBMTFStubTable = cms.EDProducer("SimpleL1ScoutingBMTFStubOrbitFlatTableProducer", + src = cms.InputTag("l1ScBMTFUnpacker", "BMTFStub"), + name = cms.string("L1BMTFStub"), + doc = cms.string("Stubs from BMTF"), + singleton = cms.bool(False), + extension = cms.bool(False), + variables = cms.PSet( + hwPhi = Var("hwPhi()", "int16", doc="hardware phi (raw L1T units)"), + hwPhiB = Var("hwPhiB()", "int16", doc="hardware phiB (raw L1T units)"), + hwQual = Var("hwQual()", "int16", doc="hardware quality (raw L1T units)"), + hwEta = Var("hwEta()", "int16", doc="hardware eta (raw L1T units)"), + hwQEta = Var("hwQEta()", "int16", doc="hardware Qeta (raw L1T units)"), + station = Var("station()", "int16", doc="station (raw L1T units)"), + wheel = Var("wheel()", "int16", doc="wheel (raw L1T units)"), + sector = Var("sector()", "int16", doc="sector (raw L1T units)"), + tag = Var("tag()", "int16", doc="tag (raw L1T units)"), + ), +)