Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-05-29 23:12:55

0001 /** \class L1TriggerJSONMonitoring
0002  *
0003  *  Description: This class outputs JSON files with TCDS and L1T monitoring information.
0004  *
0005  */
0006 
0007 #include <atomic>
0008 #include <fstream>
0009 
0010 #include <fmt/printf.h>
0011 
0012 #include "CondFormats/DataRecord/interface/L1TUtmTriggerMenuRcd.h"
0013 #include "CondFormats/L1TObjects/interface/L1TUtmAlgorithm.h"
0014 #include "CondFormats/L1TObjects/interface/L1TUtmTriggerMenu.h"
0015 #include "DataFormats/Common/interface/Handle.h"
0016 #include "DataFormats/L1TGlobal/interface/GlobalAlgBlk.h"
0017 #include "DataFormats/L1TGlobal/interface/GlobalExtBlk.h"
0018 #include "EventFilter/Utilities/interface/EvFDaqDirector.h"
0019 #include "EventFilter/Utilities/interface/FastMonitor.h"
0020 #include "EventFilter/Utilities/interface/FastMonitoringService.h"
0021 #include "EventFilter/Utilities/interface/JSONSerializer.h"
0022 #include "EventFilter/Utilities/interface/JsonMonitorable.h"
0023 #include "FWCore/Framework/interface/Event.h"
0024 #include "FWCore/Framework/interface/EventSetup.h"
0025 #include "FWCore/Framework/interface/LuminosityBlock.h"
0026 #include "FWCore/Framework/interface/Run.h"
0027 #include "FWCore/Framework/interface/global/EDAnalyzer.h"
0028 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0029 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0030 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0031 #include "FWCore/ServiceRegistry/interface/Service.h"
0032 #include "FWCore/Utilities/interface/Adler32Calculator.h"
0033 
0034 using namespace jsoncollector;
0035 
0036 struct L1TriggerJSONMonitoringData {
0037   // special values for prescale index checks
0038   static constexpr const int kPrescaleUndefined = -2;
0039   static constexpr const int kPrescaleConflict = -1;
0040   // variables accumulated event by event in each stream
0041   struct stream {
0042     unsigned int processed = 0;                      // number of events processed
0043     std::vector<unsigned int> l1tAccept;             // number of events accepted by each L1 trigger
0044     std::vector<unsigned int> l1tAcceptPhysics;      // number of "physics" events accepted by each L1 trigger
0045     std::vector<unsigned int> l1tAcceptCalibration;  // number of "calibration" events accepted by each L1 trigger
0046     std::vector<unsigned int> l1tAcceptRandom;       // number of "random" events accepted by each L1 trigger
0047     std::vector<unsigned int> tcdsAccept;    // number of "physics", "calibration", "random" and other event types
0048     int prescaleIndex = kPrescaleUndefined;  // prescale column index
0049   };
0050 
0051   // variables initialised for each run
0052   struct run {
0053     std::string streamDestination;
0054     std::string streamMergeType;
0055     std::string baseRunDir;   // base directory from EvFDaqDirector
0056     std::string jsdFileName;  // definition file name for JSON with rates
0057   };
0058 
0059   // variables accumulated over the whole lumisection
0060   struct lumisection {
0061     jsoncollector::HistoJ<unsigned int> processed;         // number of events processed
0062     jsoncollector::HistoJ<unsigned int> l1tAccept;         // number of events accepted by each L1 trigger
0063     jsoncollector::HistoJ<unsigned int> l1tAcceptPhysics;  // number of "physics" events accepted by each L1 trigger
0064     jsoncollector::HistoJ<unsigned int>
0065         l1tAcceptCalibration;                             // number of "calibration" events accepted by each L1 trigger
0066     jsoncollector::HistoJ<unsigned int> l1tAcceptRandom;  // number of "random" events accepted by each L1 trigger
0067     jsoncollector::HistoJ<unsigned int> tcdsAccept;  // number of "physics", "calibration", "random" and other event types
0068     int prescaleIndex = kPrescaleUndefined;          // prescale column index
0069   };
0070 };
0071 
0072 class L1TriggerJSONMonitoring : public edm::global::EDAnalyzer<
0073                                     // per-stream information
0074                                     edm::StreamCache<L1TriggerJSONMonitoringData::stream>,
0075                                     // per-run accounting
0076                                     edm::RunCache<L1TriggerJSONMonitoringData::run>,
0077                                     // accumulate per-lumisection statistics
0078                                     edm::LuminosityBlockSummaryCache<L1TriggerJSONMonitoringData::lumisection> > {
0079 public:
0080   // constructor
0081   explicit L1TriggerJSONMonitoring(const edm::ParameterSet&);
0082 
0083   // destructor
0084   ~L1TriggerJSONMonitoring() override = default;
0085 
0086   // validate the configuration and optionally fill the default values
0087   static void fillDescriptions(edm::ConfigurationDescriptions& descriptions);
0088 
0089   // called for each Event
0090   void analyze(edm::StreamID, edm::Event const&, edm::EventSetup const&) const override;
0091 
0092   // -- inherited from edm::StreamCache<L1TriggerJSONMonitoringData::stream>
0093 
0094   // called once for each Stream being used in the job to create the cache object that will be used for that particular Stream
0095   std::unique_ptr<L1TriggerJSONMonitoringData::stream> beginStream(edm::StreamID) const override;
0096 
0097   // called when the Stream is switching from one LuminosityBlock to a new LuminosityBlock.
0098   void streamBeginLuminosityBlock(edm::StreamID, edm::LuminosityBlock const&, edm::EventSetup const&) const override;
0099 
0100   // -- inherited from edm::RunCache<L1TriggerJSONMonitoringData::run>
0101 
0102   // called each time the Source sees a new Run, and guaranteed to finish before any Stream calls streamBeginRun for that same Run
0103   std::shared_ptr<L1TriggerJSONMonitoringData::run> globalBeginRun(edm::Run const&,
0104                                                                    edm::EventSetup const&) const override;
0105 
0106   // called after all Streams have finished processing a given Run (i.e. streamEndRun for all Streams have completed)
0107   void globalEndRun(edm::Run const&, edm::EventSetup const&) const override;
0108 
0109   // -- inherited from edm::LuminosityBlockSummaryCache<L1TriggerJSONMonitoringData::lumisection>
0110 
0111   // called each time the Source sees a new LuminosityBlock
0112   std::shared_ptr<L1TriggerJSONMonitoringData::lumisection> globalBeginLuminosityBlockSummary(
0113       edm::LuminosityBlock const&, edm::EventSetup const&) const override;
0114 
0115   // called when a Stream has finished processing a LuminosityBlock, after streamEndLuminosityBlock
0116   void streamEndLuminosityBlockSummary(edm::StreamID,
0117                                        edm::LuminosityBlock const&,
0118                                        edm::EventSetup const&,
0119                                        L1TriggerJSONMonitoringData::lumisection*) const override;
0120 
0121   // called after the streamEndLuminosityBlockSummary method for all Streams have finished processing a given LuminosityBlock
0122   void globalEndLuminosityBlockSummary(edm::LuminosityBlock const&,
0123                                        edm::EventSetup const&,
0124                                        L1TriggerJSONMonitoringData::lumisection*) const override;
0125 
0126 private:
0127   // TCDS trigger types
0128   // see https://twiki.cern.ch/twiki/bin/viewauth/CMS/TcdsEventRecord
0129   static constexpr const std::array<const char*, 16> tcdsTriggerTypes_ = {{
0130       "Error",          //  0 - No trigger (DAQ error stream events may have this value)
0131       "Physics",        //  1 - GT trigger
0132       "Calibration",    //  2 - Sequence trigger (calibration)
0133       "Random",         //  3 - Random trigger
0134       "Auxiliary",      //  4 - Auxiliary (CPM front panel NIM input) trigger
0135       "",               //  5 - reserved
0136       "",               //  6 - reserved
0137       "",               //  7 - reserved
0138       "Cyclic",         //  8 - Cyclic trigger
0139       "Bunch-pattern",  //  9 - Bunch-pattern trigger
0140       "Software",       // 10 - Software trigger
0141       "TTS",            // 11 - TTS-sourced trigger
0142       "",               // 12 - reserved
0143       "",               // 13 - reserved
0144       "",               // 14 - reserved
0145       ""                // 15 - reserved
0146   }};
0147 
0148   static constexpr const char* streamName_ = "streamL1Rates";
0149 
0150   static void writeJsdFile(L1TriggerJSONMonitoringData::run const&);
0151   static void writeIniFile(L1TriggerJSONMonitoringData::run const&, unsigned int, std::vector<std::string> const&);
0152 
0153   // configuration
0154   const edm::InputTag level1Results_;                                    // InputTag for L1 trigger results
0155   const edm::EDGetTokenT<GlobalAlgBlkBxCollection> level1ResultsToken_;  // Token for L1 trigger results
0156   const edm::ESGetToken<L1TUtmTriggerMenu, L1TUtmTriggerMenuRcd> l1tUtmTriggerMenuRcdToken_;
0157 };
0158 
0159 // instantiate static data members
0160 constexpr const std::array<const char*, 16> L1TriggerJSONMonitoring::tcdsTriggerTypes_;
0161 
0162 // constructor
0163 L1TriggerJSONMonitoring::L1TriggerJSONMonitoring(edm::ParameterSet const& config)
0164     : level1Results_(config.getParameter<edm::InputTag>("L1Results")),
0165       level1ResultsToken_(consumes<GlobalAlgBlkBxCollection>(level1Results_)),
0166       l1tUtmTriggerMenuRcdToken_(esConsumes<edm::Transition::BeginRun>()) {
0167   if (edm::Service<evf::EvFDaqDirector>().isAvailable()) {
0168     //output initemp file. This lets hltd know number of streams early
0169     std::string initFileName = edm::Service<evf::EvFDaqDirector>()->getInitTempFilePath("streamL1Rates");
0170     std::ofstream file(initFileName);
0171     if (!file)
0172       throw cms::Exception("L1TriggerJsonMonitoring")
0173           << "Cannot create INITEMP file: " << initFileName << " error: " << strerror(errno);
0174     file.close();
0175   }
0176 }
0177 
0178 // validate the configuration and optionally fill the default values
0179 void L1TriggerJSONMonitoring::fillDescriptions(edm::ConfigurationDescriptions& descriptions) {
0180   edm::ParameterSetDescription desc;
0181   desc.add<edm::InputTag>("L1Results", edm::InputTag("hltGtStage2Digis"));
0182   descriptions.add("L1TriggerJSONMonitoring", desc);
0183 }
0184 
0185 // called once for each Stream being used in the job to create the cache object that will be used for that particular Stream
0186 std::unique_ptr<L1TriggerJSONMonitoringData::stream> L1TriggerJSONMonitoring::beginStream(edm::StreamID) const {
0187   return std::make_unique<L1TriggerJSONMonitoringData::stream>();
0188 }
0189 
0190 // called each time the Source sees a new Run, and guaranteed to finish before any Stream calls streamBeginRun for that same Run
0191 std::shared_ptr<L1TriggerJSONMonitoringData::run> L1TriggerJSONMonitoring::globalBeginRun(
0192     edm::Run const& run, edm::EventSetup const& setup) const {
0193   auto rundata = std::make_shared<L1TriggerJSONMonitoringData::run>();
0194 
0195   // set the DAQ parameters
0196   if (edm::Service<evf::EvFDaqDirector>().isAvailable()) {
0197     rundata->streamDestination = edm::Service<evf::EvFDaqDirector>()->getStreamDestinations(streamName_);
0198     rundata->streamMergeType =
0199         edm::Service<evf::EvFDaqDirector>()->getStreamMergeType(streamName_, evf::MergeTypeJSNDATA);
0200     rundata->baseRunDir = edm::Service<evf::EvFDaqDirector>()->baseRunDir();
0201   } else {
0202     rundata->streamDestination = "";
0203     rundata->streamMergeType = "";
0204     rundata->baseRunDir = ".";
0205   }
0206 
0207   // read the L1 trigger names from the EventSetup
0208   std::vector<std::string> triggerNames(GlobalAlgBlk::maxPhysicsTriggers, ""s);
0209   auto const& menuHandle = setup.getHandle(l1tUtmTriggerMenuRcdToken_);
0210   if (menuHandle.isValid()) {
0211     for (auto const& algo : menuHandle->getAlgorithmMap())
0212       triggerNames[algo.second.getIndex()] = algo.first;
0213   } else {
0214     edm::LogWarning("L1TriggerJSONMonitoring") << "L1TUtmTriggerMenu not found in the EventSetup.\nThe Level 1 Trigger "
0215                                                   "rate monitoring will not include the trigger names.";
0216   }
0217 
0218   // write the per-run .jsd file
0219   rundata->jsdFileName = fmt::sprintf("run%06d_ls0000_streamL1Rates_pid%05d.jsd", run.run(), getpid());
0220   writeJsdFile(*rundata);
0221 
0222   // write the per-run .ini file
0223   //iniFileName = fmt::sprintf("run%06d_ls0000_streamL1Rates_pid%05d.ini", run.run(), getpid());
0224   writeIniFile(*rundata, run.run(), triggerNames);
0225 
0226   return rundata;
0227 }
0228 
0229 // called after all Streams have finished processing a given Run (i.e. streamEndRun for all Streams have completed)
0230 void L1TriggerJSONMonitoring::globalEndRun(edm::Run const&, edm::EventSetup const&) const {}
0231 
0232 // called for each Event
0233 void L1TriggerJSONMonitoring::analyze(edm::StreamID sid, edm::Event const& event, edm::EventSetup const&) const {
0234   auto& stream = *streamCache(sid);
0235 
0236   ++stream.processed;
0237   unsigned int eventType = event.experimentType();
0238   if (eventType < tcdsTriggerTypes_.size())
0239     ++stream.tcdsAccept[eventType];
0240   else
0241     edm::LogWarning("L1TriggerJSONMonitoring") << "Unexpected event type " << eventType;
0242 
0243   // get hold of TriggerResults
0244   edm::Handle<GlobalAlgBlkBxCollection> handle;
0245   if (not event.getByToken(level1ResultsToken_, handle) or not handle.isValid() or handle->isEmpty(0)) {
0246     edm::LogError("L1TriggerJSONMonitoring")
0247         << "L1 trigger results with label [" + level1Results_.encode() + "] not present or invalid";
0248     return;
0249   }
0250 
0251   // The GlobalAlgBlkBxCollection is a vector of vectors, but the second layer can only ever
0252   // have one entry since there can't be more than one collection per bunch crossing.
0253   // The first "0" here means BX = 0, while the second "0" is used to access the first and only element.
0254   auto const& results = handle->at(0, 0);
0255   auto const& decision = results.getAlgoDecisionFinal();
0256   assert(decision.size() == GlobalAlgBlk::maxPhysicsTriggers);
0257 
0258   // check the results for each HLT path
0259   for (unsigned int i = 0; i < decision.size(); ++i) {
0260     if (decision[i]) {
0261       ++stream.l1tAccept[i];
0262       switch (eventType) {
0263         case edm::EventAuxiliary::PhysicsTrigger:
0264           ++stream.l1tAcceptPhysics[i];
0265           break;
0266         case edm::EventAuxiliary::CalibrationTrigger:
0267           ++stream.l1tAcceptCalibration[i];
0268           break;
0269         case edm::EventAuxiliary::RandomTrigger:
0270           ++stream.l1tAcceptRandom[i];
0271           break;
0272         default:
0273           break;
0274       }
0275     }
0276   }
0277 
0278   // check for conflicting values in the prescale column index, and store it
0279   int prescaleIndex = results.getPreScColumn();
0280   if (stream.prescaleIndex == L1TriggerJSONMonitoringData::kPrescaleUndefined) {
0281     stream.prescaleIndex = prescaleIndex;
0282   } else if (stream.prescaleIndex == L1TriggerJSONMonitoringData::kPrescaleConflict) {
0283     // do nothing
0284   } else if (stream.prescaleIndex != prescaleIndex) {
0285     edm::LogWarning("L1TriggerJSONMonitoring") << "Prescale index changed from " << stream.prescaleIndex << " to "
0286                                                << prescaleIndex << " inside lumisection " << event.luminosityBlock();
0287     stream.prescaleIndex = L1TriggerJSONMonitoringData::kPrescaleConflict;
0288   }
0289 }
0290 
0291 // called each time the Source sees a new LuminosityBlock
0292 std::shared_ptr<L1TriggerJSONMonitoringData::lumisection> L1TriggerJSONMonitoring::globalBeginLuminosityBlockSummary(
0293     edm::LuminosityBlock const& lumi, edm::EventSetup const&) const {
0294   // the API of jsoncollector::HistoJ does not really match our use case,
0295   // but it is the only vector-like object available in JsonMonitorable.h
0296   auto lumidata = std::make_shared<L1TriggerJSONMonitoringData::lumisection>(L1TriggerJSONMonitoringData::lumisection{
0297       jsoncollector::HistoJ<unsigned int>(1),                                 // processed
0298       jsoncollector::HistoJ<unsigned int>(GlobalAlgBlk::maxPhysicsTriggers),  // l1tAccept
0299       jsoncollector::HistoJ<unsigned int>(GlobalAlgBlk::maxPhysicsTriggers),  // l1tAcceptPhysics
0300       jsoncollector::HistoJ<unsigned int>(GlobalAlgBlk::maxPhysicsTriggers),  // l1tAcceptCalibration
0301       jsoncollector::HistoJ<unsigned int>(GlobalAlgBlk::maxPhysicsTriggers),  // l1tAcceptRandom
0302       jsoncollector::HistoJ<unsigned int>(tcdsTriggerTypes_.size())           // tcdsAccept
0303   });
0304   // repeated calls to `update` necessary to set the internal element counter
0305   lumidata->processed.update(0);
0306   for (unsigned int i = 0; i < GlobalAlgBlk::maxPhysicsTriggers; ++i)
0307     lumidata->l1tAccept.update(0);
0308   for (unsigned int i = 0; i < GlobalAlgBlk::maxPhysicsTriggers; ++i)
0309     lumidata->l1tAcceptPhysics.update(0);
0310   for (unsigned int i = 0; i < GlobalAlgBlk::maxPhysicsTriggers; ++i)
0311     lumidata->l1tAcceptCalibration.update(0);
0312   for (unsigned int i = 0; i < GlobalAlgBlk::maxPhysicsTriggers; ++i)
0313     lumidata->l1tAcceptRandom.update(0);
0314   for (unsigned int i = 0; i < tcdsTriggerTypes_.size(); ++i)
0315     lumidata->tcdsAccept.update(0);
0316   lumidata->prescaleIndex = L1TriggerJSONMonitoringData::kPrescaleUndefined;
0317 
0318   return lumidata;
0319 }
0320 
0321 // called when the Stream is switching from one LuminosityBlock to a new LuminosityBlock.
0322 void L1TriggerJSONMonitoring::streamBeginLuminosityBlock(edm::StreamID sid,
0323                                                          edm::LuminosityBlock const& lumi,
0324                                                          edm::EventSetup const&) const {
0325   auto& stream = *streamCache(sid);
0326 
0327   // reset the stream counters
0328   stream.processed = 0;
0329   stream.l1tAccept.assign(GlobalAlgBlk::maxPhysicsTriggers, 0);
0330   stream.l1tAcceptPhysics.assign(GlobalAlgBlk::maxPhysicsTriggers, 0);
0331   stream.l1tAcceptCalibration.assign(GlobalAlgBlk::maxPhysicsTriggers, 0);
0332   stream.l1tAcceptRandom.assign(GlobalAlgBlk::maxPhysicsTriggers, 0);
0333   stream.tcdsAccept.assign(tcdsTriggerTypes_.size(), 0);
0334   stream.prescaleIndex = L1TriggerJSONMonitoringData::kPrescaleUndefined;
0335 }
0336 
0337 // called when a Stream has finished processing a LuminosityBlock, after streamEndLuminosityBlock
0338 void L1TriggerJSONMonitoring::streamEndLuminosityBlockSummary(edm::StreamID sid,
0339                                                               edm::LuminosityBlock const& lumi,
0340                                                               edm::EventSetup const&,
0341                                                               L1TriggerJSONMonitoringData::lumisection* lumidata) const {
0342   auto const& stream = *streamCache(sid);
0343   lumidata->processed.value()[0] += stream.processed;
0344 
0345   for (unsigned int i = 0; i < GlobalAlgBlk::maxPhysicsTriggers; ++i) {
0346     lumidata->l1tAccept.value()[i] += stream.l1tAccept[i];
0347     lumidata->l1tAcceptPhysics.value()[i] += stream.l1tAcceptPhysics[i];
0348     lumidata->l1tAcceptCalibration.value()[i] += stream.l1tAcceptCalibration[i];
0349     lumidata->l1tAcceptRandom.value()[i] += stream.l1tAcceptRandom[i];
0350   }
0351   for (unsigned int i = 0; i < tcdsTriggerTypes_.size(); ++i)
0352     lumidata->tcdsAccept.value()[i] += stream.tcdsAccept[i];
0353 
0354   // check for conflicting values in the prescale column index
0355   if (lumidata->prescaleIndex == L1TriggerJSONMonitoringData::kPrescaleUndefined)
0356     lumidata->prescaleIndex = stream.prescaleIndex;
0357   else if (lumidata->prescaleIndex != stream.prescaleIndex)
0358     lumidata->prescaleIndex = L1TriggerJSONMonitoringData::kPrescaleConflict;
0359 }
0360 
0361 // called after the streamEndLuminosityBlockSummary method for all Streams have finished processing a given LuminosityBlock
0362 void L1TriggerJSONMonitoring::globalEndLuminosityBlockSummary(edm::LuminosityBlock const& lumi,
0363                                                               edm::EventSetup const&,
0364                                                               L1TriggerJSONMonitoringData::lumisection* lumidata) const {
0365   unsigned int ls = lumi.luminosityBlock();
0366   unsigned int run = lumi.run();
0367 
0368   bool writeFiles = true;
0369   if (edm::Service<evf::FastMonitoringService>().isAvailable()) {
0370     evf::FastMonitoringService* fms =
0371         (evf::FastMonitoringService*)(edm::Service<evf::FastMonitoringService>().operator->());
0372     if (fms)
0373       writeFiles = fms->shouldWriteFiles(ls);
0374   }
0375   if (not writeFiles)
0376     return;
0377 
0378   unsigned int processed = lumidata->processed.value().at(0);
0379   auto const& rundata = *runCache(lumi.getRun().index());
0380   Json::StyledWriter writer;
0381 
0382   // [SIC]
0383   char hostname[33];
0384   gethostname(hostname, 32);
0385   std::string sourceHost(hostname);
0386 
0387   // [SIC]
0388   std::stringstream sOutDef;
0389   sOutDef << rundata.baseRunDir << "/"
0390           << "output_" << getpid() << ".jsd";
0391 
0392   std::string jsndataFileList = "";
0393   unsigned int jsndataSize = 0;
0394   unsigned int jsndataAdler32 = 1;  // adler32 checksum for an empty file
0395 
0396   if (processed) {
0397     // write the .jsndata files which contain the actual rates
0398     Json::Value jsndata;
0399     jsndata[jsoncollector::DataPoint::SOURCE] = sourceHost;
0400     jsndata[jsoncollector::DataPoint::DEFINITION] = rundata.jsdFileName;
0401     jsndata[jsoncollector::DataPoint::DATA].append(lumidata->processed.toJsonValue());
0402     jsndata[jsoncollector::DataPoint::DATA].append(lumidata->l1tAccept.toJsonValue());
0403     jsndata[jsoncollector::DataPoint::DATA].append(lumidata->l1tAcceptPhysics.toJsonValue());
0404     jsndata[jsoncollector::DataPoint::DATA].append(lumidata->l1tAcceptCalibration.toJsonValue());
0405     jsndata[jsoncollector::DataPoint::DATA].append(lumidata->l1tAcceptRandom.toJsonValue());
0406 
0407     // write only the number of "physics", "calibration" and "random" events
0408     jsoncollector::HistoJ<unsigned int> tcdsAccept;
0409     tcdsAccept.update(lumidata->tcdsAccept.value()[edm::EventAuxiliary::PhysicsTrigger]);
0410     tcdsAccept.update(lumidata->tcdsAccept.value()[edm::EventAuxiliary::CalibrationTrigger]);
0411     tcdsAccept.update(lumidata->tcdsAccept.value()[edm::EventAuxiliary::RandomTrigger]);
0412     jsndata[jsoncollector::DataPoint::DATA].append(tcdsAccept.toJsonValue());
0413     /* FIXME send information for all event types instead of only these three
0414     jsndata[jsoncollector::DataPoint::DATA].append(lumidata->tcdsAccept.toJsonValue());
0415     */
0416     jsndata[jsoncollector::DataPoint::DATA].append(lumidata->prescaleIndex);
0417 
0418     auto jsndataFileName = fmt::sprintf("run%06d_ls%04d_streamL1Rates_pid%05d.jsndata", run, ls, getpid());
0419 
0420     std::string result = writer.write(jsndata);
0421     std::ofstream jsndataFile(rundata.baseRunDir + "/" + jsndataFileName);
0422     jsndataFile << result;
0423     jsndataFile.close();
0424 
0425     jsndataFileList = jsndataFileName;
0426     jsndataSize = result.size();
0427     jsndataAdler32 = cms::Adler32(result.c_str(), result.size());
0428   }
0429 
0430   // create a metadata json file for the "HLT rates" pseudo-stream
0431   unsigned int jsnProcessed = processed;
0432   unsigned int jsnAccepted = processed;
0433   unsigned int jsnErrorEvents = 0;
0434   unsigned int jsnRetCodeMask = 0;
0435   std::string jsnInputFiles = "";
0436   unsigned int jsnHLTErrorEvents = 0;
0437 
0438   Json::Value jsn;
0439   jsn[jsoncollector::DataPoint::SOURCE] = sourceHost;
0440   jsn[jsoncollector::DataPoint::DEFINITION] = sOutDef.str();
0441   jsn[jsoncollector::DataPoint::DATA].append(jsnProcessed);
0442   jsn[jsoncollector::DataPoint::DATA].append(jsnAccepted);
0443   jsn[jsoncollector::DataPoint::DATA].append(jsnErrorEvents);
0444   jsn[jsoncollector::DataPoint::DATA].append(jsnRetCodeMask);
0445   jsn[jsoncollector::DataPoint::DATA].append(jsndataFileList);
0446   jsn[jsoncollector::DataPoint::DATA].append(jsndataSize);
0447   jsn[jsoncollector::DataPoint::DATA].append(jsnInputFiles);
0448   jsn[jsoncollector::DataPoint::DATA].append(jsndataAdler32);
0449   jsn[jsoncollector::DataPoint::DATA].append(rundata.streamDestination);
0450   jsn[jsoncollector::DataPoint::DATA].append(rundata.streamMergeType);
0451   jsn[jsoncollector::DataPoint::DATA].append(jsnHLTErrorEvents);
0452 
0453   auto jsnFileName = fmt::sprintf("run%06d_ls%04d_streamL1Rates_pid%05d.jsn", run, ls, getpid());
0454   std::ofstream jsnFile(rundata.baseRunDir + "/" + jsnFileName);
0455   jsnFile << writer.write(jsn);
0456   jsnFile.close();
0457 }
0458 
0459 void L1TriggerJSONMonitoring::writeJsdFile(L1TriggerJSONMonitoringData::run const& rundata) {
0460   std::ofstream file(rundata.baseRunDir + "/" + rundata.jsdFileName);
0461   file << R"""({
0462    "data" : [
0463       { "name" : "Processed", "type" : "integer", "operation" : "histo"},
0464       { "name" : "L1-AlgoAccepted", "type" : "integer", "operation" : "histo"},
0465       { "name" : "L1-AlgoAccepted-Physics", "type" : "integer", "operation" : "histo"},
0466       { "name" : "L1-AlgoAccepted-Calibration", "type" : "integer", "operation" : "histo"},
0467       { "name" : "L1-AlgoAccepted-Random", "type" : "integer", "operation" : "histo"},
0468       { "name" : "L1-Global", "type" : "integer", "operation" : "histo"},
0469       { "name" : "Prescale-Index", "type" : "integer", "operation" : "sample"}
0470    ]
0471 })""";
0472   file.close();
0473 }
0474 
0475 void L1TriggerJSONMonitoring::writeIniFile(L1TriggerJSONMonitoringData::run const& rundata,
0476                                            unsigned int run,
0477                                            std::vector<std::string> const& l1TriggerNames) {
0478   Json::Value content;
0479 
0480   Json::Value triggerNames(Json::arrayValue);
0481   for (auto const& name : l1TriggerNames)
0482     triggerNames.append(name);
0483   content["L1-Algo-Names"] = triggerNames;
0484 
0485   Json::Value eventTypes(Json::arrayValue);
0486   eventTypes.append(tcdsTriggerTypes_[edm::EventAuxiliary::PhysicsTrigger]);
0487   eventTypes.append(tcdsTriggerTypes_[edm::EventAuxiliary::CalibrationTrigger]);
0488   eventTypes.append(tcdsTriggerTypes_[edm::EventAuxiliary::RandomTrigger]);
0489   /* FIXME send information for all event types instead of only these three
0490   for (auto const& name : tcdsTriggerTypes_)
0491     eventTypes.append(name);
0492   */
0493   content["Event-Type"] = eventTypes;
0494 
0495   std::string iniFileName = fmt::sprintf("run%06d_ls0000_streamL1Rates_pid%05d.ini", run, getpid());
0496   std::ofstream file(rundata.baseRunDir + "/" + iniFileName);
0497   Json::StyledWriter writer;
0498   file << writer.write(content);
0499   file.close();
0500 }
0501 
0502 // declare as a framework plugin
0503 #include "FWCore/ServiceRegistry/interface/ServiceMaker.h"
0504 #include "FWCore/Framework/interface/MakerMacros.h"
0505 DEFINE_FWK_MODULE(L1TriggerJSONMonitoring);