Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2023-03-17 11:09:37

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