Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-14 00:06:40

0001 /**_________________________________________________________________
0002    class:   BeamSpotOnlineProducer.h
0003    package: RecoVertex/BeamSpotProducer
0004 
0005 
0006 
0007  author: Francisco Yumiceva, Fermilab (yumiceva@fnal.gov)
0008  modified by: Simone Gennai, INFN MIB
0009 
0010 
0011 ________________________________________________________________**/
0012 
0013 #include "CondFormats/BeamSpotObjects/interface/BeamSpotObjects.h"
0014 #include "CondFormats/DataRecord/interface/BeamSpotObjectsRcd.h"
0015 #include "CondFormats/BeamSpotObjects/interface/BeamSpotOnlineObjects.h"
0016 #include "CondFormats/DataRecord/interface/BeamSpotOnlineHLTObjectsRcd.h"
0017 #include "CondFormats/DataRecord/interface/BeamSpotOnlineLegacyObjectsRcd.h"
0018 #include "DataFormats/BeamSpot/interface/BeamSpot.h"
0019 #include "DataFormats/Common/interface/Handle.h"
0020 #include "DataFormats/GeometryCommonDetAlgo/interface/GlobalError.h"
0021 #include "DataFormats/L1GlobalTrigger/interface/L1GlobalTriggerEvmReadoutRecord.h"
0022 #include "DataFormats/Scalers/interface/BeamSpotOnline.h"
0023 #include "FWCore/Framework/interface/ESHandle.h"
0024 #include "FWCore/Framework/interface/Event.h"
0025 #include "FWCore/Framework/interface/EventSetup.h"
0026 #include "FWCore/Framework/interface/stream/EDProducer.h"
0027 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0028 #include "FWCore/ParameterSet/interface/ConfigurationDescriptions.h"
0029 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0030 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
0031 #include "FWCore/Utilities/interface/ESGetToken.h"
0032 #include "FWCore/Utilities/interface/TypeDemangler.h"
0033 
0034 #include <optional>
0035 
0036 class BeamSpotOnlineProducer : public edm::stream::EDProducer<> {
0037 public:
0038   /// constructor
0039   explicit BeamSpotOnlineProducer(const edm::ParameterSet& iConf);
0040 
0041   void beginLuminosityBlock(const edm::LuminosityBlock& lumi, const edm::EventSetup& setup) override;
0042 
0043   /// produce a beam spot class
0044   void produce(edm::Event& iEvent, const edm::EventSetup& iSetup) override;
0045 
0046   ///Fill descriptor
0047   static void fillDescriptions(edm::ConfigurationDescriptions& iDesc);
0048 
0049 private:
0050   // helper methods
0051   bool shouldShout(const edm::Event& iEvent) const;
0052   std::optional<reco::BeamSpot> processRecords(const edm::LuminosityBlock& iLumi,
0053                                                const edm::EventSetup& iSetup,
0054                                                bool shoutMODE) const;
0055   reco::BeamSpot createBeamSpotFromRecord(const BeamSpotObjects& spotDB) const;
0056   template <typename RecordType, typename TokenType>
0057   const BeamSpotOnlineObjects* getBeamSpotFromRecord(const TokenType& token,
0058                                                      const edm::LuminosityBlock& lumi,
0059                                                      const edm::EventSetup& setup) const;
0060   const BeamSpotOnlineObjects* chooseBS(const BeamSpotOnlineObjects* bs1, const BeamSpotOnlineObjects* bs2) const;
0061   std::optional<reco::BeamSpot> processScalers(const edm::Event& iEvent, bool shoutMODE) const;
0062   reco::BeamSpot createBeamSpotFromScaler(const BeamSpotOnline& spotOnline) const;
0063   bool isInvalidScaler(const BeamSpotOnline& spotOnline, bool shoutMODE) const;
0064   reco::BeamSpot createBeamSpotFromDB(const edm::EventSetup& iSetup, bool shoutMODE) const;
0065 
0066   // data members
0067   const bool changeFrame_;
0068   const double theMaxZ, theSetSigmaZ;
0069   double theMaxR2;
0070   const int timeThreshold_;
0071   const double sigmaZThreshold_, sigmaXYThreshold_;
0072   const bool useBSOnlineRecords_;
0073   const edm::EDGetTokenT<BeamSpotOnlineCollection> scalerToken_;
0074   const edm::EDGetTokenT<L1GlobalTriggerEvmReadoutRecord> l1GtEvmReadoutRecordToken_;
0075   const edm::ESGetToken<BeamSpotObjects, BeamSpotObjectsRcd> beamToken_;
0076   const edm::ESGetToken<BeamSpotOnlineObjects, BeamSpotOnlineLegacyObjectsRcd> beamTokenLegacy_;
0077   const edm::ESGetToken<BeamSpotOnlineObjects, BeamSpotOnlineHLTObjectsRcd> beamTokenHLT_;
0078 
0079   std::optional<reco::BeamSpot> lumiResult_;
0080   const unsigned int theBeamShoutMode;
0081 };
0082 
0083 using namespace edm;
0084 
0085 BeamSpotOnlineProducer::BeamSpotOnlineProducer(const ParameterSet& iconf)
0086     : changeFrame_(iconf.getParameter<bool>("changeToCMSCoordinates")),
0087       theMaxZ(iconf.getParameter<double>("maxZ")),
0088       theSetSigmaZ(iconf.getParameter<double>("setSigmaZ")),
0089       timeThreshold_(iconf.getParameter<int>("timeThreshold")),
0090       sigmaZThreshold_(iconf.getParameter<double>("sigmaZThreshold")),
0091       sigmaXYThreshold_(iconf.getParameter<double>("sigmaXYThreshold") * 1E-4),
0092       useBSOnlineRecords_(iconf.getParameter<bool>("useBSOnlineRecords")),
0093       scalerToken_(useBSOnlineRecords_ ? edm::EDGetTokenT<BeamSpotOnlineCollection>()
0094                                        : consumes<BeamSpotOnlineCollection>(iconf.getParameter<InputTag>("src"))),
0095       l1GtEvmReadoutRecordToken_(consumes<L1GlobalTriggerEvmReadoutRecord>(iconf.getParameter<InputTag>("gtEvmLabel"))),
0096       beamToken_(esConsumes<BeamSpotObjects, BeamSpotObjectsRcd, edm::Transition::BeginLuminosityBlock>()),
0097       beamTokenLegacy_(
0098           esConsumes<BeamSpotOnlineObjects, BeamSpotOnlineLegacyObjectsRcd, edm::Transition::BeginLuminosityBlock>()),
0099       beamTokenHLT_(
0100           esConsumes<BeamSpotOnlineObjects, BeamSpotOnlineHLTObjectsRcd, edm::Transition::BeginLuminosityBlock>()),
0101       theBeamShoutMode(iconf.getUntrackedParameter<unsigned int>("beamMode", 11)) {
0102   theMaxR2 = iconf.getParameter<double>("maxRadius");
0103   theMaxR2 *= theMaxR2;
0104 
0105   produces<reco::BeamSpot>();
0106 }
0107 
0108 void BeamSpotOnlineProducer::fillDescriptions(edm::ConfigurationDescriptions& iDesc) {
0109   edm::ParameterSetDescription ps;
0110   ps.add<bool>("changeToCMSCoordinates", false);
0111   ps.add<double>("maxZ", 40.);
0112   ps.add<double>("setSigmaZ", -1.);
0113   ps.addUntracked<unsigned int>("beamMode", 11);
0114   ps.addOptional<InputTag>("src", InputTag("hltScalersRawToDigi"))->setComment("SCAL decommissioned after Run 2");
0115   ps.add<InputTag>("gtEvmLabel", InputTag(""));
0116   ps.add<double>("maxRadius", 2.0);
0117   ps.add<bool>("useBSOnlineRecords", false);
0118   ps.add<int>("timeThreshold", 48)->setComment("hours");
0119   ps.add<double>("sigmaZThreshold", 2.)->setComment("cm");
0120   ps.add<double>("sigmaXYThreshold", 4.)->setComment("um");
0121   iDesc.addWithDefaultLabel(ps);
0122 }
0123 
0124 void BeamSpotOnlineProducer::beginLuminosityBlock(const edm::LuminosityBlock& lumi, const edm::EventSetup& setup) {
0125   /// fetch online records only at the beginning of a lumisection
0126   if (useBSOnlineRecords_) {
0127     lumiResult_ = processRecords(lumi, setup, true);
0128     if (lumiResult_)
0129       return;
0130   }
0131   lumiResult_ = createBeamSpotFromDB(setup, true);
0132 }
0133 
0134 void BeamSpotOnlineProducer::produce(edm::Event& iEvent, const edm::EventSetup& iSetup) {
0135   // Determine if we should "shout" based on the beam mode
0136   bool shoutMODE = shouldShout(iEvent);
0137 
0138   std::unique_ptr<reco::BeamSpot> toput;
0139   if (not useBSOnlineRecords_) {
0140     // Process online beam spot scalers
0141     auto bs = processScalers(iEvent, shoutMODE);
0142     if (bs) {
0143       toput = std::make_unique<reco::BeamSpot>(std::move(*bs));
0144     }
0145   }
0146   if (not toput) {
0147     assert(lumiResult_);
0148     toput = std::make_unique<reco::BeamSpot>(*lumiResult_);
0149   }
0150   iEvent.put(std::move(toput));
0151 }
0152 
0153 bool BeamSpotOnlineProducer::shouldShout(const edm::Event& iEvent) const {
0154   edm::Handle<L1GlobalTriggerEvmReadoutRecord> gtEvmReadoutRecord;
0155   if (iEvent.getByToken(l1GtEvmReadoutRecordToken_, gtEvmReadoutRecord)) {
0156     return gtEvmReadoutRecord->gtfeWord().beamMode() == theBeamShoutMode;
0157   }
0158   return true;  // Default to "shout" if the record is missing
0159 }
0160 
0161 std::optional<reco::BeamSpot> BeamSpotOnlineProducer::processRecords(const edm::LuminosityBlock& iLumi,
0162                                                                      const edm::EventSetup& iSetup,
0163                                                                      bool shoutMODE) const {
0164   auto const* spotDBLegacy = getBeamSpotFromRecord<BeamSpotOnlineLegacyObjectsRcd>(beamTokenLegacy_, iLumi, iSetup);
0165   auto const* spotDBHLT = getBeamSpotFromRecord<BeamSpotOnlineHLTObjectsRcd>(beamTokenHLT_, iLumi, iSetup);
0166   auto const* spotDB = chooseBS(spotDBLegacy, spotDBHLT);
0167 
0168   if (not spotDB) {
0169     if (shoutMODE) {
0170       edm::LogWarning("BeamSpotOnlineProducer") << "None of the online records holds a valid beam spot. The Online "
0171                                                    "Beam Spot producer falls back to the PCL value.";
0172     }
0173     return {};  // Trigger fallback to DB
0174   }
0175 
0176   // Create BeamSpot from transient record
0177   return createBeamSpotFromRecord(*spotDB);
0178 }
0179 
0180 template <typename RecordType, typename TokenType>
0181 const BeamSpotOnlineObjects* BeamSpotOnlineProducer::getBeamSpotFromRecord(const TokenType& token,
0182                                                                            const LuminosityBlock& lumi,
0183                                                                            const EventSetup& setup) const {
0184   auto const bsRecord = setup.tryToGet<RecordType>();
0185   if (!bsRecord) {
0186     const auto& recordTypeName = edm::typeDemangle(typeid(RecordType).name());
0187     edm::LogWarning("BeamSpotOnlineProducer") << "No " << recordTypeName << " found in the EventSetup";
0188     return nullptr;
0189   }
0190   const auto& bsHandle = setup.getHandle(token);
0191   if (bsHandle.isValid()) {
0192     const auto& bs = *bsHandle;
0193     if (bs.sigmaZ() < sigmaZThreshold_ || bs.beamWidthX() < sigmaXYThreshold_ || bs.beamWidthY() < sigmaXYThreshold_ ||
0194         bs.beamType() != reco::BeamSpot::Tracker) {
0195       const auto& recordTypeName = edm::typeDemangle(typeid(RecordType).name());
0196       edm::LogWarning("BeamSpotOnlineProducer")
0197           << "The beam spot record does not pass the fit sanity checks (record: " << recordTypeName << ")" << std::endl
0198           << "sigmaZ: " << bs.sigmaZ() << std::endl
0199           << "sigmaX: " << bs.beamWidthX() << std::endl
0200           << "sigmaY: " << bs.beamWidthY() << std::endl
0201           << "type: " << bs.beamType();
0202       return nullptr;
0203     }
0204     auto lumitime = std::chrono::seconds(lumi.beginTime().unixTime());
0205     auto bstime = std::chrono::microseconds(bs.creationTime());
0206     auto threshold = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::hours(timeThreshold_)).count();
0207     if ((lumitime - bstime).count() > threshold) {
0208       const auto& recordTypeName = edm::typeDemangle(typeid(RecordType).name());
0209       edm::LogWarning("BeamSpotOnlineProducer")
0210           << "The beam spot record is too old. (record: " << recordTypeName << ")" << std::endl
0211           << " record creation time: " << std::chrono::duration_cast<std::chrono::seconds>(bstime).count()
0212           << " lumi block time: " << std::chrono::duration_cast<std::chrono::seconds>(lumitime).count();
0213       return nullptr;
0214     }
0215     return &bs;
0216   } else {
0217     const auto& recordTypeName = edm::typeDemangle(typeid(RecordType).name());
0218     edm::LogWarning("BeamSpotOnlineProducer") << "Invalid online beam spot handle for the record: " << recordTypeName;
0219     return nullptr;
0220   }
0221 }
0222 
0223 const BeamSpotOnlineObjects* BeamSpotOnlineProducer::chooseBS(const BeamSpotOnlineObjects* bs1,
0224                                                               const BeamSpotOnlineObjects* bs2) const {
0225   if (bs1 and bs2 and bs1->beamType() == reco::BeamSpot::Tracker && bs2->beamType() == reco::BeamSpot::Tracker) {
0226     return bs1->sigmaZ() > bs2->sigmaZ() ? bs1 : bs2;
0227   } else if (bs1 and bs1->beamType() == reco::BeamSpot::Tracker) {
0228     return bs1;
0229   } else if (bs2 and bs2->beamType() == reco::BeamSpot::Tracker) {
0230     return bs2;
0231   } else {
0232     return nullptr;
0233   }
0234 }
0235 
0236 reco::BeamSpot BeamSpotOnlineProducer::createBeamSpotFromRecord(const BeamSpotObjects& spotDB) const {
0237   double f = changeFrame_ ? -1.0 : 1.0;
0238   reco::BeamSpot::Point apoint(f * spotDB.x(), f * spotDB.y(), f * spotDB.z());
0239 
0240   reco::BeamSpot::CovarianceMatrix matrix;
0241   for (int i = 0; i < reco::BeamSpot::dimension; ++i) {
0242     for (int j = 0; j < reco::BeamSpot::dimension; ++j) {
0243       matrix(i, j) = spotDB.covariance(i, j);
0244     }
0245   }
0246 
0247   double sigmaZ = (theSetSigmaZ > 0) ? theSetSigmaZ : spotDB.sigmaZ();
0248   reco::BeamSpot result(apoint, sigmaZ, spotDB.dxdz(), spotDB.dydz(), spotDB.beamWidthX(), matrix);
0249   result.setBeamWidthY(spotDB.beamWidthY());
0250   result.setEmittanceX(spotDB.emittanceX());
0251   result.setEmittanceY(spotDB.emittanceY());
0252   result.setbetaStar(spotDB.betaStar());
0253   result.setType(reco::BeamSpot::Tracker);
0254   return result;
0255 }
0256 
0257 std::optional<reco::BeamSpot> BeamSpotOnlineProducer::processScalers(const edm::Event& iEvent, bool shoutMODE) const {
0258   edm::Handle<BeamSpotOnlineCollection> handleScaler;
0259   iEvent.getByToken(scalerToken_, handleScaler);
0260 
0261   if (handleScaler->empty()) {
0262     if (shoutMODE && iEvent.isRealData()) {
0263       edm::LogWarning("BeamSpotOnlineProducer") << " Scalers handle is empty. The Online "
0264                                                    "Beam Spot producer falls back to the PCL value.";
0265     }
0266     return {};
0267   }
0268 
0269   // Extract data from scaler
0270   BeamSpotOnline spotOnline = *(handleScaler->begin());
0271   // Validate the scaler data
0272   if (isInvalidScaler(spotOnline, shoutMODE)) {
0273     return {};  // Trigger fallback to DB
0274   }
0275   return createBeamSpotFromScaler(spotOnline);
0276 }
0277 
0278 reco::BeamSpot BeamSpotOnlineProducer::createBeamSpotFromScaler(const BeamSpotOnline& spotOnline) const {
0279   double f = changeFrame_ ? -1.0 : 1.0;
0280   reco::BeamSpot::Point apoint(f * spotOnline.x(), spotOnline.y(), f * spotOnline.z());
0281 
0282   reco::BeamSpot::CovarianceMatrix matrix;
0283   matrix(0, 0) = spotOnline.err_x() * spotOnline.err_x();
0284   matrix(1, 1) = spotOnline.err_y() * spotOnline.err_y();
0285   matrix(2, 2) = spotOnline.err_z() * spotOnline.err_z();
0286   matrix(3, 3) = spotOnline.err_sigma_z() * spotOnline.err_sigma_z();
0287 
0288   double sigmaZ = (theSetSigmaZ > 0) ? theSetSigmaZ : spotOnline.sigma_z();
0289   reco::BeamSpot result(apoint, sigmaZ, spotOnline.dxdz(), f * spotOnline.dydz(), spotOnline.width_x(), matrix);
0290   result.setBeamWidthY(spotOnline.width_y());
0291   result.setEmittanceX(0.0);
0292   result.setEmittanceY(0.0);
0293   result.setbetaStar(0.0);
0294   result.setType(reco::BeamSpot::LHC);
0295   return result;
0296 }
0297 
0298 bool BeamSpotOnlineProducer::isInvalidScaler(const BeamSpotOnline& spotOnline, bool shoutMODE) const {
0299   if (spotOnline.x() == 0 && spotOnline.y() == 0 && spotOnline.z() == 0 && spotOnline.width_x() == 0 &&
0300       spotOnline.width_y() == 0) {
0301     if (shoutMODE) {
0302       edm::LogWarning("BeamSpotOnlineProducer")
0303           << "Online Beam Spot producer falls back to DB due to zero scaler values.";
0304     }
0305     return true;
0306   }
0307 
0308   double r2 = spotOnline.x() * spotOnline.x() + spotOnline.y() * spotOnline.y();
0309   if (std::abs(spotOnline.z()) >= theMaxZ || r2 >= theMaxR2) {
0310     if (shoutMODE) {
0311       edm::LogError("BeamSpotOnlineProducer")
0312           << "Online Beam Spot producer falls back to DB due to out-of-range scaler values: " << spotOnline.x() << ", "
0313           << spotOnline.y() << ", " << spotOnline.z();
0314     }
0315     return true;
0316   }
0317   return false;
0318 }
0319 
0320 reco::BeamSpot BeamSpotOnlineProducer::createBeamSpotFromDB(const edm::EventSetup& iSetup, bool shoutMODE) const {
0321   edm::ESHandle<BeamSpotObjects> beamhandle = iSetup.getHandle(beamToken_);
0322   const BeamSpotObjects* spotDB = beamhandle.product();
0323 
0324   reco::BeamSpot::Point apoint(spotDB->x(), spotDB->y(), spotDB->z());
0325 
0326   reco::BeamSpot::CovarianceMatrix matrix;
0327   for (int i = 0; i < reco::BeamSpot::dimension; ++i) {
0328     for (int j = 0; j < reco::BeamSpot::dimension; ++j) {
0329       matrix(i, j) = spotDB->covariance(i, j);
0330     }
0331   }
0332 
0333   reco::BeamSpot result(apoint, spotDB->sigmaZ(), spotDB->dxdz(), spotDB->dydz(), spotDB->beamWidthX(), matrix);
0334   result.setBeamWidthY(spotDB->beamWidthY());
0335   result.setEmittanceX(spotDB->emittanceX());
0336   result.setEmittanceY(spotDB->emittanceY());
0337   result.setbetaStar(spotDB->betaStar());
0338   result.setType(reco::BeamSpot::Tracker);
0339 
0340   GlobalError bse(result.rotatedCovariance3D());
0341   if ((bse.cxx() <= 0.0) || (bse.cyy() <= 0.0) || (bse.czz() <= 0.0)) {
0342     edm::LogError("UnusableBeamSpot") << "Beamspot from DB fallback has invalid errors: " << result.covariance();
0343   }
0344   return result;
0345 }
0346 
0347 #include "FWCore/Framework/interface/MakerMacros.h"
0348 DEFINE_FWK_MODULE(BeamSpotOnlineProducer);